From 8e4bb176d308364a063633f2bcbae9cb858510b1 Mon Sep 17 00:00:00 2001 From: Kelly Rodger Date: Sat, 20 Jul 2019 01:02:01 -0400 Subject: [PATCH] First drop of samples from 11.5.0 --- BARVendor/ACS_scripts/acs_ibmstor.sh | 1559 +++ BARVendor/ACS_scripts/dm-1310acs_lvm.sh | 371 + BARVendor/ACS_scripts/dm-1311acs_gpfs.sh | 1178 ++ BARVendor/README | 128 + BARVendor/custom.h | 63 + BARVendor/libacssc.sh | 391 + BARVendor/policy.h | 358 + BARVendor/vendor.C | 1541 +++ BARVendor/xbsa.h | 678 ++ admin_scripts/README | 175 + admin_scripts/admincmd_tbload.db2 | 93 + admin_scripts/alterpartition.db2 | 142 + admin_scripts/audit.db2 | 778 ++ admin_scripts/autocfg.db2 | 100 + admin_scripts/autodb.db2 | 177 + admin_scripts/autonomous_transaction.db2 | 630 + admin_scripts/autorestore.db2 | 126 + admin_scripts/autostore.db2 | 145 + admin_scripts/cgtt.db2 | 514 + admin_scripts/checkv9limits.db2 | 157 + admin_scripts/contacts.db2 | 92 + admin_scripts/databaseroles.db2 | 726 ++ admin_scripts/fasterrollout.db2 | 152 + admin_scripts/gethealthconfig.db2 | 76 + admin_scripts/getlogs.db2 | 83 + admin_scripts/globvarsupport.db2 | 343 + admin_scripts/healthmon.db2 | 268 + admin_scripts/ingest_files.sh | 532 + admin_scripts/largerid.db2 | 256 + admin_scripts/lbac.db2 | 734 ++ admin_scripts/monitor.db2 | 100 + admin_scripts/onlineload.db2 | 208 + admin_scripts/partitionindex.db2 | 110 + admin_scripts/public_alias.db2 | 501 + admin_scripts/redistribute_cmd.db2 | 296 + admin_scripts/rollindata.db2 | 160 + admin_scripts/rolloutdata.db2 | 178 + admin_scripts/sec_rcac.db2 | 783 ++ admin_scripts/security.db2 | 72 + admin_scripts/setintegrity.db2 | 300 + admin_scripts/ssv_backup_db.db2 | 135 + admin_scripts/ssv_backup_tbsp.db2 | 127 + admin_scripts/ssv_db_cfg.db2 | 164 + admin_scripts/tablepartition.db2 | 171 + admin_scripts/tbeventmon.db2 | 120 + admin_scripts/tbonlineinx.db2 | 138 + admin_scripts/tbrowcompress.db2 | 370 + admin_scripts/tbrunstats.db2 | 87 + admin_scripts/tbsreduce.db2 | 393 + admin_scripts/wlmtiersdefault.db2 | 240 + admin_scripts/wlmtiersdrop.db2 | 119 + admin_scripts/wlmtierstimerons.db2 | 293 + autoloader/loadFtpFtc.pl | 329 + automaintcfg/DB2AutoBackupPolicySample.xml | 120 + automaintcfg/DB2AutoReorgPolicySample.xml | 85 + automaintcfg/DB2AutoRunstatsPolicySample.xml | 47 + .../DB2MaintenanceWindowPolicySample.xml | 95 + c/README | 420 + c/autostore.c | 588 + c/bldapp | 111 + c/bldmc | 107 + c/bldmt | 95 + c/bldrtn | 111 + c/cli_info.c | 419 + c/clisnap.c | 123 + c/clisnapnew.c | 121 + c/db2uext2.cdisk | 1624 +++ c/db2uext2.ctape | 2052 ++++ c/db2uext2.ctsm | 2389 ++++ c/dbauth.sqc | 262 + c/dbcfg.sqc | 490 + c/dbconn.sqc | 199 + c/dbcreate.c | 169 + c/dbhistfile.sqc | 550 + c/dbinfo.c | 281 + c/dbinline.sqc | 885 ++ c/dbinspec.sqc | 339 + c/dblogconn.sqc | 637 + c/dblognoconn.sqc | 349 + c/dblognoconnlogmerge.c | 1052 ++ c/dbmcon.sqc | 369 + c/dbmcon1.h | 48 + c/dbmcon1.sqc | 78 + c/dbmcon2.h | 48 + c/dbmcon2.sqc | 78 + c/dbpkg.sqc | 244 + c/dbrecov.sqc | 58 + c/dbredirect.sqc | 570 + c/dbrestore.sqc | 244 + c/dbrollfwd.sqc | 289 + c/dbsample.sqc | 2484 ++++ c/dbsnap.c | 134 + c/dbsnapnew.c | 164 + c/dbstat.c | 558 + c/dbthrds.sqc | 613 + c/dbupgrade.c | 105 + c/dbuse.sqc | 486 + c/dtformat.sqc | 501 + c/dtlob.sqc | 366 + c/dtudt.sqc | 222 + c/embprep | 63 + c/evm.sqc | 930 ++ c/fnuse.sqc | 250 + c/getlogs.sqc | 522 + c/getmessage.sqc | 102 + c/globvarsupport.sqc | 1064 ++ c/implicitcasting.sqc | 690 ++ c/inattach.c | 155 + c/inauth.sqc | 241 + c/ininfo.c | 759 ++ c/insnap.c | 119 + c/insnapnew.c | 115 + c/instart.c | 148 + c/largerid.sqc | 857 ++ c/makefile | 408 + c/setintegrity.sqc | 1086 ++ c/spcat | 31 + c/spclient.sqc | 670 ++ c/spcreate.db2 | 212 + c/spcreate_gv.db2 | 64 + c/spdrop.db2 | 65 + c/spserver.exp | 12 + c/spserver.sqc | 1935 +++ c/ssv_backup_db.c | 310 + c/ssv_backup_tbsp.sqc | 548 + c/ssv_db_cfg.c | 336 + c/tbast.sqc | 353 + c/tbcompress.sqc | 178 + c/tbconstr.sqc | 1054 ++ c/tbcreate.sqc | 150 + c/tbident.sqc | 328 + c/tbinfo.sqc | 189 + c/tbintrig.sqc | 839 ++ c/tbload.sqc | 488 + c/tbloadcursor.sqc | 472 + c/tbmerge.sqc | 427 + c/tbmod.sqc | 934 ++ c/tbmove.sqc | 581 + c/tbonlineinx.sqc | 536 + c/tbpriv.sqc | 192 + c/tbread.sqc | 2101 ++++ c/tbreorg.sqc | 200 + c/tbrowcompress.sqc | 1078 ++ c/tbrunstats.sqc | 193 + c/tbsavept.sqc | 845 ++ c/tbsel.sqc | 397 + c/tbselcreate.db2 | 64 + c/tbseldrop.db2 | 44 + c/tbselinit | 29 + c/tbtemp.sqc | 613 + c/tbtrig.sqc | 865 ++ c/tbumqt.sqc | 1037 ++ c/tbunion.sqc | 704 ++ c/tscreate.sqc | 341 + c/udfcli.sqc | 877 ++ c/udfemcli.sqc | 603 + c/udfemsrv.exp | 5 + c/udfemsrv.sqc | 465 + c/udfsrv.c | 649 + c/udfsrv.exp | 6 + c/utilapi.c | 359 + c/utilapi.h | 116 + c/utilemb.h | 94 + c/utilemb.sqc | 130 + c/utilrecov.c | 1130 ++ c/utilsnap.c | 1590 +++ cli/README | 344 + cli/admincmd_autoconfigure.c | 184 + cli/admincmd_contacts.c | 447 + cli/admincmd_describe.c | 300 + cli/admincmd_export.c | 265 + cli/admincmd_import.c | 367 + cli/admincmd_onlinebackup.c | 210 + cli/admincmd_quiesce.c | 241 + cli/admincmd_updateconfig.c | 245 + cli/bldapp | 94 + cli/bldmc | 97 + cli/bldrtn | 94 + cli/cli_info.c | 127 + cli/clihandl.c | 160 + cli/clisqlca.c | 227 + cli/dbcongui.c | 264 + cli/dbconn.c | 323 + cli/dbinfo.c | 312 + cli/dbmcon.c | 690 ++ cli/dbmconx.c | 481 + cli/dbmconx1.h | 40 + cli/dbmconx1.sqc | 85 + cli/dbmconx2.h | 40 + cli/dbmconx2.sqc | 85 + cli/dbnative.c | 120 + cli/dbuse.c | 1340 +++ cli/dbusemx.sqc | 145 + cli/dbxamon.c | 2944 +++++ cli/dbxamon.ini | 7 + cli/dtinfo.c | 237 + cli/dtlob.c | 980 ++ cli/dtudt.c | 296 + cli/embprep | 63 + cli/getdbcfgparams.c | 240 + cli/getdbmcfgparams.c | 223 + cli/getmessage.c | 161 + cli/ilinfo.c | 203 + cli/ininfo.c | 184 + cli/makefile | 295 + cli/spcall.c | 604 + cli/spcat | 30 + cli/spclient.c | 1543 +++ cli/spclires.c | 507 + cli/spcreate.db2 | 216 + cli/spdrop.db2 | 57 + cli/spserver.c | 4045 +++++++ cli/spserver.exp | 12 + cli/ssv_db_cfg.c | 321 + cli/tbast.c | 658 + cli/tbcompress.c | 297 + cli/tbconstr.c | 2658 ++++ cli/tbcreate.c | 197 + cli/tbinfo.c | 884 ++ cli/tbload.c | 388 + cli/tbmod.c | 812 ++ cli/tbonlineinx.c | 436 + cli/tbread.c | 1791 +++ cli/tbrunstats.c | 258 + cli/tbtemp.c | 877 ++ cli/tbumqt.c | 600 + cli/trustedcontext.c | 731 ++ cli/udfcli.c | 946 ++ cli/udfsrv.c | 658 + cli/udfsrv.exp | 6 + cli/utilcli.c | 638 + cli/utilcli.h | 135 + clp/README | 134 + clp/const.db2 | 59 + clp/cte.db2 | 60 + clp/datecompat.db2 | 282 + clp/flt.db2 | 73 + clp/implicitcasting.db2 | 310 + clp/join.db2 | 79 + clp/scalarfunction.db2 | 620 + clp/stock.db2 | 121 + clp/tablestatesize.db2 | 192 + clp/tbast.db2 | 119 + clp/tbcompress.db2 | 83 + clp/tbconstr.db2 | 636 + clp/tbread.db2 | 239 + clp/tbtemp.db2 | 190 + clp/tbumqt.db2 | 248 + clp/temporal_att.db2 | 417 + clp/temporal_btt.db2 | 574 + clp/temporal_revert.db2 | 329 + clp/temporal_stt.db2 | 560 + clp/testdata.db2 | 72 + clp/tsinfo.db2 | 117 + cobol_mf/README | 381 + cobol_mf/advsql.sqb | 150 + cobol_mf/bldapp | 77 + cobol_mf/bldrtn | 73 + cobol_mf/checkerr.cbl | 120 + cobol_mf/client.cbl | 252 + cobol_mf/cursor.sqb | 128 + cobol_mf/d_dbconf.cbl | 137 + cobol_mf/d_dbmcon.cbl | 116 + cobol_mf/db_udcs.cbl | 158 + cobol_mf/dbauth.sqb | 158 + cobol_mf/dbcat.cbl | 265 + cobol_mf/dbcmt.cbl | 187 + cobol_mf/dbconf.cbl | 278 + cobol_mf/dbinst.cbl | 142 + cobol_mf/dbmconf.cbl | 196 + cobol_mf/dbsnap.cbl | 141 + cobol_mf/dbstart.cbl | 77 + cobol_mf/dbstat.sqb | 276 + cobol_mf/dbstop.cbl | 121 + cobol_mf/dbupgrade.cbl | 133 + cobol_mf/dcscat.cbl | 184 + cobol_mf/delet.sqb | 116 + cobol_mf/dynamic.sqb | 141 + cobol_mf/ebcdicdb.cbl | 158 + cobol_mf/embprep | 63 + cobol_mf/expsamp.sqb | 324 + cobol_mf/impexp.sqb | 258 + cobol_mf/inpcli.sqb | 152 + cobol_mf/inpsrv.sqb | 197 + cobol_mf/joinsql.sqb | 220 + cobol_mf/loadqry.sqb | 183 + cobol_mf/lobeval.sqb | 177 + cobol_mf/lobfile.sqb | 119 + cobol_mf/lobloc.sqb | 194 + cobol_mf/makefile | 382 + cobol_mf/monreset.cbl | 86 + cobol_mf/monsz.cbl | 154 + cobol_mf/nodecat.cbl | 198 + cobol_mf/openftch.sqb | 162 + cobol_mf/outcli.sqb | 172 + cobol_mf/outsrv.sqb | 166 + cobol_mf/prepbind.sqb | 226 + cobol_mf/qload.sqb | 128 + cobol_mf/rebind.sqb | 133 + cobol_mf/restart.cbl | 108 + cobol_mf/setact.cbl | 80 + cobol_mf/spcat | 31 + cobol_mf/spcreate.db2 | 59 + cobol_mf/spdrop.db2 | 42 + cobol_mf/static.sqb | 107 + cobol_mf/sws.cbl | 236 + cobol_mf/tabscont.sqb | 261 + cobol_mf/tabspace.sqb | 414 + cobol_mf/tabsql.sqb | 227 + cobol_mf/tload.sqb | 317 + cobol_mf/trigsql.sqb | 240 + cobol_mf/tspace.sqb | 415 + cobol_mf/updat.sqb | 145 + cobol_mf/varinp.sqb | 159 + cpp/README | 367 + cpp/bldapp | 105 + cpp/bldmc | 98 + cpp/bldmt | 91 + cpp/bldrtn | 96 + cpp/cli_info.C | 443 + cpp/clisnap.C | 136 + cpp/clisnapnew.C | 136 + cpp/dbauth.sqC | 260 + cpp/dbcfg.sqC | 498 + cpp/dbconn.sqC | 229 + cpp/dbcreate.C | 177 + cpp/dbhistfile.sqC | 530 + cpp/dbinfo.C | 290 + cpp/dbinline.sqC | 906 ++ cpp/dbinspec.sqC | 352 + cpp/dblogconn.sqC | 634 + cpp/dblognoconn.sqC | 352 + cpp/dbmcon.sqC | 409 + cpp/dbmcon1.h | 52 + cpp/dbmcon1.sqC | 83 + cpp/dbmcon2.h | 52 + cpp/dbmcon2.sqC | 83 + cpp/dbpkg.sqC | 256 + cpp/dbrecov.sqC | 58 + cpp/dbrestore.sqC | 253 + cpp/dbrollfwd.sqC | 311 + cpp/dbsample.sqC | 2489 ++++ cpp/dbsnap.C | 148 + cpp/dbsnapnew.C | 180 + cpp/dbthrds.sqC | 653 + cpp/dbupgrade.C | 113 + cpp/dbuse.sqC | 497 + cpp/dtformat.sqC | 519 + cpp/dtlob.sqC | 375 + cpp/dtstruct.sqC | 1223 ++ cpp/dtudt.sqC | 234 + cpp/embprep | 63 + cpp/evm.sqC | 968 ++ cpp/fnuse.sqC | 270 + cpp/inattach.C | 152 + cpp/inauth.sqC | 206 + cpp/ininfo.C | 803 ++ cpp/insnap.C | 133 + cpp/insnapnew.C | 128 + cpp/instart.C | 155 + cpp/makefile | 365 + cpp/routinecompile | 627 + cpp/spcat | 30 + cpp/spclient.sqC | 705 ++ cpp/spcreate.db2 | 215 + cpp/spdrop.db2 | 68 + cpp/spserver.exp | 12 + cpp/spserver.sqC | 2038 ++++ cpp/tbast.sqC | 380 + cpp/tbcompress.sqC | 209 + cpp/tbconstr.sqC | 1077 ++ cpp/tbcreate.sqC | 154 + cpp/tbident.sqC | 350 + cpp/tbinfo.sqC | 202 + cpp/tbintrig.sqC | 856 ++ cpp/tbloadcursor.sqC | 537 + cpp/tbmerge.sqC | 435 + cpp/tbmod.sqC | 934 ++ cpp/tbmove.sqC | 566 + cpp/tbonlineinx.sqC | 542 + cpp/tbpriv.sqC | 199 + cpp/tbread.sqC | 2197 ++++ cpp/tbreorg.sqC | 210 + cpp/tbrunstats.sqC | 212 + cpp/tbsavept.sqC | 860 ++ cpp/tbsel.sqC | 407 + cpp/tbselcreate.db2 | 64 + cpp/tbseldrop.db2 | 44 + cpp/tbselinit | 29 + cpp/tbtemp.sqC | 651 + cpp/tbtrig.sqC | 902 ++ cpp/tbumqt.sqC | 375 + cpp/tbunion.sqC | 737 ++ cpp/tscreate.sqC | 364 + cpp/udfcli.sqC | 898 ++ cpp/udfemcli.sqC | 632 + cpp/udfemsrv.exp | 5 + cpp/udfemsrv.sqC | 463 + cpp/udfsampl.cpp | 91 + cpp/udfsrv.C | 641 + cpp/udfsrv.exp | 6 + cpp/udtfsampl.cpp | 150 + cpp/utilapi.C | 309 + cpp/utilapi.h | 142 + cpp/utilemb.h | 95 + cpp/utilemb.sqC | 136 + cpp/utilrecov.C | 1099 ++ cpp/utilsnap.C | 1597 +++ db2ci/README | 171 + db2ci/bldapp | 88 + db2ci/cihandl.c | 165 + db2ci/dbuse.c | 490 + db2ci/ilinfo.c | 154 + db2ci/makefile | 132 + db2ci/ocitest | Bin 0 -> 1161816 bytes db2ci/tbcompress.c | 354 + db2ci/tbcreate.c | 213 + db2ci/tbmod.c | 624 + db2ci/tbread.c | 598 + db2ci/utilci.c | 487 + db2ci/utilci.h | 86 + db2sampl/addr.xsd | 15 + db2sampl/c1.xml | 10 + db2sampl/c2.xml | 10 + db2sampl/c3.xml | 10 + db2sampl/c4.xml | 13 + db2sampl/c5.xml | 15 + db2sampl/c6.xml | 15 + db2sampl/catalog.xsd | 49 + db2sampl/customer.xsd | 47 + db2sampl/db200130.asc | 56 + db2sampl/db200130.bmp | Bin 0 -> 43690 bytes db2sampl/db200130.gif | Bin 0 -> 29540 bytes db2sampl/db200130.html | 97 + db2sampl/db200130.scr | 86 + db2sampl/db200130.xwd | Bin 0 -> 45800 bytes db2sampl/db200140.asc | 55 + db2sampl/db200140.bmp | Bin 0 -> 71798 bytes db2sampl/db200140.gif | Bin 0 -> 29143 bytes db2sampl/db200140.html | 97 + db2sampl/db200140.scr | 87 + db2sampl/db200140.xwd | Bin 0 -> 73908 bytes db2sampl/db200150.asc | 55 + db2sampl/db200150.bmp | Bin 0 -> 73438 bytes db2sampl/db200150.gif | Bin 0 -> 39795 bytes db2sampl/db200150.html | 97 + db2sampl/db200150.scr | 87 + db2sampl/db200150.xwd | Bin 0 -> 75547 bytes db2sampl/db200190.asc | 55 + db2sampl/db200190.bmp | Bin 0 -> 63542 bytes db2sampl/db200190.gif | Bin 0 -> 36088 bytes db2sampl/db200190.html | 97 + db2sampl/db200190.scr | 87 + db2sampl/db200190.xwd | Bin 0 -> 65650 bytes db2sampl/history.xsd | 14 + db2sampl/mdcdata.del | 10000 ++++++++++++++++ db2sampl/p1.xml | 8 + db2sampl/p2.xml | 8 + db2sampl/p3.xml | 8 + db2sampl/p4.xml | 7 + db2sampl/po1.xml | 15 + db2sampl/po2.xml | 20 + db2sampl/po3.xml | 20 + db2sampl/po4.xml | 8 + db2sampl/po5.xml | 14 + db2sampl/po6.xml | 21 + db2sampl/porder.xsd | 22 + db2sampl/product.xsd | 31 + db2sampl/supplier.xsd | 23 + extenders/spatial/README_spatial_samples.txt | 107 + .../spatial/bank/seBankDemoConversion.db2 | 47 + extenders/spatial/bank/seBankDemoDDL.db2 | 95 + extenders/spatial/bank/seBankDemoREADME.txt | 263 + extenders/spatial/bank/seBankDemoRefresh.db2 | 60 + extenders/spatial/bank/seBankDemoRunBankDemo | 1698 +++ .../spatial/bank/seBankDemoSpatialSQL.db2 | 1437 +++ .../spatial/bank/seBankDemoTableData.db2 | 1096 ++ extenders/spatial/bank/seBankDemoViewDDL.db2 | 210 + extenders/spatial/bldDemo | 157 + extenders/spatial/customers.data | 337 + extenders/spatial/data/cityLimits.dbf | Bin 0 -> 4672 bytes extenders/spatial/data/cityLimits.prj | 1 + extenders/spatial/data/cityLimits.shp | Bin 0 -> 92404 bytes extenders/spatial/data/cityLimits.shx | Bin 0 -> 556 bytes extenders/spatial/data/floodzones.dbf | Bin 0 -> 1162 bytes extenders/spatial/data/floodzones.prj | 1 + extenders/spatial/data/floodzones.shp | Bin 0 -> 5140 bytes extenders/spatial/data/floodzones.shx | Bin 0 -> 404 bytes extenders/spatial/data/offices.dbf | Bin 0 -> 1339 bytes extenders/spatial/data/offices.prj | 1 + extenders/spatial/data/offices.shp | Bin 0 -> 968 bytes extenders/spatial/data/offices.shx | Bin 0 -> 348 bytes extenders/spatial/data/regions.dbf | Bin 0 -> 337 bytes extenders/spatial/data/regions.prj | 1 + extenders/spatial/data/regions.shp | Bin 0 -> 12364 bytes extenders/spatial/data/regions.shx | Bin 0 -> 124 bytes extenders/spatial/data/salezones.dbf | Bin 0 -> 722 bytes extenders/spatial/data/salezones.prj | 1 + extenders/spatial/data/salezones.shp | Bin 0 -> 1672 bytes extenders/spatial/data/salezones.shx | Bin 0 -> 180 bytes extenders/spatial/data/sjCensusBlocks.dbf | Bin 0 -> 28046 bytes extenders/spatial/data/sjCensusBlocks.prj | 1 + extenders/spatial/data/sjCensusBlocks.shp | Bin 0 -> 81580 bytes extenders/spatial/data/sjCensusBlocks.shx | Bin 0 -> 2012 bytes extenders/spatial/data/sjMainStreets.dbf | Bin 0 -> 51434 bytes extenders/spatial/data/sjMainStreets.prj | 1 + extenders/spatial/data/sjMainStreets.shp | Bin 0 -> 71188 bytes extenders/spatial/data/sjMainStreets.shx | Bin 0 -> 4004 bytes extenders/spatial/data/sjZipCodes.dbf | Bin 0 -> 13250 bytes extenders/spatial/data/sjZipCodes.prj | 1 + extenders/spatial/data/sjZipCodes.shp | Bin 0 -> 76188 bytes extenders/spatial/data/sjZipCodes.shx | Bin 0 -> 484 bytes extenders/spatial/data/st_linestring.dbf | Bin 0 -> 111 bytes extenders/spatial/data/st_linestring.prj | 1 + extenders/spatial/data/st_linestring.shp | Bin 0 -> 940 bytes extenders/spatial/data/st_linestring.shx | Bin 0 -> 140 bytes extenders/spatial/data/st_multilinestring.dbf | Bin 0 -> 65 bytes extenders/spatial/data/st_multilinestring.prj | 1 + extenders/spatial/data/st_multilinestring.shp | Bin 0 -> 100 bytes extenders/spatial/data/st_multilinestring.shx | Bin 0 -> 100 bytes extenders/spatial/data/st_multipoint.dbf | Bin 0 -> 273 bytes extenders/spatial/data/st_multipoint.prj | 1 + extenders/spatial/data/st_multipoint.shp | Bin 0 -> 744 bytes extenders/spatial/data/st_multipoint.shx | Bin 0 -> 284 bytes extenders/spatial/data/st_multipolygon.dbf | Bin 0 -> 192 bytes extenders/spatial/data/st_multipolygon.prj | 1 + extenders/spatial/data/st_multipolygon.shp | Bin 0 -> 7640 bytes extenders/spatial/data/st_multipolygon.shx | Bin 0 -> 212 bytes extenders/spatial/data/st_point.dbf | Bin 0 -> 390 bytes extenders/spatial/data/st_point.prj | 1 + extenders/spatial/data/st_point.shp | Bin 0 -> 1108 bytes extenders/spatial/data/st_point.shx | Bin 0 -> 388 bytes extenders/spatial/data/st_polygon.dbf | Bin 0 -> 120 bytes extenders/spatial/data/st_polygon.prj | 1 + extenders/spatial/data/st_polygon.shp | Bin 0 -> 6680 bytes extenders/spatial/data/st_polygon.shx | Bin 0 -> 148 bytes extenders/spatial/makefile | 127 + extenders/spatial/runGseDemo | Bin 0 -> 124504 bytes extenders/spatial/runGseDemo.c | 3897 ++++++ extenders/spatial/samputil.c | 382 + extenders/spatial/samputil.h | 67 + federated/drdalbacfun.clp | 20 + federated/net8olsfun.clp | 11 + federated/selective_view/README | 1 + federated/selective_view/selective_view.txt | 1 + .../selective_view/selective_view_prep.db2 | 1 + .../selective_view/selective_view_procs.db2 | 1 + federated/umplugin/file/README | 59 + federated/umplugin/file/fsumlookup | Bin 0 -> 36120 bytes federated/umplugin/file/fsumplugin_file.c | 597 + federated/umplugin/file/fsumplugin_file.h | 35 + federated/umplugin/file/fsumplugin_file.txt | 3 + federated/umplugin/file/fsumsetup_file | Bin 0 -> 30688 bytes federated/umplugin/file/fsumsetup_file.c | 83 + federated/umplugin/ldap/README.txt | 151 + .../umplugin/ldap/UserMappingCryptoLDAP.java | 99 + .../umplugin/ldap/UserMappingLookupLDAP.java | 180 + .../ldap/UserMappingRepositoryLDAP.java | 291 + .../umplugin/ldap/UserMappingSetupLDAP.java | 463 + federated/umplugin/ldap/entry.ldif | 41 + federated/umplugin/ldap/schema.ldif | 52 + ha/xml/db2ha.xsd | 341 + ha/xml/db2ha_sample_DPF_NPlusM.xml | 132 + ha/xml/db2ha_sample_DPF_mutual.xml | 200 + ha/xml/db2ha_sample_HADR.xml | 147 + ha/xml/db2ha_sample_sharedstorage_mutual.xml | 131 + java/Websphere/AIRLINE.war | Bin 0 -> 988058 bytes java/Websphere/AccessEmployee.ear | Bin 0 -> 178077 bytes java/Websphere/OptimisticLocking.war | Bin 0 -> 104244 bytes java/Websphere/README | 136 + java/Websphere/airline.db2 | 68 + java/jdbc/AdmCmdAutoCfg.java | 153 + java/jdbc/AdmCmdContacts.java | 282 + java/jdbc/AdmCmdDescribe.java | 217 + java/jdbc/AdmCmdExport.java | 195 + java/jdbc/AdmCmdImport.java | 230 + java/jdbc/AdmCmdOnlineBackup.java | 158 + java/jdbc/AdmCmdQuiesce.java | 152 + java/jdbc/AdmCmdUpdateCfg.java | 160 + java/jdbc/Applt.html | 33 + java/jdbc/Applt.java | 175 + java/jdbc/Array_Stack.java | 148 + java/jdbc/Arrays_Sqlpl.java | 163 + java/jdbc/Cgtt.java | 346 + java/jdbc/CreateCGTT.db2 | 425 + java/jdbc/CreateEmployee.java | 508 + java/jdbc/CreateGTF.db2 | 92 + java/jdbc/DB2EvmonChangeHistory.xsl | 565 + java/jdbc/DB2EvmonLocking.xsl | 1169 ++ java/jdbc/DB2EvmonPkgCache.xsl | 1041 ++ java/jdbc/DB2EvmonUOW.xsl | 1479 +++ java/jdbc/DB2LockReportHTML.xsl | 499 + java/jdbc/DbAuth.java | 224 + java/jdbc/DbConn.java | 89 + java/jdbc/DbInfo.java | 144 + java/jdbc/DbMCon.java | 246 + java/jdbc/DbNative.java | 117 + java/jdbc/DbRsHold.java | 426 + java/jdbc/DbSeq.java | 437 + java/jdbc/DbUse.java | 219 + java/jdbc/DropCGTT.db2 | 56 + java/jdbc/DropGTF.db2 | 37 + java/jdbc/DtInfo.java | 204 + java/jdbc/DtLob.java | 547 + java/jdbc/DtUdt.java | 261 + java/jdbc/GTFqueries.db2 | 38 + java/jdbc/GeneratePayroll.java | 341 + java/jdbc/GetDBCfgParams.java | 186 + java/jdbc/GetDBMCfgParams.java | 181 + java/jdbc/GetLogs.java | 324 + java/jdbc/GetMessage.java | 147 + java/jdbc/IlInfo.java | 171 + java/jdbc/ImplicitCasting.java | 968 ++ java/jdbc/JCCKerberosPlugin.java | 253 + java/jdbc/JCCKerberosPluginTest.java | 120 + java/jdbc/JCCSimpleGSSContext.java | 1295 ++ java/jdbc/JCCSimpleGSSCredential.java | 346 + java/jdbc/JCCSimpleGSSException.java | 61 + java/jdbc/JCCSimpleGSSName.java | 227 + java/jdbc/JCCSimpleGSSPlugin.java | 169 + java/jdbc/JCCSimpleGSSPluginTest.java | 118 + java/jdbc/LargeRid.java | 757 ++ java/jdbc/README | 431 + java/jdbc/ScalarFunctions.java | 2437 ++++ java/jdbc/SetIntegrity.java | 1180 ++ java/jdbc/SpClient.java | 692 ++ java/jdbc/SpCreate.db2 | 165 + java/jdbc/SpDrop.db2 | 51 + java/jdbc/SpServer.java | 944 ++ java/jdbc/TbAST.java | 376 + java/jdbc/TbCompress.java | 214 + java/jdbc/TbConstr.java | 1473 +++ java/jdbc/TbCreate.java | 169 + java/jdbc/TbGenCol.java | 403 + java/jdbc/TbIdent.java | 272 + java/jdbc/TbInTrig.java | 881 ++ java/jdbc/TbInfo.java | 202 + java/jdbc/TbMerge.java | 370 + java/jdbc/TbMod.java | 1072 ++ java/jdbc/TbOnlineInx.java | 317 + java/jdbc/TbPriv.java | 225 + java/jdbc/TbRead.java | 1501 +++ java/jdbc/TbRowcompress.java | 1141 ++ java/jdbc/TbRunstats.java | 181 + java/jdbc/TbSel.java | 570 + java/jdbc/TbTemp.java | 503 + java/jdbc/TbTrig.java | 1011 ++ java/jdbc/TbUMQT.java | 952 ++ java/jdbc/TbUnion.java | 700 ++ java/jdbc/Temporal.java | 655 + java/jdbc/TrustedContext.java | 755 ++ java/jdbc/UDFCreate.db2 | 68 + java/jdbc/UDFDrop.db2 | 38 + java/jdbc/UDFcli.java | 284 + java/jdbc/UDFcsvReader.java | 329 + java/jdbc/UDFjCreate.db2 | 43 + java/jdbc/UDFjDrop.db2 | 34 + java/jdbc/UDFjcli.java | 175 + java/jdbc/UDFjsrv.java | 105 + java/jdbc/UDFsCreate.db2 | 74 + java/jdbc/UDFsDrop.db2 | 37 + java/jdbc/UDFsqlcl.java | 287 + java/jdbc/UDFsqlsv.java | 364 + java/jdbc/UDFsrv.java | 284 + java/jdbc/Util.java | 340 + java/jdbc/bonus_calculate.db2 | 90 + java/jdbc/db2evmonfmt.java | 2738 +++++ java/jdbc/makefile | 402 + java/jdbc/sample.csv | 5 + java/jdbc/spcat | 58 + java/jdbc/stack_functions.db2 | 144 + java/jdbc/udfcat | 58 + java/jdbc/udfjcat | 31 + java/sqlj/Applt.html | 33 + java/sqlj/Applt.sqlj | 221 + java/sqlj/Batch1Demo.sqlj | 171 + java/sqlj/Batch2Demo.sqlj | 282 + java/sqlj/Batch3Demo.sqlj | 212 + java/sqlj/BlobClobDemo.sqlj | 168 + java/sqlj/CreateDemoSchema.sqlj | 87 + java/sqlj/CreateEmployee.sqlj | 331 + java/sqlj/DS1.prop | 9 + java/sqlj/DS2.prop | 9 + java/sqlj/DS3.prop | 9 + java/sqlj/DbAuth.sqlj | 219 + java/sqlj/DbConMDataSources.sqlj | 184 + java/sqlj/DbConn.sqlj | 92 + java/sqlj/DbConnDataSource.sqlj | 123 + java/sqlj/DbMCon.sqlj | 238 + java/sqlj/DbUse.sqlj | 168 + java/sqlj/DtUdt.sqlj | 250 + java/sqlj/GeneratePayroll.sqlj | 367 + java/sqlj/LargeRid.sqlj | 399 + java/sqlj/LargeRidScrpt | 30 + java/sqlj/LargeRid_cleanup.db2 | 64 + java/sqlj/LargeRid_setup.db2 | 173 + java/sqlj/README | 704 ++ java/sqlj/ScrollIterDemo.sqlj | 235 + java/sqlj/SetIntegrity.sqlj | 803 ++ java/sqlj/SetIntegrityScrpt | 30 + java/sqlj/SetIntegrity_cleanup.db2 | 73 + java/sqlj/SetIntegrity_setup.db2 | 156 + java/sqlj/SpClient.sqlj | 582 + java/sqlj/SpCreate.db2 | 165 + java/sqlj/SpDrop.db2 | 51 + java/sqlj/SpIterat.sqlj | 40 + java/sqlj/SpServer.sqlj | 882 ++ java/sqlj/TbAST.sqlj | 287 + java/sqlj/TbASTScrpt | 30 + java/sqlj/TbAST_cleanup.db2 | 50 + java/sqlj/TbAST_setup.db2 | 70 + java/sqlj/TbCompress.sqlj | 199 + java/sqlj/TbConstr.sqlj | 1426 +++ java/sqlj/TbCreate.sqlj | 161 + java/sqlj/TbIdent.sqlj | 266 + java/sqlj/TbInfo.sqlj | 185 + java/sqlj/TbMod.sqlj | 1058 ++ java/sqlj/TbOnlineInx.sqlj | 310 + java/sqlj/TbPriv.sqlj | 219 + java/sqlj/TbRead.sqlj | 1403 +++ java/sqlj/TbRowcompress.sqlj | 648 + java/sqlj/TbRowcompressScrpt | 30 + java/sqlj/TbRowcompress_cleanup.db2 | 62 + java/sqlj/TbRowcompress_setup.db2 | 64 + java/sqlj/TbRunstats.sqlj | 176 + java/sqlj/TbSel.sqlj | 517 + java/sqlj/TbTemp.sqlj | 482 + java/sqlj/TbTrig.sqlj | 1008 ++ java/sqlj/TbUMQT.sqlj | 872 ++ java/sqlj/UDFCreate.db2 | 68 + java/sqlj/UDFDrop.db2 | 38 + java/sqlj/UDFcli.sqlj | 274 + java/sqlj/UDFjCreate.db2 | 43 + java/sqlj/UDFjDrop.db2 | 34 + java/sqlj/UDFjcli.sqlj | 167 + java/sqlj/UDFjsrv.java | 107 + java/sqlj/UDFsrv.java | 271 + java/sqlj/Util.sqlj | 319 + java/sqlj/bldsqlj | 90 + java/sqlj/bldsqljds | 66 + java/sqlj/bldsqljs | 97 + java/sqlj/createRegisterDS.java | 127 + java/sqlj/jndi.properties | 2 + java/sqlj/makefile | 439 + java/sqlj/spcat | 31 + java/sqlj/udfcat | 30 + java/sqlj/udfjcat | 31 + lifesci/SCRIPT_DAEMON.config | 7 + lifesci/biors/create_function_mappings.ddl | 214 + lifesci/script/create_function_mappings.ddl | 38 + pd/db2_hang_analyze | 2621 ++++ pd/db2_hang_detect | 1649 +++ perf/db2mon.sh | 63 + perf/db2mon.sql | 2480 ++++ perf/db2monAfter.sql | 2102 ++++ perf/db2monBefore.sql | 377 + perf/db2monInterval.sql | 1 + perf/db2mon_export.sql | 199 + perf/db2mon_import.sql | 606 + perf/db2mon_report.sql | 2045 ++++ perl/DB2SampUtil.pm | 176 + perl/DB2WlmHist.pm | 156 + perl/README | 183 + perl/README_QPWLMMIG | 234 + perl/README_WLMHIST | 245 + perl/dbauth.pl | 231 + perl/dbuse.pl | 220 + perl/dtlob.pl | 384 + perl/hadrCalculator.pl | 432 + perl/qpwlmmig.pl | 1586 +++ perl/spclient.pl | 1076 ++ perl/tbconstr.pl | 984 ++ perl/tbinfo.pl | 171 + perl/tbpriv.pl | 223 + perl/tbsel.pl | 436 + perl/tbselcreate.db2 | 64 + perl/tbseldrop.db2 | 44 + perl/tbselinit | 29 + perl/tbtrig.pl | 918 ++ perl/tbuse.pl | 305 + perl/wlmhist.pl | 1019 ++ perl/wlmhistrep.pl | 1068 ++ php/DbAuthorities_DB2.php | 381 + php/DbAuthorities_PDO.php | 386 + php/DtInfo_DB2.php | 164 + php/DtInfo_PDO.php | 162 + php/DtLOB_DB2.php | 707 ++ php/DtLOB_PDO_generic.php | 755 ++ php/DtUDT_DB2.php | 316 + php/DtUDT_PDO.php | 347 + php/PHPSampleConfig.cfg | 5 + php/README | 423 + php/TblConstraints_DB2.php | 1663 +++ php/TblConstraints_PDO.php | 2085 ++++ php/TblIdentityCol_DB2.php | 332 + php/TblIdentityCol_PDO.php | 352 + php/TblSelect_DB2.php | 753 ++ php/TblSelect_PDO.php | 813 ++ php/TblTrigger_DB2.php | 1143 ++ php/TblTrigger_PDO.php | 1421 +++ php/TblUnion_DB2.php | 1151 ++ php/TblUnion_PDO.php | 1603 +++ php/UtilConnection_DB2.php | 282 + php/UtilConnection_DB2_Def | 76 + php/UtilConnection_PDO.php | 373 + php/UtilConnection_PDO_Def | 83 + php/UtilIOHelper.php | 421 + php/UtilIOHelper_Def | 128 + php/UtilTableSetup_Def | 39 + php/UtilTableSetup_LOB.php | 98 + php/UtilTableSetup_Staff.php | 125 + php/UtilTableSetup_Xml.php | 288 + php/XmlFlwor_DB2.php | 384 + php/XmlIndex_DB2.php | 850 ++ php/XmlInsert_DB2.php | 878 ++ php/XmlRead_DB2.php | 374 + php/XmlRelToXmlDOC_DB2.php | 413 + php/XmlRelToXmlType_DB2.php | 274 + php/XmlRunstats.php | 329 + php/XmlSQLXQuery_DB2.php | 367 + php/XmlSchema_DB2.php | 366 + php/XmlToTable_DB2.php | 808 ++ php/XmlUniqueIndexes_DB2.php | 603 + php/XmlUpAndDel_DB2.php | 875 ++ php/XmlXPath_DB2.php | 369 + php/XmlXQuery_DB2.php | 426 + php/photo.gif | Bin 0 -> 29540 bytes php/resume.txt | 56 + php/tbselinit | 22 + plsql/README | 25 + repl/asnclp/2Nodes.in | 42 + repl/asnclp/2nodes/2Node0.in | 43 + repl/asnclp/2nodes/2Node1.in | 43 + repl/asnclp/2nodes/2Node2.in | 49 + repl/asnclp/3Nodes.in | 46 + repl/asnclp/3nodes/3Node0.in | 53 + repl/asnclp/3nodes/3Node1.in | 53 + repl/asnclp/3nodes/3Node2.in | 53 + repl/asnclp/3nodes/3Node3.in | 59 + repl/asnclp/Addtables.in | 36 + repl/asnclp/AlterPubQMap.txt | 45 + repl/asnclp/AlterQReplMap.txt | 45 + repl/asnclp/AlterQSubsUOW.txt | 51 + repl/asnclp/AlterXMLUOW.txt | 47 + repl/asnclp/Bidir.in | 46 + repl/asnclp/CrtPubQMap.txt | 45 + repl/asnclp/CrtQApplyUOW.txt | 47 + repl/asnclp/CrtQCapP2P.txt | 45 + repl/asnclp/CrtQCaptureUOW.txt | 50 + repl/asnclp/CrtQSubCCD.txt | 45 + repl/asnclp/CrtQSubsUOW.txt | 49 + repl/asnclp/CrtReg.txt | 45 + repl/asnclp/CrtReplQMap.txt | 47 + repl/asnclp/CrtReplQMap3nodes.txt | 45 + repl/asnclp/CrtSubs.txt | 45 + repl/asnclp/CrtXMLPubs.txt | 46 + repl/asnclp/Delete.in | 47 + repl/asnclp/DropPubQMap.txt | 43 + repl/asnclp/DropQApplyUOW.txt | 47 + repl/asnclp/DropQCapP2P.txt | 45 + repl/asnclp/DropQCaptureUOW.txt | 48 + repl/asnclp/DropQSubs.txt | 49 + repl/asnclp/DropReplQMap.txt | 47 + repl/asnclp/DropReplQMap3nodes.txt | 45 + repl/asnclp/DropXMLPub.txt | 45 + repl/asnclp/DropXMLPubs.txt | 45 + repl/asnclp/MassSubcrt.txt | 45 + repl/asnclp/P2PREADME.TXT | 119 + repl/asnclp/Update.in | 40 + repl/asnclp/ValidateWSMQ.txt | 48 + repl/asnclp/addtables/Addtables.in | 42 + repl/asnclp/bidir/Bidir0.in | 45 + repl/asnclp/bidir/Bidir1.in | 45 + repl/asnclp/bidir/Bidir2.in | 47 + repl/asnclp/bidir/Bidir3.in | 48 + repl/asnclp/delete/Delete0.in | 41 + repl/asnclp/delete/Delete1.in | 39 + repl/asnclp/delete/Delete2.in | 40 + repl/asnclp/delete/Delete3.in | 40 + repl/asnclp/q/exccdfanout.in | 45 + repl/asnclp/q/newccdfanout.in | 45 + repl/asnclp/setup.sql | 77 + repl/asnclp/update/Update0.in | 40 + repl/asnclp/update/Update3.in | 42 + repl/asnqwxml/README.htm | 1560 +++ repl/asnqwxml/stockticker/build.xml | 417 + .../asnqwxml/stockticker/dist/stockticker.war | Bin 0 -> 9983 bytes .../asnqwxml/stockticker/scripts/capparms.sql | 13 + .../asnqwxml/stockticker/scripts/createdb.sql | 5 + .../stockticker/scripts/stockdata_dlt.sql | 17 + .../stockticker/scripts/stockdata_init.sql | 22 + .../stockticker/scripts/stockdata_ins.sql | 45 + .../stockticker/scripts/stockdata_upd.sql | 45 + repl/asnqwxml/stockticker/scripts/stocks.mq | 15 + repl/asnqwxml/stockticker/scripts/stocks.sql | 40 + .../stockticker/scripts/stockxpub.sql | 82 + .../samples/repl/publication/StockPrice.java | 150 + .../repl/publication/StockPriceListener.java | 320 + repl/asnqwxml/stockticker/web/WEB-INF/web.xml | 20 + repl/asnqwxml/stockticker/web/stockticker.jsp | 244 + repl/mig10/q/asnoqcapluwv10.sql | 89 + repl/mig10/q/asnoqcapluwv10fp.sql | 37 + repl/mig10/q/asnqappluwinfxv10.sql | 55 + repl/mig10/q/asnqappluwinfxv10fp.sql | 80 + repl/mig10/q/asnqappluwmssqlv10.sql | 56 + repl/mig10/q/asnqappluwmssqlv10fp.sql | 72 + repl/mig10/q/asnqappluworav10.sql | 56 + repl/mig10/q/asnqappluworav10fp.sql | 85 + repl/mig10/q/asnqappluwsybv10.sql | 58 + repl/mig10/q/asnqappluwsybv10fp.sql | 71 + repl/mig10/q/asnqappluwteradatav10.sql | 57 + repl/mig10/q/asnqappluwteradatav10fp.sql | 77 + repl/mig10/q/asnqappluwv10.sql | 57 + repl/mig10/q/asnqappluwv10fp.sql | 47 + repl/mig10/q/asnqcapluwv10.sql | 145 + repl/mig10/q/asnqcapluwv10fp.sql | 37 + repl/mig10/q/asnqmz10.sql | 1 + repl/mig10/sql/asnappluwv10.sql | 190 + repl/mig10/sql/asncapluwv10.sql | 293 + repl/mig10/sql/asnmz10.sql | 1 + repl/mig1021/mon/asnmonluwv1021.sql | 25 + repl/mig1021/mon/asnmonluwv1021fp.sql | 41 + repl/mig1021/q/asnoqappluwv1021.sql | 225 + repl/mig1021/q/asnoqappluwv1021fp.sql | 184 + repl/mig1021/q/asnoqcapluwv1021.sql | 49 + repl/mig1021/q/asnoqcapluwv1021fp.sql | 29 + repl/mig1021/q/asnqappluwinfxv1021.sql | 213 + repl/mig1021/q/asnqappluwinfxv1021fp.sql | 32 + repl/mig1021/q/asnqappluwmssqlv1021.sql | 214 + repl/mig1021/q/asnqappluwmssqlv1021fp.sql | 32 + repl/mig1021/q/asnqappluworav1021.sql | 241 + repl/mig1021/q/asnqappluworav1021fp.sql | 32 + repl/mig1021/q/asnqappluwsybv1021.sql | 213 + repl/mig1021/q/asnqappluwsybv1021fp.sql | 31 + repl/mig1021/q/asnqappluwteradatav1021.sql | 211 + repl/mig1021/q/asnqappluwteradatav1021fp.sql | 31 + repl/mig1021/q/asnqappluwv1021.sql | 200 + repl/mig1021/q/asnqappluwv1021fp.sql | 39 + repl/mig1021/q/asnqcapluwv1021.sql | 60 + repl/mig1021/q/asnqcapluwv1021fp.sql | 27 + repl/mig1021/sql/asnappluwv1021.sql | 24 + repl/mig1021/sql/asnappluwv1021fp.sql | 25 + repl/mig1021/sql/asncapluwv1021.sql | 43 + repl/mig1021/sql/asncapluwv1021fp.sql | 32 + repl/mig1140/mon/asnmonluwv1140.sql | 25 + repl/mig1140/mon/asnmonluwv1140fp.sql | 28 + repl/mig1140/q/asnoqappluwv1140.sql | 105 + repl/mig1140/q/asnoqappluwv1140fp.sql | 28 + repl/mig1140/q/asnoqcapluwv1140.sql | 164 + repl/mig1140/q/asnoqcapluwv1140fp.sql | 29 + repl/mig1140/q/asnqappluwinfxv1140.sql | 153 + repl/mig1140/q/asnqappluwinfxv1140fp.sql | 32 + repl/mig1140/q/asnqappluwmssqlv1140.sql | 160 + repl/mig1140/q/asnqappluwmssqlv1140fp.sql | 32 + repl/mig1140/q/asnqappluworav1140.sql | 160 + repl/mig1140/q/asnqappluworav1140fp.sql | 32 + repl/mig1140/q/asnqappluwsybv1140.sql | 153 + repl/mig1140/q/asnqappluwsybv1140fp.sql | 31 + repl/mig1140/q/asnqappluwteradatav1140.sql | 153 + repl/mig1140/q/asnqappluwteradatav1140fp.sql | 31 + repl/mig1140/q/asnqappluwv1140.sql | 130 + repl/mig1140/q/asnqappluwv1140fp.sql | 29 + repl/mig1140/q/asnqcapluw1140.sql | 182 + repl/mig1140/q/asnqcapluwv1140fp.sql | 27 + repl/mig1140/sql/asnappluwv1140.sql | 19 + repl/mig1140/sql/asnappluwv1140fp.sql | 20 + repl/mig1140/sql/asncapluwv1140.sql | 28 + repl/mig1140/sql/asncapluwv1140fp.sql | 29 + repl/mig8/sql/asnmig8.txt | 410 + repl/mig8/sql/asnmigpw.C | 214 + repl/mig8/sql/mig8400.sql | 910 ++ repl/mig8/sql/mig8fed.sql | 2260 ++++ repl/mig8/sql/mig8udb.sql | 1095 ++ repl/mig8/sql/mig8zos.sql | 1152 ++ repl/mig9/mon/asnmonluw.sql | 58 + repl/mig9/q/asnqappinfx.sql | 147 + repl/mig9/q/asnqappluw.sql | 113 + repl/mig9/q/asnqappmssql.sql | 147 + repl/mig9/q/asnqappora.sql | 161 + repl/mig9/q/asnqappsyb.sql | 147 + repl/mig9/q/asnqcapluw.sql | 115 + repl/mig9/q/asnqmzv9.sql | 338 + repl/mig9/sql/asnsmzv9.sql | 71 + repl/mig95/mon/asnmonv95.sql | 13 + repl/mig95/q/asnqappinfxv95.sql | 52 + repl/mig95/q/asnqappluwv95.sql | 39 + repl/mig95/q/asnqappmssqlv95.sql | 55 + repl/mig95/q/asnqapporav95.sql | 59 + repl/mig95/q/asnqappsybv95.sql | 54 + repl/mig95/q/asnqcapluwv95.sql | 66 + repl/mig95/q/asnqmz95.sql | 205 + repl/mig95/q/asnqreplfallbackv95.sql | 36 + repl/mig95/q/asnqupdcompv95.sql | 15 + repl/mig95/sql/asnsmz95.sql | 8 + repl/mig97/q/asnoqcapluwv97fp.sql | 151 + repl/mig97/q/asnqappinfxv97.sql | 101 + repl/mig97/q/asnqappinfxv97fp.sql | 173 + repl/mig97/q/asnqappluwv97.sql | 66 + repl/mig97/q/asnqappluwv97fp.sql | 145 + repl/mig97/q/asnqappmssqlv97.sql | 101 + repl/mig97/q/asnqappmssqlv97fp.sql | 180 + repl/mig97/q/asnqapporav97.sql | 98 + repl/mig97/q/asnqapporav97fp.sql | 200 + repl/mig97/q/asnqappsybv97.sql | 148 + repl/mig97/q/asnqappsybv97fp.sql | 161 + repl/mig97/q/asnqappteradatav97fp.sql | 176 + repl/mig97/q/asnqcapluwv97.sql | 97 + repl/mig97/q/asnqcapluwv97fp.sql | 322 + repl/mig97/q/asnqmz97.sql | 225 + repl/mig97/q/asnqupdcompv97.sql | 52 + repl/mig97/sql/asnappluwv97fp.sql | 118 + repl/mig97/sql/asncapinfxv97.sql | 1 + repl/mig97/sql/asncapluwv97.sql | 63 + repl/mig97/sql/asncapluwv97fp.sql | 140 + repl/mig97/sql/asncapmssqlv97.sql | 1 + repl/mig97/sql/asncaporav97.sql | 1 + repl/mig97/sql/asncapsybv97.sql | 1 + repl/mig97/sql/asnmz97.sql | 60 + repl/mig98/q/asnqappluw.sql | 46 + repl/mig98/q/asnqcapluw.sql | 59 + repl/mon/asnmctlw.sql | 217 + repl/mon/asnmctlz.sql | 257 + repl/mon/monitor_api.c | 200 + repl/mon/monitor_api_nt.mak | 20 + repl/mon/monitor_api_unix.mak | 30 + repl/q/README.Q | 131 + repl/q/asnqdefq | 270 + repl/q/asnqspC.SQC | 453 + repl/q/asnqspC.def | 3 + repl/q/asnqspC.exp | 1 + repl/q/asnqspC.mak | 18 + repl/q/asnqspSQL.sql | 198 + repl/q/asnqspcreate.sql | 26 + repl/q/mq/p2p_2node_remote.pdf | Bin 0 -> 380121 bytes repl/q/mq/pub_local.pdf | Bin 0 -> 299588 bytes repl/q/mq/pub_remote.pdf | Bin 0 -> 354601 bytes repl/q/mq/smart_p2p_2node_remote.pdf | Bin 0 -> 869222 bytes repl/q/mq/smart_uni_remote.pdf | Bin 0 -> 866334 bytes repl/q/mq/uni_remote.pdf | Bin 0 -> 348401 bytes repl/q/mqcap.xsd | 1307 ++ repl/q/mqsub.xsd | 54 + repl/q/qapply_api.C | 158 + repl/q/qapply_api_nt.mak | 20 + repl/q/qapply_api_unix.mak | 36 + repl/q/qcapture_api.C | 168 + repl/q/qcapture_api_nt.mak | 20 + repl/q/qcapture_api_unix.mak | 36 + repl/sql/ASNDONE.smp | 131 + repl/sql/ASNLOAD.smp | 6288 ++++++++++ repl/sql/README.SQL | 114 + repl/sql/apply_api.c | 206 + repl/sql/apply_api_nt.mak | 20 + repl/sql/apply_api_unix.mak | 30 + repl/sql/asnctlw.sql | 873 ++ repl/sql/asnctlz.sql | 2 + repl/sql/asnctlz7.sql | 2 + repl/sql/asnload.h | 232 + repl/sql/asnload.ini | 51 + repl/sql/asnmail.smp | 105 + repl/sql/asnparseini.C | 2953 +++++ repl/sql/capture_api.c | 203 + repl/sql/capture_api_nt.mak | 20 + repl/sql/capture_api_unix.mak | 30 + .../publication/ActivateSubscriptionMsg.java | 77 + .../tools/repl/publication/AddColumnMsg.java | 79 + .../db2/tools/repl/publication/Column.java | 104 + .../tools/repl/publication/ColumnSchema.java | 199 + .../tools/repl/publication/ControlMsg.java | 111 + .../db2/tools/repl/publication/DataMsg.java | 12 + .../DeactivateSubscriptionMsg.java | 77 + .../repl/publication/ErrorReportMsg.java | 82 + .../tools/repl/publication/HeartbeatMsg.java | 48 + .../repl/publication/InformationalMsg.java | 17 + .../publication/InvalidateSendQueueMsg.java | 77 + .../db2/tools/repl/publication/LOBMsg.java | 187 + .../repl/publication/LoadDoneControlMsg.java | 77 + .../repl/publication/LoadDoneReceivedMsg.java | 78 + .../ibm/db2/tools/repl/publication/Msg.java | 112 + .../publication/PublicationMsgListener.java | 16 + .../publication/PublicationMsgProvider.java | 47 + .../PublicationMsgProviderFactory.java | 25 + .../ibm/db2/tools/repl/publication/Row.java | 153 + .../repl/publication/RowOperationMsg.java | 137 + .../SubscriptionDeactivatedMsg.java | 79 + .../publication/SubscriptionSchemaMsg.java | 234 + .../repl/publication/TransactionMsg.java | 156 + .../ibm/db2/tools/repl/publication/Utils.java | 75 + .../support/PublicationHandler.java | 605 + .../support/PublicationMsgProviderImpl.java | 123 + .../support/PublicationParser.java | 49 + repl/xmlpubtk/doc/allclasses-frame.html | 77 + repl/xmlpubtk/doc/allclasses-noframe.html | 77 + .../publication/ActivateSubscriptionMsg.html | 379 + .../tools/repl/publication/AddColumnMsg.html | 505 + .../db2/tools/repl/publication/Column.html | 570 + .../tools/repl/publication/ColumnSchema.html | 718 ++ .../tools/repl/publication/ControlMsg.html | 381 + .../db2/tools/repl/publication/DataMsg.html | 244 + .../DeactivateSubscriptionMsg.html | 379 + .../repl/publication/ErrorReportMsg.html | 507 + .../tools/repl/publication/HeartbeatMsg.html | 388 + .../repl/publication/InformationalMsg.html | 244 + .../publication/InvalidateSendQueueMsg.html | 379 + .../db2/tools/repl/publication/LOBMsg.html | 867 ++ .../repl/publication/LoadDoneControlMsg.html | 379 + .../repl/publication/LoadDoneReceivedMsg.html | 505 + .../ibm/db2/tools/repl/publication/Msg.html | 478 + .../publication/PublicationMsgListener.html | 206 + .../publication/PublicationMsgProvider.html | 283 + .../PublicationMsgProviderFactory.html | 252 + .../ibm/db2/tools/repl/publication/Row.html | 747 ++ .../repl/publication/RowOperationMsg.html | 692 ++ .../SubscriptionDeactivatedMsg.html | 505 + .../publication/SubscriptionSchemaMsg.html | 1055 ++ .../repl/publication/TransactionMsg.html | 755 ++ .../ibm/db2/tools/repl/publication/Utils.html | 357 + .../tools/repl/publication/package-frame.html | 88 + .../repl/publication/package-summary.html | 247 + .../tools/repl/publication/package-tree.html | 143 + repl/xmlpubtk/doc/constant-values.html | 211 + repl/xmlpubtk/doc/deprecated-list.html | 122 + repl/xmlpubtk/doc/help-doc.html | 171 + repl/xmlpubtk/doc/index-all.html | 1147 ++ repl/xmlpubtk/doc/index.html | 22 + repl/xmlpubtk/doc/overview-tree.html | 143 + repl/xmlpubtk/doc/package-list | 1 + repl/xmlpubtk/doc/packages.html | 26 + repl/xmlpubtk/doc/serialized-form.html | 122 + repl/xmlpubtk/doc/stylesheet.css | 29 + repl/xmlpubtk/loadqueue/LoadQueue.jar | Bin 0 -> 22115 bytes repl/xmlpubtk/loadqueue/LoadQueue.java | 138 + repl/xmlpubtk/readme.txt | 63 + repl/xmlpubtk/sample1/sample1.jar | Bin 0 -> 3609 bytes repl/xmlpubtk/sample1/sample1.java | 75 + repl/xmlpubtk/sample2/Count.java | 11 + repl/xmlpubtk/sample2/MonitorFrame.java | 91 + repl/xmlpubtk/sample2/MonitorTablePanel.java | 209 + .../xmlpubtk/sample2/PublicationListener.java | 157 + repl/xmlpubtk/sample2/sample2.jar | Bin 0 -> 16882 bytes repl/xmlpubtk/sample2/sample2.java | 58 + repl/xmlpubtk/sample3/Count.java | 37 + repl/xmlpubtk/sample3/MonitorFrame.java | 165 + repl/xmlpubtk/sample3/MonitorTablePanel.java | 149 + .../sample3/PublicationDataModel.java | 235 + .../xmlpubtk/sample3/PublicationListener.java | 132 + .../sample3/PublicationTableCellRenderer.java | 109 + .../sample3/PublicationTableModel.java | 254 + repl/xmlpubtk/sample3/StringWithInterval.java | 26 + repl/xmlpubtk/sample3/SubscriptionDialog.java | 114 + repl/xmlpubtk/sample3/TableName.java | 47 + repl/xmlpubtk/sample3/sample3.jar | Bin 0 -> 32426 bytes repl/xmlpubtk/sample3/sample3.java | 57 + repl/xmlpubtk/xmlpubtk.jar | 0 security/plugins/IBMLDAPauthclient.c | 396 + security/plugins/IBMLDAPauthserver.c | 449 + security/plugins/IBMLDAPconfig.c | 626 + security/plugins/IBMLDAPgroups.c | 1251 ++ security/plugins/IBMLDAPutils.c | 1030 ++ security/plugins/IBMLDAPutils.h | 286 + security/plugins/IBMkrb5.c | 2292 ++++ security/plugins/README | 80 + security/plugins/bldplugin | 80 + security/plugins/combined.c | 1355 +++ security/plugins/group_file.c | 738 ++ security/plugins/gssapi_simple.c | 1851 +++ security/plugins/makefile | 86 + selinux/RHEL5/Makefile | 24 + selinux/RHEL5/README | 147 + selinux/RHEL5/db2.fc | 52 + selinux/RHEL5/db2.if | 53 + selinux/RHEL5/db2.te | 256 + selinux/RHEL5/ibm_db2_semanage_das | 30 + selinux/RHEL5/ibm_db2_semanage_db2inst | 109 + sql_statements/README | 25 + sqlpl/NestedSP.java | 230 + sqlpl/README | 489 + sqlpl/Util.java | 340 + sqlpl/array_stack.db2 | 203 + sqlpl/arrays_sqlpl.db2 | 180 + sqlpl/basecase.db2 | 74 + sqlpl/basecase.sqc | 189 + sqlpl/baseif.db2 | 72 + sqlpl/baseif.sqc | 189 + sqlpl/bldapp | 104 + sqlpl/bldcli | 91 + sqlpl/defaultparam.db2 | 173 + sqlpl/dynamic.db2 | 85 + sqlpl/dynamic.sqc | 181 + sqlpl/embprep | 63 + sqlpl/iterate.db2 | 85 + sqlpl/iterate.sqc | 156 + sqlpl/leave.db2 | 89 + sqlpl/leave.sqc | 163 + sqlpl/loop.db2 | 86 + sqlpl/loop.sqc | 163 + sqlpl/makefile | 183 + sqlpl/modules.db2 | 1086 ++ sqlpl/nestcase.db2 | 105 + sqlpl/nestcase.sqc | 224 + sqlpl/nestedsp.db2 | 126 + sqlpl/nestedspdrop.db2 | 49 + sqlpl/nestif.db2 | 100 + sqlpl/nestif.sqc | 226 + sqlpl/repeat.db2 | 86 + sqlpl/repeat.sqc | 163 + sqlpl/rsultset.c | 156 + sqlpl/rsultset.db2 | 102 + sqlpl/spserver.db2 | 549 + sqlpl/tbfn.db2 | 198 + sqlpl/tbfnuse.db2 | 205 + sqlpl/tbsel.sqc | 272 + sqlpl/tbselcreate.db2 | 215 + sqlpl/tbseldrop.db2 | 49 + sqlpl/utilapi.c | 340 + sqlpl/utilapi.h | 116 + sqlpl/utilcli.c | 563 + sqlpl/utilcli.h | 117 + sqlpl/utilemb.h | 94 + sqlpl/utilemb.sqc | 129 + sqlpl/whiles.db2 | 94 + sqlpl/whiles.sqc | 167 + webservices/soapsample.sql | 152 + wrappers/wrapper_sdk/cc_plugin/README | 11 + wrappers/wrapper_sdk/cc_plugin/makefile | 32 + wrappers/wrapper_sdk/cc_plugin/sample.db2 | 34 + wrappers/wrapper_sdk/cc_plugin/sample.java | 135 + .../wrapper_sdk/cc_plugin/sample.properties | 8 + wrappers/wrapper_sdk/cc_plugin/sample.xml | 57 + wrappers/wrapper_sdk/makefile | 117 + wrappers/wrapper_sdk/sample_connection.C | 242 + wrappers/wrapper_sdk/sample_connection.h | 67 + wrappers/wrapper_sdk/sample_error_reporting.h | 39 + wrappers/wrapper_sdk/sample_fenced_nickname.C | 213 + wrappers/wrapper_sdk/sample_fenced_nickname.h | 41 + wrappers/wrapper_sdk/sample_fenced_server.C | 151 + wrappers/wrapper_sdk/sample_fenced_server.h | 44 + wrappers/wrapper_sdk/sample_fenced_user.C | 67 + wrappers/wrapper_sdk/sample_fenced_user.h | 35 + wrappers/wrapper_sdk/sample_fenced_wrapper.C | 162 + wrappers/wrapper_sdk/sample_fenced_wrapper.h | 44 + wrappers/wrapper_sdk/sample_nickname.C | 345 + wrappers/wrapper_sdk/sample_nickname.h | 71 + wrappers/wrapper_sdk/sample_operation.C | 2616 ++++ wrappers/wrapper_sdk/sample_operation.h | 134 + wrappers/wrapper_sdk/sample_portability.h | 72 + wrappers/wrapper_sdk/sample_server.C | 1054 ++ wrappers/wrapper_sdk/sample_server.h | 84 + wrappers/wrapper_sdk/sample_typedefs.h | 78 + wrappers/wrapper_sdk/sample_user.C | 68 + wrappers/wrapper_sdk/sample_user.h | 38 + wrappers/wrapper_sdk/sample_utilities.C | 487 + wrappers/wrapper_sdk/sample_utilities.h | 58 + wrappers/wrapper_sdk/sample_wrapper.C | 170 + wrappers/wrapper_sdk/sample_wrapper.h | 51 + .../wrapper_sdk_java/FencedFileNickname.java | 199 + .../wrapper_sdk_java/FencedFileServer.java | 74 + .../wrapper_sdk_java/FencedFileWrapper.java | 44 + wrappers/wrapper_sdk_java/FileConnection.java | 53 + wrappers/wrapper_sdk_java/FileExecDesc.java | 451 + wrappers/wrapper_sdk_java/FileQuery.java | 387 + wrappers/wrapper_sdk_java/Readme.txt | 134 + .../UnfencedFileNickname.java | 209 + .../wrapper_sdk_java/UnfencedFileServer.java | 387 + .../wrapper_sdk_java/UnfencedFileWrapper.java | 79 + .../javadoc/allclasses-frame.html | 68 + .../javadoc/allclasses-noframe.html | 68 + .../com/ibm/db2/wrapper/CatalogInfo.html | 348 + .../com/ibm/db2/wrapper/CatalogOption.html | 426 + .../com/ibm/db2/wrapper/ColumnInfo.html | 1311 ++ .../javadoc/com/ibm/db2/wrapper/Data.html | 879 ++ .../db2/wrapper/DefaultRemoteFunction.html | 832 ++ .../db2/wrapper/FencedGenericNickname.html | 274 + .../db2/wrapper/FencedGenericRemoteUser.html | 286 + .../ibm/db2/wrapper/FencedGenericServer.html | 328 + .../ibm/db2/wrapper/FencedGenericWrapper.html | 310 + .../com/ibm/db2/wrapper/FencedNickname.html | 221 + .../com/ibm/db2/wrapper/FencedRemoteUser.html | 235 + .../com/ibm/db2/wrapper/FencedServer.html | 313 + .../com/ibm/db2/wrapper/FencedWrapper.html | 218 + .../com/ibm/db2/wrapper/IndexInfo.html | 903 ++ .../javadoc/com/ibm/db2/wrapper/Nickname.html | 417 + .../com/ibm/db2/wrapper/NicknameInfo.html | 857 ++ .../ibm/db2/wrapper/ParsedQueryFragment.html | 398 + .../com/ibm/db2/wrapper/PredicateList.html | 305 + .../com/ibm/db2/wrapper/Quantifier.html | 260 + .../com/ibm/db2/wrapper/RFuncParmInfo.html | 372 + .../com/ibm/db2/wrapper/RemoteConnection.html | 642 + .../ibm/db2/wrapper/RemoteFunctionInfo.html | 1000 ++ .../com/ibm/db2/wrapper/RemoteOperation.html | 375 + .../com/ibm/db2/wrapper/RemotePassthru.html | 456 + .../com/ibm/db2/wrapper/RemoteQuery.html | 1032 ++ .../com/ibm/db2/wrapper/RemoteUser.html | 408 + .../javadoc/com/ibm/db2/wrapper/Reply.html | 692 ++ .../javadoc/com/ibm/db2/wrapper/Request.html | 208 + .../com/ibm/db2/wrapper/RequestConstant.html | 432 + .../com/ibm/db2/wrapper/RequestExp.html | 582 + .../com/ibm/db2/wrapper/RequestExpType.html | 364 + .../com/ibm/db2/wrapper/RuntimeData.html | 1062 ++ .../com/ibm/db2/wrapper/RuntimeDataDesc.html | 586 + .../ibm/db2/wrapper/RuntimeDataDescList.html | 299 + .../com/ibm/db2/wrapper/RuntimeDataList.html | 253 + .../javadoc/com/ibm/db2/wrapper/Server.html | 461 + .../com/ibm/db2/wrapper/ServerInfo.html | 833 ++ .../db2/wrapper/UnfencedGenericNickname.html | 281 + .../wrapper/UnfencedGenericRemoteUser.html | 294 + .../db2/wrapper/UnfencedGenericServer.html | 406 + .../db2/wrapper/UnfencedGenericWrapper.html | 314 + .../com/ibm/db2/wrapper/UnfencedNickname.html | 271 + .../ibm/db2/wrapper/UnfencedRemoteUser.html | 308 + .../com/ibm/db2/wrapper/UnfencedServer.html | 474 + .../com/ibm/db2/wrapper/UnfencedWrapper.html | 348 + .../javadoc/com/ibm/db2/wrapper/UserInfo.html | 429 + .../javadoc/com/ibm/db2/wrapper/Wrapper.html | 418 + .../com/ibm/db2/wrapper/WrapperException.html | 549 + .../com/ibm/db2/wrapper/WrapperInfo.html | 499 + .../com/ibm/db2/wrapper/WrapperUtilities.html | 647 + .../com/ibm/db2/wrapper/package-frame.html | 72 + .../com/ibm/db2/wrapper/package-summary.html | 490 + .../com/ibm/db2/wrapper/package-tree.html | 234 + .../javadoc/constant-values.html | 836 ++ .../wrapper_sdk_java/javadoc/help-doc.html | 209 + .../wrapper_sdk_java/javadoc/index-all.html | 2904 +++++ wrappers/wrapper_sdk_java/javadoc/index.html | 71 + .../javadoc/overview-tree.html | 238 + .../wrapper_sdk_java/javadoc/package-list | 1 + .../javadoc/resources/background.gif | Bin 0 -> 2313 bytes .../javadoc/resources/tab.gif | Bin 0 -> 291 bytes .../javadoc/resources/titlebar.gif | Bin 0 -> 10701 bytes .../javadoc/resources/titlebar_end.gif | Bin 0 -> 849 bytes .../javadoc/serialized-form.html | 158 + .../wrapper_sdk_java/javadoc/stylesheet.css | 481 + xml/README | 294 + xml/addr.xsd | 15 + xml/c/README | 397 + xml/c/bldapp | 111 + xml/c/bldrtn | 111 + xml/c/embprep | 63 + xml/c/impexpxml.sqc | 493 + xml/c/lobstoxml.sqc | 482 + xml/c/makefile | 204 + xml/c/recxmldecomp.sqc | 350 + xml/c/reltoxmltype.sqc | 202 + xml/c/simple_xmlproc.exp | 1 + xml/c/simple_xmlproc.sqc | 213 + xml/c/simple_xmlproc_client.db2 | 63 + xml/c/simple_xmlproc_create.db2 | 58 + xml/c/simple_xmlproc_drop.db2 | 50 + xml/c/spcat_xml | 31 + xml/c/utilapi.c | 359 + xml/c/utilapi.h | 116 + xml/c/utilemb.h | 94 + xml/c/utilemb.sqc | 130 + xml/c/xmlcheckconstraint.sqc | 797 ++ xml/c/xmlconst.sqc | 309 + xml/c/xmldecomposition.sqc | 580 + xml/c/xmlindex.sqc | 449 + xml/c/xmlinsert.sqc | 290 + xml/c/xmlintegrate.sqc | 525 + xml/c/xmlload.sqc | 394 + xml/c/xmlread.sqc | 172 + xml/c/xmlrunstats.sqc | 276 + xml/c/xmlschema.sqc | 320 + xml/c/xmltrig.sqc | 562 + xml/c/xmludfs.sqc | 737 ++ xml/c/xmlupdel.sqc | 269 + xml/c/xmlxslt.sqc | 329 + xml/catalog.xsd | 49 + xml/cli/README | 316 + xml/cli/bldapp | 94 + xml/cli/bldrtn | 94 + xml/cli/makefile | 175 + xml/cli/reltoxmldoc.c | 355 + xml/cli/reltoxmlproc.db2 | 79 + xml/cli/simple_xmlproc.c | 659 + xml/cli/simple_xmlproc.exp | 1 + xml/cli/simple_xmlproc_client.c | 250 + xml/cli/simple_xmlproc_create.db2 | 55 + xml/cli/simple_xmlproc_drop.db2 | 36 + xml/cli/spcat_xml | 30 + xml/cli/utilcli.c | 638 + xml/cli/utilcli.h | 135 + xml/cli/xmlconst.c | 394 + xml/cli/xmlindex.c | 957 ++ xml/cli/xmlinsert.c | 798 ++ xml/cli/xmlread.c | 246 + xml/cli/xmltotable.c | 461 + xml/cli/xmludfs.c | 938 ++ xml/cli/xmlupdel.c | 708 ++ xml/cli/xsupdate.c | 406 + xml/clp/README | 283 + xml/clp/impexpxml.db2 | 89 + xml/clp/lobstoxml.db2 | 85 + xml/clp/recxmldecomp.db2 | 123 + xml/clp/reltoxmldoc.db2 | 70 + xml/clp/reltoxmlproc.db2 | 79 + xml/clp/reltoxmltype.db2 | 105 + xml/clp/simple_xmlproc.db2 | 135 + xml/clp/xmlcheckconstraint.db2 | 354 + xml/clp/xmlconst.db2 | 161 + xml/clp/xmldb2batch.db2 | 52 + xml/clp/xmldb2batch_in.sql | 16 + xml/clp/xmldb2look.db2 | 77 + xml/clp/xmldbafn.db2 | 220 + xml/clp/xmldecomposition.db2 | 241 + xml/clp/xmlindex.db2 | 169 + xml/clp/xmlindgtt.db2 | 277 + xml/clp/xmlinsert.db2 | 238 + xml/clp/xmlintegrate.db2 | 243 + xml/clp/xmlload.db2 | 154 + xml/clp/xmlmdc.db2 | 404 + xml/clp/xmlolic.db2 | 278 + xml/clp/xmlpartition.db2 | 463 + xml/clp/xmlrunstats.db2 | 109 + xml/clp/xmlschema.db2 | 125 + xml/clp/xmltotable.db2 | 204 + xml/clp/xmltrig.db2 | 264 + xml/clp/xmludfs.db2 | 474 + xml/clp/xmlupdel.db2 | 189 + xml/clp/xmlxslt.db2 | 225 + xml/clp/xrpart.db2 | 568 + xml/clp/xsupdate.db2 | 189 + xml/customer.xsd | 47 + xml/data/bookdetail.xml | 36 + xml/data/bookdetail.xsd | 88 + xml/data/bookdetails.xml | 30 + xml/data/bookdetails.xsd | 115 + xml/data/booksreturned.del | 3 + xml/data/booksreturned.xsd | 42 + xml/data/booksreturned1.xml | 16 + xml/data/booksreturned2.xml | 17 + xml/data/booksreturned3.xml | 17 + xml/data/boots.xsd | 21 + xml/data/cleanupfordecomposition.db2 | 56 + xml/data/cleanupscript.db2 | 47 + xml/data/cust1021.xml | 1 + xml/data/cust1022.xml | 1 + xml/data/cust1023.xml | 1 + xml/data/customer.xsd | 15 + xml/data/header.xsd | 15 + xml/data/loaddata1.del | 4 + xml/data/loaddata2.del | 6 + xml/data/loadfile1.xml | 1 + xml/data/loadfile2.xml | 1 + xml/data/musicplayer.xsd | 24 + xml/data/newprod.xsd | 23 + xml/data/order.xml | 27 + xml/data/order.xsd | 35 + xml/data/prod.xsd | 22 + xml/data/product.xsd | 15 + xml/data/purchaseorder.xml | 43 + xml/data/recemp.xml | 27 + xml/data/recemp.xsd | 26 + xml/data/setupfordecomposition.db2 | 149 + xml/data/setupscript.db2 | 120 + xml/data/xmldata.del | 4 + xml/data/xmlfiles.001.xml | 1 + xml/history.xsd | 14 + xml/java/jdbc/README | 408 + xml/java/jdbc/RecXmlDecomp.java | 275 + xml/java/jdbc/RelToXmlDoc.java | 287 + xml/java/jdbc/RelToXmlType.java | 242 + xml/java/jdbc/Simple_XmlProc.java | 198 + xml/java/jdbc/Simple_XmlProc_Client.java | 245 + xml/java/jdbc/Simple_XmlProc_Create.db2 | 47 + xml/java/jdbc/Simple_XmlProc_Drop.db2 | 36 + xml/java/jdbc/Util.java | 340 + xml/java/jdbc/XmlCheckConstraint.java | 793 ++ xml/java/jdbc/XmlConst.java | 467 + xml/java/jdbc/XmlDecomposition.java | 475 + xml/java/jdbc/XmlIndex.java | 643 + xml/java/jdbc/XmlInsert.java | 906 ++ xml/java/jdbc/XmlMdc.java | 768 ++ xml/java/jdbc/XmlRead.java | 356 + xml/java/jdbc/XmlRunstats.java | 205 + xml/java/jdbc/XmlSchema.java | 308 + xml/java/jdbc/XmlToTable.java | 336 + xml/java/jdbc/XmlTrig.java | 566 + xml/java/jdbc/XmlUdfs.java | 795 ++ xml/java/jdbc/XmlUpDel.java | 888 ++ xml/java/jdbc/XsUpdate.java | 310 + xml/java/jdbc/makefile | 204 + xml/java/jdbc/reltoxmlproc.db2 | 79 + xml/java/jdbc/spcat_xml | 31 + xml/java/sqlj/README | 463 + xml/java/sqlj/RelToXmlDoc.sqlj | 318 + xml/java/sqlj/RelToXmlScrpt | 30 + xml/java/sqlj/RelToXmlType.sqlj | 240 + xml/java/sqlj/Util.sqlj | 319 + xml/java/sqlj/XmlConst.sqlj | 448 + xml/java/sqlj/XmlIndex.sqlj | 708 ++ xml/java/sqlj/XmlInsert.sqlj | 939 ++ xml/java/sqlj/XmlInsertScrpt | 30 + xml/java/sqlj/XmlInsert_cleanup.db2 | 49 + xml/java/sqlj/XmlInsert_setup.db2 | 54 + xml/java/sqlj/XmlIntegrate.sqlj | 549 + xml/java/sqlj/XmlIntegrateScrpt | 30 + xml/java/sqlj/XmlIntegrate_cleanup.db2 | 51 + xml/java/sqlj/XmlIntegrate_setup.db2 | 65 + xml/java/sqlj/XmlRead.sqlj | 246 + xml/java/sqlj/XmlSchema.sqlj | 263 + xml/java/sqlj/XmlToTable.sqlj | 347 + xml/java/sqlj/XmlToTableScrpt | 30 + xml/java/sqlj/XmlToTable_cleanup.db2 | 49 + xml/java/sqlj/XmlToTable_setup.db2 | 50 + xml/java/sqlj/XmlUpDel.sqlj | 860 ++ xml/java/sqlj/XmlUpDelScrpt | 30 + xml/java/sqlj/XmlUpDel_cleanup.db2 | 49 + xml/java/sqlj/XmlUpDel_setup.db2 | 54 + xml/java/sqlj/XmlXslt.sqlj | 350 + xml/java/sqlj/XmlXsltScrpt | 30 + xml/java/sqlj/XmlXslt_cleanup.db2 | 51 + xml/java/sqlj/XmlXslt_setup.db2 | 59 + xml/java/sqlj/bldsqlj | 90 + xml/java/sqlj/makefile | 157 + xml/java/sqlj/reltoxmlproc.db2 | 81 + xml/java/sqlj/reltoxmlprocScrpt | 30 + xml/java/sqlj/reltoxmlprocdrop.db2 | 49 + xml/porder.xsd | 22 + xml/product.xsd | 31 + xml/supplier.xsd | 23 + xml/xquery/README | 206 + xml/xquery/c/bldapp | 111 + xml/xquery/c/bldrtn | 111 + xml/xquery/c/client_xquery_xmlproc.sqc | 179 + xml/xquery/c/embprep | 63 + xml/xquery/c/flwor.sqc | 330 + xml/xquery/c/makefile | 168 + xml/xquery/c/spcat_xquery | 30 + xml/xquery/c/sqlxquery.sqc | 306 + xml/xquery/c/utilapi.c | 359 + xml/xquery/c/utilapi.h | 116 + xml/xquery/c/utilemb.h | 94 + xml/xquery/c/utilemb.sqc | 130 + xml/xquery/c/xpath.sqc | 342 + xml/xquery/c/xquery.sqc | 425 + xml/xquery/c/xquery_xmlproc.exp | 1 + xml/xquery/c/xquery_xmlproc.sqc | 280 + xml/xquery/c/xquery_xmlproc_create.db2 | 53 + xml/xquery/c/xquery_xmlproc_drop.db2 | 49 + xml/xquery/c/xqueryparam.sqc | 338 + xml/xquery/c/xupdate.sqc | 427 + xml/xquery/cli/bldapp | 94 + xml/xquery/cli/bldrtn | 94 + xml/xquery/cli/flwor.c | 458 + xml/xquery/cli/makefile | 161 + xml/xquery/cli/spcat_xquery | 31 + xml/xquery/cli/sqlxquery.c | 369 + xml/xquery/cli/utilcli.c | 638 + xml/xquery/cli/utilcli.h | 135 + xml/xquery/cli/xpath.c | 430 + xml/xquery/cli/xquery.c | 480 + xml/xquery/cli/xquery_xmlproc.c | 859 ++ xml/xquery/cli/xquery_xmlproc.exp | 1 + xml/xquery/cli/xquery_xmlproc_client.c | 226 + xml/xquery/cli/xquery_xmlproc_create.db2 | 55 + xml/xquery/cli/xquery_xmlproc_drop.db2 | 35 + xml/xquery/clp/flwor.db2 | 113 + xml/xquery/clp/sqlxquery.db2 | 89 + xml/xquery/clp/xpath.db2 | 93 + xml/xquery/clp/xquery.db2 | 199 + xml/xquery/clp/xquery_explain.db2 | 124 + xml/xquery/clp/xquery_xmlproc.db2 | 246 + xml/xquery/clp/xqueryparam.db2 | 193 + xml/xquery/clp/xupdate.db2 | 275 + xml/xquery/java/jdbc/Flwor.java | 397 + xml/xquery/java/jdbc/SqlXQuery.java | 378 + xml/xquery/java/jdbc/XPath.java | 400 + xml/xquery/java/jdbc/XQuery.java | 412 + xml/xquery/java/jdbc/XQueryParam.java | 435 + xml/xquery/java/jdbc/XUpdate.java | 483 + xml/xquery/java/jdbc/Xquery_XmlProc.java | 292 + .../java/jdbc/Xquery_XmlProc_Client.java | 204 + .../java/jdbc/Xquery_XmlProc_Create.db2 | 47 + xml/xquery/java/jdbc/Xquery_XmlProc_Drop.db2 | 38 + xml/xquery/java/jdbc/makefile | 171 + xml/xquery/java/jdbc/spcat_xquery | 31 + xml/xquery/java/sqlj/Flwor.sqlj | 403 + xml/xquery/java/sqlj/SqlXQuery.sqlj | 343 + xml/xquery/java/sqlj/XPath.sqlj | 416 + xml/xquery/java/sqlj/XQuery.sqlj | 435 + xml/xquery/java/sqlj/bldsqlj | 90 + xml/xquery/java/sqlj/makefile | 116 + 1582 files changed, 472996 insertions(+) create mode 100644 BARVendor/ACS_scripts/acs_ibmstor.sh create mode 100644 BARVendor/ACS_scripts/dm-1310acs_lvm.sh create mode 100644 BARVendor/ACS_scripts/dm-1311acs_gpfs.sh create mode 100644 BARVendor/README create mode 100644 BARVendor/custom.h create mode 100755 BARVendor/libacssc.sh create mode 100644 BARVendor/policy.h create mode 100644 BARVendor/vendor.C create mode 100644 BARVendor/xbsa.h create mode 100644 admin_scripts/README create mode 100644 admin_scripts/admincmd_tbload.db2 create mode 100644 admin_scripts/alterpartition.db2 create mode 100644 admin_scripts/audit.db2 create mode 100644 admin_scripts/autocfg.db2 create mode 100644 admin_scripts/autodb.db2 create mode 100644 admin_scripts/autonomous_transaction.db2 create mode 100644 admin_scripts/autorestore.db2 create mode 100644 admin_scripts/autostore.db2 create mode 100644 admin_scripts/cgtt.db2 create mode 100644 admin_scripts/checkv9limits.db2 create mode 100644 admin_scripts/contacts.db2 create mode 100644 admin_scripts/databaseroles.db2 create mode 100644 admin_scripts/fasterrollout.db2 create mode 100644 admin_scripts/gethealthconfig.db2 create mode 100644 admin_scripts/getlogs.db2 create mode 100644 admin_scripts/globvarsupport.db2 create mode 100644 admin_scripts/healthmon.db2 create mode 100755 admin_scripts/ingest_files.sh create mode 100644 admin_scripts/largerid.db2 create mode 100644 admin_scripts/lbac.db2 create mode 100644 admin_scripts/monitor.db2 create mode 100644 admin_scripts/onlineload.db2 create mode 100644 admin_scripts/partitionindex.db2 create mode 100644 admin_scripts/public_alias.db2 create mode 100644 admin_scripts/redistribute_cmd.db2 create mode 100644 admin_scripts/rollindata.db2 create mode 100644 admin_scripts/rolloutdata.db2 create mode 100644 admin_scripts/sec_rcac.db2 create mode 100644 admin_scripts/security.db2 create mode 100644 admin_scripts/setintegrity.db2 create mode 100644 admin_scripts/ssv_backup_db.db2 create mode 100644 admin_scripts/ssv_backup_tbsp.db2 create mode 100644 admin_scripts/ssv_db_cfg.db2 create mode 100644 admin_scripts/tablepartition.db2 create mode 100644 admin_scripts/tbeventmon.db2 create mode 100644 admin_scripts/tbonlineinx.db2 create mode 100644 admin_scripts/tbrowcompress.db2 create mode 100644 admin_scripts/tbrunstats.db2 create mode 100644 admin_scripts/tbsreduce.db2 create mode 100644 admin_scripts/wlmtiersdefault.db2 create mode 100644 admin_scripts/wlmtiersdrop.db2 create mode 100644 admin_scripts/wlmtierstimerons.db2 create mode 100644 autoloader/loadFtpFtc.pl create mode 100644 automaintcfg/DB2AutoBackupPolicySample.xml create mode 100644 automaintcfg/DB2AutoReorgPolicySample.xml create mode 100644 automaintcfg/DB2AutoRunstatsPolicySample.xml create mode 100644 automaintcfg/DB2MaintenanceWindowPolicySample.xml create mode 100644 c/README create mode 100644 c/autostore.c create mode 100755 c/bldapp create mode 100755 c/bldmc create mode 100755 c/bldmt create mode 100755 c/bldrtn create mode 100644 c/cli_info.c create mode 100644 c/clisnap.c create mode 100644 c/clisnapnew.c create mode 100644 c/db2uext2.cdisk create mode 100644 c/db2uext2.ctape create mode 100644 c/db2uext2.ctsm create mode 100644 c/dbauth.sqc create mode 100644 c/dbcfg.sqc create mode 100644 c/dbconn.sqc create mode 100644 c/dbcreate.c create mode 100644 c/dbhistfile.sqc create mode 100644 c/dbinfo.c create mode 100644 c/dbinline.sqc create mode 100644 c/dbinspec.sqc create mode 100644 c/dblogconn.sqc create mode 100644 c/dblognoconn.sqc create mode 100644 c/dblognoconnlogmerge.c create mode 100644 c/dbmcon.sqc create mode 100644 c/dbmcon1.h create mode 100644 c/dbmcon1.sqc create mode 100644 c/dbmcon2.h create mode 100644 c/dbmcon2.sqc create mode 100644 c/dbpkg.sqc create mode 100644 c/dbrecov.sqc create mode 100644 c/dbredirect.sqc create mode 100644 c/dbrestore.sqc create mode 100644 c/dbrollfwd.sqc create mode 100644 c/dbsample.sqc create mode 100644 c/dbsnap.c create mode 100644 c/dbsnapnew.c create mode 100644 c/dbstat.c create mode 100644 c/dbthrds.sqc create mode 100644 c/dbupgrade.c create mode 100644 c/dbuse.sqc create mode 100644 c/dtformat.sqc create mode 100644 c/dtlob.sqc create mode 100644 c/dtudt.sqc create mode 100755 c/embprep create mode 100644 c/evm.sqc create mode 100644 c/fnuse.sqc create mode 100644 c/getlogs.sqc create mode 100644 c/getmessage.sqc create mode 100644 c/globvarsupport.sqc create mode 100644 c/implicitcasting.sqc create mode 100644 c/inattach.c create mode 100644 c/inauth.sqc create mode 100644 c/ininfo.c create mode 100644 c/insnap.c create mode 100644 c/insnapnew.c create mode 100644 c/instart.c create mode 100644 c/largerid.sqc create mode 100755 c/makefile create mode 100644 c/setintegrity.sqc create mode 100755 c/spcat create mode 100644 c/spclient.sqc create mode 100644 c/spcreate.db2 create mode 100644 c/spcreate_gv.db2 create mode 100644 c/spdrop.db2 create mode 100644 c/spserver.exp create mode 100644 c/spserver.sqc create mode 100644 c/ssv_backup_db.c create mode 100644 c/ssv_backup_tbsp.sqc create mode 100644 c/ssv_db_cfg.c create mode 100644 c/tbast.sqc create mode 100644 c/tbcompress.sqc create mode 100644 c/tbconstr.sqc create mode 100644 c/tbcreate.sqc create mode 100644 c/tbident.sqc create mode 100644 c/tbinfo.sqc create mode 100644 c/tbintrig.sqc create mode 100644 c/tbload.sqc create mode 100644 c/tbloadcursor.sqc create mode 100644 c/tbmerge.sqc create mode 100644 c/tbmod.sqc create mode 100644 c/tbmove.sqc create mode 100644 c/tbonlineinx.sqc create mode 100644 c/tbpriv.sqc create mode 100644 c/tbread.sqc create mode 100644 c/tbreorg.sqc create mode 100644 c/tbrowcompress.sqc create mode 100644 c/tbrunstats.sqc create mode 100644 c/tbsavept.sqc create mode 100644 c/tbsel.sqc create mode 100644 c/tbselcreate.db2 create mode 100644 c/tbseldrop.db2 create mode 100755 c/tbselinit create mode 100644 c/tbtemp.sqc create mode 100644 c/tbtrig.sqc create mode 100644 c/tbumqt.sqc create mode 100644 c/tbunion.sqc create mode 100644 c/tscreate.sqc create mode 100644 c/udfcli.sqc create mode 100644 c/udfemcli.sqc create mode 100644 c/udfemsrv.exp create mode 100644 c/udfemsrv.sqc create mode 100644 c/udfsrv.c create mode 100644 c/udfsrv.exp create mode 100644 c/utilapi.c create mode 100644 c/utilapi.h create mode 100644 c/utilemb.h create mode 100644 c/utilemb.sqc create mode 100644 c/utilrecov.c create mode 100644 c/utilsnap.c create mode 100755 cli/README create mode 100644 cli/admincmd_autoconfigure.c create mode 100644 cli/admincmd_contacts.c create mode 100644 cli/admincmd_describe.c create mode 100644 cli/admincmd_export.c create mode 100644 cli/admincmd_import.c create mode 100644 cli/admincmd_onlinebackup.c create mode 100644 cli/admincmd_quiesce.c create mode 100644 cli/admincmd_updateconfig.c create mode 100755 cli/bldapp create mode 100755 cli/bldmc create mode 100755 cli/bldrtn create mode 100644 cli/cli_info.c create mode 100644 cli/clihandl.c create mode 100644 cli/clisqlca.c create mode 100644 cli/dbcongui.c create mode 100644 cli/dbconn.c create mode 100644 cli/dbinfo.c create mode 100644 cli/dbmcon.c create mode 100644 cli/dbmconx.c create mode 100644 cli/dbmconx1.h create mode 100644 cli/dbmconx1.sqc create mode 100644 cli/dbmconx2.h create mode 100644 cli/dbmconx2.sqc create mode 100644 cli/dbnative.c create mode 100644 cli/dbuse.c create mode 100644 cli/dbusemx.sqc create mode 100644 cli/dbxamon.c create mode 100644 cli/dbxamon.ini create mode 100644 cli/dtinfo.c create mode 100644 cli/dtlob.c create mode 100644 cli/dtudt.c create mode 100755 cli/embprep create mode 100644 cli/getdbcfgparams.c create mode 100644 cli/getdbmcfgparams.c create mode 100644 cli/getmessage.c create mode 100644 cli/ilinfo.c create mode 100644 cli/ininfo.c create mode 100755 cli/makefile create mode 100644 cli/spcall.c create mode 100755 cli/spcat create mode 100644 cli/spclient.c create mode 100644 cli/spclires.c create mode 100644 cli/spcreate.db2 create mode 100644 cli/spdrop.db2 create mode 100644 cli/spserver.c create mode 100644 cli/spserver.exp create mode 100644 cli/ssv_db_cfg.c create mode 100644 cli/tbast.c create mode 100644 cli/tbcompress.c create mode 100644 cli/tbconstr.c create mode 100644 cli/tbcreate.c create mode 100644 cli/tbinfo.c create mode 100644 cli/tbload.c create mode 100644 cli/tbmod.c create mode 100644 cli/tbonlineinx.c create mode 100644 cli/tbread.c create mode 100644 cli/tbrunstats.c create mode 100644 cli/tbtemp.c create mode 100644 cli/tbumqt.c create mode 100644 cli/trustedcontext.c create mode 100644 cli/udfcli.c create mode 100644 cli/udfsrv.c create mode 100644 cli/udfsrv.exp create mode 100644 cli/utilcli.c create mode 100644 cli/utilcli.h create mode 100644 clp/README create mode 100644 clp/const.db2 create mode 100644 clp/cte.db2 create mode 100644 clp/datecompat.db2 create mode 100644 clp/flt.db2 create mode 100644 clp/implicitcasting.db2 create mode 100644 clp/join.db2 create mode 100644 clp/scalarfunction.db2 create mode 100644 clp/stock.db2 create mode 100644 clp/tablestatesize.db2 create mode 100644 clp/tbast.db2 create mode 100644 clp/tbcompress.db2 create mode 100644 clp/tbconstr.db2 create mode 100644 clp/tbread.db2 create mode 100644 clp/tbtemp.db2 create mode 100644 clp/tbumqt.db2 create mode 100644 clp/temporal_att.db2 create mode 100644 clp/temporal_btt.db2 create mode 100644 clp/temporal_revert.db2 create mode 100644 clp/temporal_stt.db2 create mode 100644 clp/testdata.db2 create mode 100644 clp/tsinfo.db2 create mode 100644 cobol_mf/README create mode 100644 cobol_mf/advsql.sqb create mode 100755 cobol_mf/bldapp create mode 100755 cobol_mf/bldrtn create mode 100644 cobol_mf/checkerr.cbl create mode 100644 cobol_mf/client.cbl create mode 100644 cobol_mf/cursor.sqb create mode 100644 cobol_mf/d_dbconf.cbl create mode 100644 cobol_mf/d_dbmcon.cbl create mode 100644 cobol_mf/db_udcs.cbl create mode 100644 cobol_mf/dbauth.sqb create mode 100644 cobol_mf/dbcat.cbl create mode 100644 cobol_mf/dbcmt.cbl create mode 100644 cobol_mf/dbconf.cbl create mode 100644 cobol_mf/dbinst.cbl create mode 100644 cobol_mf/dbmconf.cbl create mode 100755 cobol_mf/dbsnap.cbl create mode 100644 cobol_mf/dbstart.cbl create mode 100644 cobol_mf/dbstat.sqb create mode 100644 cobol_mf/dbstop.cbl create mode 100644 cobol_mf/dbupgrade.cbl create mode 100644 cobol_mf/dcscat.cbl create mode 100644 cobol_mf/delet.sqb create mode 100644 cobol_mf/dynamic.sqb create mode 100644 cobol_mf/ebcdicdb.cbl create mode 100755 cobol_mf/embprep create mode 100644 cobol_mf/expsamp.sqb create mode 100644 cobol_mf/impexp.sqb create mode 100644 cobol_mf/inpcli.sqb create mode 100644 cobol_mf/inpsrv.sqb create mode 100644 cobol_mf/joinsql.sqb create mode 100644 cobol_mf/loadqry.sqb create mode 100644 cobol_mf/lobeval.sqb create mode 100644 cobol_mf/lobfile.sqb create mode 100644 cobol_mf/lobloc.sqb create mode 100644 cobol_mf/makefile create mode 100644 cobol_mf/monreset.cbl create mode 100644 cobol_mf/monsz.cbl create mode 100644 cobol_mf/nodecat.cbl create mode 100644 cobol_mf/openftch.sqb create mode 100644 cobol_mf/outcli.sqb create mode 100644 cobol_mf/outsrv.sqb create mode 100644 cobol_mf/prepbind.sqb create mode 100644 cobol_mf/qload.sqb create mode 100644 cobol_mf/rebind.sqb create mode 100644 cobol_mf/restart.cbl create mode 100644 cobol_mf/setact.cbl create mode 100755 cobol_mf/spcat create mode 100644 cobol_mf/spcreate.db2 create mode 100644 cobol_mf/spdrop.db2 create mode 100644 cobol_mf/static.sqb create mode 100644 cobol_mf/sws.cbl create mode 100644 cobol_mf/tabscont.sqb create mode 100644 cobol_mf/tabspace.sqb create mode 100644 cobol_mf/tabsql.sqb create mode 100644 cobol_mf/tload.sqb create mode 100644 cobol_mf/trigsql.sqb create mode 100644 cobol_mf/tspace.sqb create mode 100644 cobol_mf/updat.sqb create mode 100644 cobol_mf/varinp.sqb create mode 100644 cpp/README create mode 100755 cpp/bldapp create mode 100755 cpp/bldmc create mode 100755 cpp/bldmt create mode 100755 cpp/bldrtn create mode 100644 cpp/cli_info.C create mode 100644 cpp/clisnap.C create mode 100644 cpp/clisnapnew.C create mode 100644 cpp/dbauth.sqC create mode 100644 cpp/dbcfg.sqC create mode 100644 cpp/dbconn.sqC create mode 100644 cpp/dbcreate.C create mode 100644 cpp/dbhistfile.sqC create mode 100644 cpp/dbinfo.C create mode 100644 cpp/dbinline.sqC create mode 100644 cpp/dbinspec.sqC create mode 100644 cpp/dblogconn.sqC create mode 100644 cpp/dblognoconn.sqC create mode 100644 cpp/dbmcon.sqC create mode 100644 cpp/dbmcon1.h create mode 100644 cpp/dbmcon1.sqC create mode 100644 cpp/dbmcon2.h create mode 100644 cpp/dbmcon2.sqC create mode 100644 cpp/dbpkg.sqC create mode 100644 cpp/dbrecov.sqC create mode 100644 cpp/dbrestore.sqC create mode 100644 cpp/dbrollfwd.sqC create mode 100644 cpp/dbsample.sqC create mode 100644 cpp/dbsnap.C create mode 100644 cpp/dbsnapnew.C create mode 100644 cpp/dbthrds.sqC create mode 100644 cpp/dbupgrade.C create mode 100644 cpp/dbuse.sqC create mode 100644 cpp/dtformat.sqC create mode 100644 cpp/dtlob.sqC create mode 100644 cpp/dtstruct.sqC create mode 100644 cpp/dtudt.sqC create mode 100755 cpp/embprep create mode 100644 cpp/evm.sqC create mode 100644 cpp/fnuse.sqC create mode 100644 cpp/inattach.C create mode 100644 cpp/inauth.sqC create mode 100644 cpp/ininfo.C create mode 100644 cpp/insnap.C create mode 100644 cpp/insnapnew.C create mode 100644 cpp/instart.C create mode 100755 cpp/makefile create mode 100755 cpp/routinecompile create mode 100755 cpp/spcat create mode 100644 cpp/spclient.sqC create mode 100644 cpp/spcreate.db2 create mode 100644 cpp/spdrop.db2 create mode 100644 cpp/spserver.exp create mode 100644 cpp/spserver.sqC create mode 100644 cpp/tbast.sqC create mode 100644 cpp/tbcompress.sqC create mode 100644 cpp/tbconstr.sqC create mode 100644 cpp/tbcreate.sqC create mode 100644 cpp/tbident.sqC create mode 100644 cpp/tbinfo.sqC create mode 100644 cpp/tbintrig.sqC create mode 100644 cpp/tbloadcursor.sqC create mode 100644 cpp/tbmerge.sqC create mode 100644 cpp/tbmod.sqC create mode 100644 cpp/tbmove.sqC create mode 100644 cpp/tbonlineinx.sqC create mode 100644 cpp/tbpriv.sqC create mode 100644 cpp/tbread.sqC create mode 100644 cpp/tbreorg.sqC create mode 100644 cpp/tbrunstats.sqC create mode 100644 cpp/tbsavept.sqC create mode 100644 cpp/tbsel.sqC create mode 100644 cpp/tbselcreate.db2 create mode 100644 cpp/tbseldrop.db2 create mode 100755 cpp/tbselinit create mode 100644 cpp/tbtemp.sqC create mode 100644 cpp/tbtrig.sqC create mode 100644 cpp/tbumqt.sqC create mode 100644 cpp/tbunion.sqC create mode 100644 cpp/tscreate.sqC create mode 100644 cpp/udfcli.sqC create mode 100644 cpp/udfemcli.sqC create mode 100644 cpp/udfemsrv.exp create mode 100644 cpp/udfemsrv.sqC create mode 100644 cpp/udfsampl.cpp create mode 100644 cpp/udfsrv.C create mode 100644 cpp/udfsrv.exp create mode 100644 cpp/udtfsampl.cpp create mode 100644 cpp/utilapi.C create mode 100644 cpp/utilapi.h create mode 100644 cpp/utilemb.h create mode 100644 cpp/utilemb.sqC create mode 100644 cpp/utilrecov.C create mode 100644 cpp/utilsnap.C create mode 100644 db2ci/README create mode 100755 db2ci/bldapp create mode 100644 db2ci/cihandl.c create mode 100644 db2ci/dbuse.c create mode 100644 db2ci/ilinfo.c create mode 100644 db2ci/makefile create mode 100755 db2ci/ocitest create mode 100644 db2ci/tbcompress.c create mode 100644 db2ci/tbcreate.c create mode 100644 db2ci/tbmod.c create mode 100644 db2ci/tbread.c create mode 100644 db2ci/utilci.c create mode 100644 db2ci/utilci.h create mode 100644 db2sampl/addr.xsd create mode 100755 db2sampl/c1.xml create mode 100755 db2sampl/c2.xml create mode 100755 db2sampl/c3.xml create mode 100755 db2sampl/c4.xml create mode 100755 db2sampl/c5.xml create mode 100644 db2sampl/c6.xml create mode 100644 db2sampl/catalog.xsd create mode 100644 db2sampl/customer.xsd create mode 100644 db2sampl/db200130.asc create mode 100644 db2sampl/db200130.bmp create mode 100644 db2sampl/db200130.gif create mode 100755 db2sampl/db200130.html create mode 100644 db2sampl/db200130.scr create mode 100644 db2sampl/db200130.xwd create mode 100644 db2sampl/db200140.asc create mode 100644 db2sampl/db200140.bmp create mode 100644 db2sampl/db200140.gif create mode 100755 db2sampl/db200140.html create mode 100644 db2sampl/db200140.scr create mode 100644 db2sampl/db200140.xwd create mode 100644 db2sampl/db200150.asc create mode 100644 db2sampl/db200150.bmp create mode 100644 db2sampl/db200150.gif create mode 100755 db2sampl/db200150.html create mode 100644 db2sampl/db200150.scr create mode 100644 db2sampl/db200150.xwd create mode 100644 db2sampl/db200190.asc create mode 100644 db2sampl/db200190.bmp create mode 100644 db2sampl/db200190.gif create mode 100755 db2sampl/db200190.html create mode 100644 db2sampl/db200190.scr create mode 100644 db2sampl/db200190.xwd create mode 100644 db2sampl/history.xsd create mode 100644 db2sampl/mdcdata.del create mode 100755 db2sampl/p1.xml create mode 100755 db2sampl/p2.xml create mode 100755 db2sampl/p3.xml create mode 100755 db2sampl/p4.xml create mode 100644 db2sampl/po1.xml create mode 100644 db2sampl/po2.xml create mode 100644 db2sampl/po3.xml create mode 100644 db2sampl/po4.xml create mode 100644 db2sampl/po5.xml create mode 100644 db2sampl/po6.xml create mode 100644 db2sampl/porder.xsd create mode 100644 db2sampl/product.xsd create mode 100644 db2sampl/supplier.xsd create mode 100644 extenders/spatial/README_spatial_samples.txt create mode 100644 extenders/spatial/bank/seBankDemoConversion.db2 create mode 100644 extenders/spatial/bank/seBankDemoDDL.db2 create mode 100644 extenders/spatial/bank/seBankDemoREADME.txt create mode 100644 extenders/spatial/bank/seBankDemoRefresh.db2 create mode 100755 extenders/spatial/bank/seBankDemoRunBankDemo create mode 100644 extenders/spatial/bank/seBankDemoSpatialSQL.db2 create mode 100644 extenders/spatial/bank/seBankDemoTableData.db2 create mode 100644 extenders/spatial/bank/seBankDemoViewDDL.db2 create mode 100644 extenders/spatial/bldDemo create mode 100644 extenders/spatial/customers.data create mode 100644 extenders/spatial/data/cityLimits.dbf create mode 100644 extenders/spatial/data/cityLimits.prj create mode 100644 extenders/spatial/data/cityLimits.shp create mode 100644 extenders/spatial/data/cityLimits.shx create mode 100644 extenders/spatial/data/floodzones.dbf create mode 100644 extenders/spatial/data/floodzones.prj create mode 100644 extenders/spatial/data/floodzones.shp create mode 100644 extenders/spatial/data/floodzones.shx create mode 100644 extenders/spatial/data/offices.dbf create mode 100644 extenders/spatial/data/offices.prj create mode 100644 extenders/spatial/data/offices.shp create mode 100644 extenders/spatial/data/offices.shx create mode 100644 extenders/spatial/data/regions.dbf create mode 100644 extenders/spatial/data/regions.prj create mode 100644 extenders/spatial/data/regions.shp create mode 100644 extenders/spatial/data/regions.shx create mode 100644 extenders/spatial/data/salezones.dbf create mode 100644 extenders/spatial/data/salezones.prj create mode 100644 extenders/spatial/data/salezones.shp create mode 100644 extenders/spatial/data/salezones.shx create mode 100644 extenders/spatial/data/sjCensusBlocks.dbf create mode 100644 extenders/spatial/data/sjCensusBlocks.prj create mode 100644 extenders/spatial/data/sjCensusBlocks.shp create mode 100644 extenders/spatial/data/sjCensusBlocks.shx create mode 100644 extenders/spatial/data/sjMainStreets.dbf create mode 100644 extenders/spatial/data/sjMainStreets.prj create mode 100644 extenders/spatial/data/sjMainStreets.shp create mode 100644 extenders/spatial/data/sjMainStreets.shx create mode 100644 extenders/spatial/data/sjZipCodes.dbf create mode 100644 extenders/spatial/data/sjZipCodes.prj create mode 100644 extenders/spatial/data/sjZipCodes.shp create mode 100644 extenders/spatial/data/sjZipCodes.shx create mode 100644 extenders/spatial/data/st_linestring.dbf create mode 100644 extenders/spatial/data/st_linestring.prj create mode 100644 extenders/spatial/data/st_linestring.shp create mode 100644 extenders/spatial/data/st_linestring.shx create mode 100644 extenders/spatial/data/st_multilinestring.dbf create mode 100644 extenders/spatial/data/st_multilinestring.prj create mode 100644 extenders/spatial/data/st_multilinestring.shp create mode 100644 extenders/spatial/data/st_multilinestring.shx create mode 100644 extenders/spatial/data/st_multipoint.dbf create mode 100644 extenders/spatial/data/st_multipoint.prj create mode 100644 extenders/spatial/data/st_multipoint.shp create mode 100644 extenders/spatial/data/st_multipoint.shx create mode 100644 extenders/spatial/data/st_multipolygon.dbf create mode 100644 extenders/spatial/data/st_multipolygon.prj create mode 100644 extenders/spatial/data/st_multipolygon.shp create mode 100644 extenders/spatial/data/st_multipolygon.shx create mode 100644 extenders/spatial/data/st_point.dbf create mode 100644 extenders/spatial/data/st_point.prj create mode 100644 extenders/spatial/data/st_point.shp create mode 100644 extenders/spatial/data/st_point.shx create mode 100644 extenders/spatial/data/st_polygon.dbf create mode 100644 extenders/spatial/data/st_polygon.prj create mode 100644 extenders/spatial/data/st_polygon.shp create mode 100644 extenders/spatial/data/st_polygon.shx create mode 100644 extenders/spatial/makefile create mode 100755 extenders/spatial/runGseDemo create mode 100644 extenders/spatial/runGseDemo.c create mode 100644 extenders/spatial/samputil.c create mode 100644 extenders/spatial/samputil.h create mode 100644 federated/drdalbacfun.clp create mode 100644 federated/net8olsfun.clp create mode 100644 federated/selective_view/README create mode 100644 federated/selective_view/selective_view.txt create mode 100644 federated/selective_view/selective_view_prep.db2 create mode 100644 federated/selective_view/selective_view_procs.db2 create mode 100644 federated/umplugin/file/README create mode 100755 federated/umplugin/file/fsumlookup create mode 100644 federated/umplugin/file/fsumplugin_file.c create mode 100644 federated/umplugin/file/fsumplugin_file.h create mode 100644 federated/umplugin/file/fsumplugin_file.txt create mode 100755 federated/umplugin/file/fsumsetup_file create mode 100644 federated/umplugin/file/fsumsetup_file.c create mode 100644 federated/umplugin/ldap/README.txt create mode 100644 federated/umplugin/ldap/UserMappingCryptoLDAP.java create mode 100644 federated/umplugin/ldap/UserMappingLookupLDAP.java create mode 100644 federated/umplugin/ldap/UserMappingRepositoryLDAP.java create mode 100644 federated/umplugin/ldap/UserMappingSetupLDAP.java create mode 100644 federated/umplugin/ldap/entry.ldif create mode 100644 federated/umplugin/ldap/schema.ldif create mode 100644 ha/xml/db2ha.xsd create mode 100644 ha/xml/db2ha_sample_DPF_NPlusM.xml create mode 100644 ha/xml/db2ha_sample_DPF_mutual.xml create mode 100644 ha/xml/db2ha_sample_HADR.xml create mode 100644 ha/xml/db2ha_sample_sharedstorage_mutual.xml create mode 100644 java/Websphere/AIRLINE.war create mode 100644 java/Websphere/AccessEmployee.ear create mode 100644 java/Websphere/OptimisticLocking.war create mode 100644 java/Websphere/README create mode 100644 java/Websphere/airline.db2 create mode 100644 java/jdbc/AdmCmdAutoCfg.java create mode 100644 java/jdbc/AdmCmdContacts.java create mode 100644 java/jdbc/AdmCmdDescribe.java create mode 100644 java/jdbc/AdmCmdExport.java create mode 100644 java/jdbc/AdmCmdImport.java create mode 100644 java/jdbc/AdmCmdOnlineBackup.java create mode 100644 java/jdbc/AdmCmdQuiesce.java create mode 100644 java/jdbc/AdmCmdUpdateCfg.java create mode 100644 java/jdbc/Applt.html create mode 100644 java/jdbc/Applt.java create mode 100644 java/jdbc/Array_Stack.java create mode 100644 java/jdbc/Arrays_Sqlpl.java create mode 100644 java/jdbc/Cgtt.java create mode 100644 java/jdbc/CreateCGTT.db2 create mode 100644 java/jdbc/CreateEmployee.java create mode 100644 java/jdbc/CreateGTF.db2 create mode 100755 java/jdbc/DB2EvmonChangeHistory.xsl create mode 100755 java/jdbc/DB2EvmonLocking.xsl create mode 100755 java/jdbc/DB2EvmonPkgCache.xsl create mode 100755 java/jdbc/DB2EvmonUOW.xsl create mode 100755 java/jdbc/DB2LockReportHTML.xsl create mode 100644 java/jdbc/DbAuth.java create mode 100644 java/jdbc/DbConn.java create mode 100644 java/jdbc/DbInfo.java create mode 100644 java/jdbc/DbMCon.java create mode 100644 java/jdbc/DbNative.java create mode 100644 java/jdbc/DbRsHold.java create mode 100644 java/jdbc/DbSeq.java create mode 100644 java/jdbc/DbUse.java create mode 100644 java/jdbc/DropCGTT.db2 create mode 100644 java/jdbc/DropGTF.db2 create mode 100644 java/jdbc/DtInfo.java create mode 100644 java/jdbc/DtLob.java create mode 100644 java/jdbc/DtUdt.java create mode 100644 java/jdbc/GTFqueries.db2 create mode 100644 java/jdbc/GeneratePayroll.java create mode 100644 java/jdbc/GetDBCfgParams.java create mode 100644 java/jdbc/GetDBMCfgParams.java create mode 100644 java/jdbc/GetLogs.java create mode 100644 java/jdbc/GetMessage.java create mode 100644 java/jdbc/IlInfo.java create mode 100644 java/jdbc/ImplicitCasting.java create mode 100644 java/jdbc/JCCKerberosPlugin.java create mode 100644 java/jdbc/JCCKerberosPluginTest.java create mode 100644 java/jdbc/JCCSimpleGSSContext.java create mode 100644 java/jdbc/JCCSimpleGSSCredential.java create mode 100644 java/jdbc/JCCSimpleGSSException.java create mode 100644 java/jdbc/JCCSimpleGSSName.java create mode 100644 java/jdbc/JCCSimpleGSSPlugin.java create mode 100644 java/jdbc/JCCSimpleGSSPluginTest.java create mode 100644 java/jdbc/LargeRid.java create mode 100644 java/jdbc/README create mode 100644 java/jdbc/ScalarFunctions.java create mode 100644 java/jdbc/SetIntegrity.java create mode 100644 java/jdbc/SpClient.java create mode 100644 java/jdbc/SpCreate.db2 create mode 100644 java/jdbc/SpDrop.db2 create mode 100644 java/jdbc/SpServer.java create mode 100644 java/jdbc/TbAST.java create mode 100644 java/jdbc/TbCompress.java create mode 100644 java/jdbc/TbConstr.java create mode 100644 java/jdbc/TbCreate.java create mode 100644 java/jdbc/TbGenCol.java create mode 100644 java/jdbc/TbIdent.java create mode 100644 java/jdbc/TbInTrig.java create mode 100644 java/jdbc/TbInfo.java create mode 100644 java/jdbc/TbMerge.java create mode 100644 java/jdbc/TbMod.java create mode 100644 java/jdbc/TbOnlineInx.java create mode 100644 java/jdbc/TbPriv.java create mode 100644 java/jdbc/TbRead.java create mode 100644 java/jdbc/TbRowcompress.java create mode 100644 java/jdbc/TbRunstats.java create mode 100644 java/jdbc/TbSel.java create mode 100644 java/jdbc/TbTemp.java create mode 100644 java/jdbc/TbTrig.java create mode 100644 java/jdbc/TbUMQT.java create mode 100644 java/jdbc/TbUnion.java create mode 100644 java/jdbc/Temporal.java create mode 100644 java/jdbc/TrustedContext.java create mode 100644 java/jdbc/UDFCreate.db2 create mode 100644 java/jdbc/UDFDrop.db2 create mode 100644 java/jdbc/UDFcli.java create mode 100644 java/jdbc/UDFcsvReader.java create mode 100644 java/jdbc/UDFjCreate.db2 create mode 100644 java/jdbc/UDFjDrop.db2 create mode 100644 java/jdbc/UDFjcli.java create mode 100644 java/jdbc/UDFjsrv.java create mode 100644 java/jdbc/UDFsCreate.db2 create mode 100644 java/jdbc/UDFsDrop.db2 create mode 100644 java/jdbc/UDFsqlcl.java create mode 100644 java/jdbc/UDFsqlsv.java create mode 100644 java/jdbc/UDFsrv.java create mode 100644 java/jdbc/Util.java create mode 100644 java/jdbc/bonus_calculate.db2 create mode 100755 java/jdbc/db2evmonfmt.java create mode 100644 java/jdbc/makefile create mode 100644 java/jdbc/sample.csv create mode 100755 java/jdbc/spcat create mode 100644 java/jdbc/stack_functions.db2 create mode 100755 java/jdbc/udfcat create mode 100755 java/jdbc/udfjcat create mode 100644 java/sqlj/Applt.html create mode 100644 java/sqlj/Applt.sqlj create mode 100644 java/sqlj/Batch1Demo.sqlj create mode 100644 java/sqlj/Batch2Demo.sqlj create mode 100644 java/sqlj/Batch3Demo.sqlj create mode 100644 java/sqlj/BlobClobDemo.sqlj create mode 100644 java/sqlj/CreateDemoSchema.sqlj create mode 100644 java/sqlj/CreateEmployee.sqlj create mode 100644 java/sqlj/DS1.prop create mode 100644 java/sqlj/DS2.prop create mode 100644 java/sqlj/DS3.prop create mode 100644 java/sqlj/DbAuth.sqlj create mode 100644 java/sqlj/DbConMDataSources.sqlj create mode 100644 java/sqlj/DbConn.sqlj create mode 100644 java/sqlj/DbConnDataSource.sqlj create mode 100644 java/sqlj/DbMCon.sqlj create mode 100644 java/sqlj/DbUse.sqlj create mode 100644 java/sqlj/DtUdt.sqlj create mode 100644 java/sqlj/GeneratePayroll.sqlj create mode 100644 java/sqlj/LargeRid.sqlj create mode 100644 java/sqlj/LargeRidScrpt create mode 100644 java/sqlj/LargeRid_cleanup.db2 create mode 100644 java/sqlj/LargeRid_setup.db2 create mode 100644 java/sqlj/README create mode 100644 java/sqlj/ScrollIterDemo.sqlj create mode 100644 java/sqlj/SetIntegrity.sqlj create mode 100644 java/sqlj/SetIntegrityScrpt create mode 100644 java/sqlj/SetIntegrity_cleanup.db2 create mode 100644 java/sqlj/SetIntegrity_setup.db2 create mode 100644 java/sqlj/SpClient.sqlj create mode 100644 java/sqlj/SpCreate.db2 create mode 100644 java/sqlj/SpDrop.db2 create mode 100644 java/sqlj/SpIterat.sqlj create mode 100644 java/sqlj/SpServer.sqlj create mode 100644 java/sqlj/TbAST.sqlj create mode 100644 java/sqlj/TbASTScrpt create mode 100644 java/sqlj/TbAST_cleanup.db2 create mode 100644 java/sqlj/TbAST_setup.db2 create mode 100644 java/sqlj/TbCompress.sqlj create mode 100644 java/sqlj/TbConstr.sqlj create mode 100644 java/sqlj/TbCreate.sqlj create mode 100644 java/sqlj/TbIdent.sqlj create mode 100644 java/sqlj/TbInfo.sqlj create mode 100644 java/sqlj/TbMod.sqlj create mode 100644 java/sqlj/TbOnlineInx.sqlj create mode 100644 java/sqlj/TbPriv.sqlj create mode 100644 java/sqlj/TbRead.sqlj create mode 100644 java/sqlj/TbRowcompress.sqlj create mode 100644 java/sqlj/TbRowcompressScrpt create mode 100644 java/sqlj/TbRowcompress_cleanup.db2 create mode 100644 java/sqlj/TbRowcompress_setup.db2 create mode 100644 java/sqlj/TbRunstats.sqlj create mode 100644 java/sqlj/TbSel.sqlj create mode 100644 java/sqlj/TbTemp.sqlj create mode 100644 java/sqlj/TbTrig.sqlj create mode 100644 java/sqlj/TbUMQT.sqlj create mode 100644 java/sqlj/UDFCreate.db2 create mode 100644 java/sqlj/UDFDrop.db2 create mode 100644 java/sqlj/UDFcli.sqlj create mode 100644 java/sqlj/UDFjCreate.db2 create mode 100644 java/sqlj/UDFjDrop.db2 create mode 100644 java/sqlj/UDFjcli.sqlj create mode 100644 java/sqlj/UDFjsrv.java create mode 100644 java/sqlj/UDFsrv.java create mode 100644 java/sqlj/Util.sqlj create mode 100644 java/sqlj/bldsqlj create mode 100644 java/sqlj/bldsqljds create mode 100644 java/sqlj/bldsqljs create mode 100644 java/sqlj/createRegisterDS.java create mode 100644 java/sqlj/jndi.properties create mode 100644 java/sqlj/makefile create mode 100755 java/sqlj/spcat create mode 100755 java/sqlj/udfcat create mode 100755 java/sqlj/udfjcat create mode 100644 lifesci/SCRIPT_DAEMON.config create mode 100644 lifesci/biors/create_function_mappings.ddl create mode 100644 lifesci/script/create_function_mappings.ddl create mode 100755 pd/db2_hang_analyze create mode 100755 pd/db2_hang_detect create mode 100755 perf/db2mon.sh create mode 100644 perf/db2mon.sql create mode 100644 perf/db2monAfter.sql create mode 100644 perf/db2monBefore.sql create mode 100644 perf/db2monInterval.sql create mode 100644 perf/db2mon_export.sql create mode 100644 perf/db2mon_import.sql create mode 100644 perf/db2mon_report.sql create mode 100644 perl/DB2SampUtil.pm create mode 100644 perl/DB2WlmHist.pm create mode 100644 perl/README create mode 100644 perl/README_QPWLMMIG create mode 100644 perl/README_WLMHIST create mode 100644 perl/dbauth.pl create mode 100644 perl/dbuse.pl create mode 100644 perl/dtlob.pl create mode 100755 perl/hadrCalculator.pl create mode 100644 perl/qpwlmmig.pl create mode 100644 perl/spclient.pl create mode 100644 perl/tbconstr.pl create mode 100644 perl/tbinfo.pl create mode 100644 perl/tbpriv.pl create mode 100644 perl/tbsel.pl create mode 100644 perl/tbselcreate.db2 create mode 100644 perl/tbseldrop.db2 create mode 100644 perl/tbselinit create mode 100644 perl/tbtrig.pl create mode 100644 perl/tbuse.pl create mode 100644 perl/wlmhist.pl create mode 100644 perl/wlmhistrep.pl create mode 100644 php/DbAuthorities_DB2.php create mode 100644 php/DbAuthorities_PDO.php create mode 100644 php/DtInfo_DB2.php create mode 100644 php/DtInfo_PDO.php create mode 100644 php/DtLOB_DB2.php create mode 100644 php/DtLOB_PDO_generic.php create mode 100644 php/DtUDT_DB2.php create mode 100644 php/DtUDT_PDO.php create mode 100644 php/PHPSampleConfig.cfg create mode 100644 php/README create mode 100644 php/TblConstraints_DB2.php create mode 100644 php/TblConstraints_PDO.php create mode 100644 php/TblIdentityCol_DB2.php create mode 100644 php/TblIdentityCol_PDO.php create mode 100644 php/TblSelect_DB2.php create mode 100644 php/TblSelect_PDO.php create mode 100644 php/TblTrigger_DB2.php create mode 100644 php/TblTrigger_PDO.php create mode 100644 php/TblUnion_DB2.php create mode 100644 php/TblUnion_PDO.php create mode 100644 php/UtilConnection_DB2.php create mode 100644 php/UtilConnection_DB2_Def create mode 100644 php/UtilConnection_PDO.php create mode 100644 php/UtilConnection_PDO_Def create mode 100644 php/UtilIOHelper.php create mode 100644 php/UtilIOHelper_Def create mode 100644 php/UtilTableSetup_Def create mode 100644 php/UtilTableSetup_LOB.php create mode 100644 php/UtilTableSetup_Staff.php create mode 100644 php/UtilTableSetup_Xml.php create mode 100644 php/XmlFlwor_DB2.php create mode 100644 php/XmlIndex_DB2.php create mode 100644 php/XmlInsert_DB2.php create mode 100644 php/XmlRead_DB2.php create mode 100644 php/XmlRelToXmlDOC_DB2.php create mode 100644 php/XmlRelToXmlType_DB2.php create mode 100644 php/XmlRunstats.php create mode 100644 php/XmlSQLXQuery_DB2.php create mode 100644 php/XmlSchema_DB2.php create mode 100644 php/XmlToTable_DB2.php create mode 100644 php/XmlUniqueIndexes_DB2.php create mode 100644 php/XmlUpAndDel_DB2.php create mode 100644 php/XmlXPath_DB2.php create mode 100644 php/XmlXQuery_DB2.php create mode 100644 php/photo.gif create mode 100644 php/resume.txt create mode 100644 php/tbselinit create mode 100644 plsql/README create mode 100644 repl/asnclp/2Nodes.in create mode 100644 repl/asnclp/2nodes/2Node0.in create mode 100644 repl/asnclp/2nodes/2Node1.in create mode 100644 repl/asnclp/2nodes/2Node2.in create mode 100644 repl/asnclp/3Nodes.in create mode 100644 repl/asnclp/3nodes/3Node0.in create mode 100644 repl/asnclp/3nodes/3Node1.in create mode 100644 repl/asnclp/3nodes/3Node2.in create mode 100644 repl/asnclp/3nodes/3Node3.in create mode 100644 repl/asnclp/Addtables.in create mode 100644 repl/asnclp/AlterPubQMap.txt create mode 100644 repl/asnclp/AlterQReplMap.txt create mode 100644 repl/asnclp/AlterQSubsUOW.txt create mode 100644 repl/asnclp/AlterXMLUOW.txt create mode 100644 repl/asnclp/Bidir.in create mode 100644 repl/asnclp/CrtPubQMap.txt create mode 100644 repl/asnclp/CrtQApplyUOW.txt create mode 100644 repl/asnclp/CrtQCapP2P.txt create mode 100644 repl/asnclp/CrtQCaptureUOW.txt create mode 100644 repl/asnclp/CrtQSubCCD.txt create mode 100644 repl/asnclp/CrtQSubsUOW.txt create mode 100644 repl/asnclp/CrtReg.txt create mode 100644 repl/asnclp/CrtReplQMap.txt create mode 100644 repl/asnclp/CrtReplQMap3nodes.txt create mode 100644 repl/asnclp/CrtSubs.txt create mode 100644 repl/asnclp/CrtXMLPubs.txt create mode 100644 repl/asnclp/Delete.in create mode 100644 repl/asnclp/DropPubQMap.txt create mode 100644 repl/asnclp/DropQApplyUOW.txt create mode 100644 repl/asnclp/DropQCapP2P.txt create mode 100644 repl/asnclp/DropQCaptureUOW.txt create mode 100644 repl/asnclp/DropQSubs.txt create mode 100644 repl/asnclp/DropReplQMap.txt create mode 100644 repl/asnclp/DropReplQMap3nodes.txt create mode 100644 repl/asnclp/DropXMLPub.txt create mode 100644 repl/asnclp/DropXMLPubs.txt create mode 100644 repl/asnclp/MassSubcrt.txt create mode 100644 repl/asnclp/P2PREADME.TXT create mode 100644 repl/asnclp/Update.in create mode 100644 repl/asnclp/ValidateWSMQ.txt create mode 100644 repl/asnclp/addtables/Addtables.in create mode 100644 repl/asnclp/bidir/Bidir0.in create mode 100644 repl/asnclp/bidir/Bidir1.in create mode 100644 repl/asnclp/bidir/Bidir2.in create mode 100644 repl/asnclp/bidir/Bidir3.in create mode 100644 repl/asnclp/delete/Delete0.in create mode 100644 repl/asnclp/delete/Delete1.in create mode 100644 repl/asnclp/delete/Delete2.in create mode 100644 repl/asnclp/delete/Delete3.in create mode 100644 repl/asnclp/q/exccdfanout.in create mode 100644 repl/asnclp/q/newccdfanout.in create mode 100644 repl/asnclp/setup.sql create mode 100644 repl/asnclp/update/Update0.in create mode 100644 repl/asnclp/update/Update3.in create mode 100644 repl/asnqwxml/README.htm create mode 100644 repl/asnqwxml/stockticker/build.xml create mode 100644 repl/asnqwxml/stockticker/dist/stockticker.war create mode 100644 repl/asnqwxml/stockticker/scripts/capparms.sql create mode 100644 repl/asnqwxml/stockticker/scripts/createdb.sql create mode 100644 repl/asnqwxml/stockticker/scripts/stockdata_dlt.sql create mode 100644 repl/asnqwxml/stockticker/scripts/stockdata_init.sql create mode 100644 repl/asnqwxml/stockticker/scripts/stockdata_ins.sql create mode 100644 repl/asnqwxml/stockticker/scripts/stockdata_upd.sql create mode 100644 repl/asnqwxml/stockticker/scripts/stocks.mq create mode 100644 repl/asnqwxml/stockticker/scripts/stocks.sql create mode 100644 repl/asnqwxml/stockticker/scripts/stockxpub.sql create mode 100644 repl/asnqwxml/stockticker/src/com/ibm/db2/samples/repl/publication/StockPrice.java create mode 100644 repl/asnqwxml/stockticker/src/com/ibm/db2/samples/repl/publication/StockPriceListener.java create mode 100644 repl/asnqwxml/stockticker/web/WEB-INF/web.xml create mode 100644 repl/asnqwxml/stockticker/web/stockticker.jsp create mode 100644 repl/mig10/q/asnoqcapluwv10.sql create mode 100644 repl/mig10/q/asnoqcapluwv10fp.sql create mode 100644 repl/mig10/q/asnqappluwinfxv10.sql create mode 100644 repl/mig10/q/asnqappluwinfxv10fp.sql create mode 100644 repl/mig10/q/asnqappluwmssqlv10.sql create mode 100644 repl/mig10/q/asnqappluwmssqlv10fp.sql create mode 100644 repl/mig10/q/asnqappluworav10.sql create mode 100644 repl/mig10/q/asnqappluworav10fp.sql create mode 100644 repl/mig10/q/asnqappluwsybv10.sql create mode 100644 repl/mig10/q/asnqappluwsybv10fp.sql create mode 100644 repl/mig10/q/asnqappluwteradatav10.sql create mode 100644 repl/mig10/q/asnqappluwteradatav10fp.sql create mode 100644 repl/mig10/q/asnqappluwv10.sql create mode 100644 repl/mig10/q/asnqappluwv10fp.sql create mode 100644 repl/mig10/q/asnqcapluwv10.sql create mode 100644 repl/mig10/q/asnqcapluwv10fp.sql create mode 100644 repl/mig10/q/asnqmz10.sql create mode 100644 repl/mig10/sql/asnappluwv10.sql create mode 100644 repl/mig10/sql/asncapluwv10.sql create mode 100644 repl/mig10/sql/asnmz10.sql create mode 100644 repl/mig1021/mon/asnmonluwv1021.sql create mode 100644 repl/mig1021/mon/asnmonluwv1021fp.sql create mode 100644 repl/mig1021/q/asnoqappluwv1021.sql create mode 100644 repl/mig1021/q/asnoqappluwv1021fp.sql create mode 100644 repl/mig1021/q/asnoqcapluwv1021.sql create mode 100644 repl/mig1021/q/asnoqcapluwv1021fp.sql create mode 100644 repl/mig1021/q/asnqappluwinfxv1021.sql create mode 100644 repl/mig1021/q/asnqappluwinfxv1021fp.sql create mode 100644 repl/mig1021/q/asnqappluwmssqlv1021.sql create mode 100644 repl/mig1021/q/asnqappluwmssqlv1021fp.sql create mode 100644 repl/mig1021/q/asnqappluworav1021.sql create mode 100644 repl/mig1021/q/asnqappluworav1021fp.sql create mode 100644 repl/mig1021/q/asnqappluwsybv1021.sql create mode 100644 repl/mig1021/q/asnqappluwsybv1021fp.sql create mode 100644 repl/mig1021/q/asnqappluwteradatav1021.sql create mode 100644 repl/mig1021/q/asnqappluwteradatav1021fp.sql create mode 100644 repl/mig1021/q/asnqappluwv1021.sql create mode 100644 repl/mig1021/q/asnqappluwv1021fp.sql create mode 100644 repl/mig1021/q/asnqcapluwv1021.sql create mode 100644 repl/mig1021/q/asnqcapluwv1021fp.sql create mode 100644 repl/mig1021/sql/asnappluwv1021.sql create mode 100644 repl/mig1021/sql/asnappluwv1021fp.sql create mode 100644 repl/mig1021/sql/asncapluwv1021.sql create mode 100644 repl/mig1021/sql/asncapluwv1021fp.sql create mode 100644 repl/mig1140/mon/asnmonluwv1140.sql create mode 100644 repl/mig1140/mon/asnmonluwv1140fp.sql create mode 100644 repl/mig1140/q/asnoqappluwv1140.sql create mode 100644 repl/mig1140/q/asnoqappluwv1140fp.sql create mode 100644 repl/mig1140/q/asnoqcapluwv1140.sql create mode 100644 repl/mig1140/q/asnoqcapluwv1140fp.sql create mode 100644 repl/mig1140/q/asnqappluwinfxv1140.sql create mode 100644 repl/mig1140/q/asnqappluwinfxv1140fp.sql create mode 100644 repl/mig1140/q/asnqappluwmssqlv1140.sql create mode 100644 repl/mig1140/q/asnqappluwmssqlv1140fp.sql create mode 100644 repl/mig1140/q/asnqappluworav1140.sql create mode 100644 repl/mig1140/q/asnqappluworav1140fp.sql create mode 100644 repl/mig1140/q/asnqappluwsybv1140.sql create mode 100644 repl/mig1140/q/asnqappluwsybv1140fp.sql create mode 100644 repl/mig1140/q/asnqappluwteradatav1140.sql create mode 100644 repl/mig1140/q/asnqappluwteradatav1140fp.sql create mode 100644 repl/mig1140/q/asnqappluwv1140.sql create mode 100644 repl/mig1140/q/asnqappluwv1140fp.sql create mode 100644 repl/mig1140/q/asnqcapluw1140.sql create mode 100644 repl/mig1140/q/asnqcapluwv1140fp.sql create mode 100644 repl/mig1140/sql/asnappluwv1140.sql create mode 100644 repl/mig1140/sql/asnappluwv1140fp.sql create mode 100644 repl/mig1140/sql/asncapluwv1140.sql create mode 100644 repl/mig1140/sql/asncapluwv1140fp.sql create mode 100644 repl/mig8/sql/asnmig8.txt create mode 100644 repl/mig8/sql/asnmigpw.C create mode 100644 repl/mig8/sql/mig8400.sql create mode 100644 repl/mig8/sql/mig8fed.sql create mode 100644 repl/mig8/sql/mig8udb.sql create mode 100644 repl/mig8/sql/mig8zos.sql create mode 100644 repl/mig9/mon/asnmonluw.sql create mode 100644 repl/mig9/q/asnqappinfx.sql create mode 100644 repl/mig9/q/asnqappluw.sql create mode 100644 repl/mig9/q/asnqappmssql.sql create mode 100644 repl/mig9/q/asnqappora.sql create mode 100644 repl/mig9/q/asnqappsyb.sql create mode 100644 repl/mig9/q/asnqcapluw.sql create mode 100644 repl/mig9/q/asnqmzv9.sql create mode 100644 repl/mig9/sql/asnsmzv9.sql create mode 100644 repl/mig95/mon/asnmonv95.sql create mode 100644 repl/mig95/q/asnqappinfxv95.sql create mode 100644 repl/mig95/q/asnqappluwv95.sql create mode 100644 repl/mig95/q/asnqappmssqlv95.sql create mode 100644 repl/mig95/q/asnqapporav95.sql create mode 100644 repl/mig95/q/asnqappsybv95.sql create mode 100644 repl/mig95/q/asnqcapluwv95.sql create mode 100644 repl/mig95/q/asnqmz95.sql create mode 100644 repl/mig95/q/asnqreplfallbackv95.sql create mode 100644 repl/mig95/q/asnqupdcompv95.sql create mode 100644 repl/mig95/sql/asnsmz95.sql create mode 100644 repl/mig97/q/asnoqcapluwv97fp.sql create mode 100644 repl/mig97/q/asnqappinfxv97.sql create mode 100644 repl/mig97/q/asnqappinfxv97fp.sql create mode 100644 repl/mig97/q/asnqappluwv97.sql create mode 100644 repl/mig97/q/asnqappluwv97fp.sql create mode 100644 repl/mig97/q/asnqappmssqlv97.sql create mode 100644 repl/mig97/q/asnqappmssqlv97fp.sql create mode 100644 repl/mig97/q/asnqapporav97.sql create mode 100644 repl/mig97/q/asnqapporav97fp.sql create mode 100644 repl/mig97/q/asnqappsybv97.sql create mode 100644 repl/mig97/q/asnqappsybv97fp.sql create mode 100644 repl/mig97/q/asnqappteradatav97fp.sql create mode 100644 repl/mig97/q/asnqcapluwv97.sql create mode 100644 repl/mig97/q/asnqcapluwv97fp.sql create mode 100644 repl/mig97/q/asnqmz97.sql create mode 100644 repl/mig97/q/asnqupdcompv97.sql create mode 100755 repl/mig97/sql/asnappluwv97fp.sql create mode 100644 repl/mig97/sql/asncapinfxv97.sql create mode 100644 repl/mig97/sql/asncapluwv97.sql create mode 100644 repl/mig97/sql/asncapluwv97fp.sql create mode 100644 repl/mig97/sql/asncapmssqlv97.sql create mode 100644 repl/mig97/sql/asncaporav97.sql create mode 100644 repl/mig97/sql/asncapsybv97.sql create mode 100644 repl/mig97/sql/asnmz97.sql create mode 100644 repl/mig98/q/asnqappluw.sql create mode 100644 repl/mig98/q/asnqcapluw.sql create mode 100644 repl/mon/asnmctlw.sql create mode 100644 repl/mon/asnmctlz.sql create mode 100644 repl/mon/monitor_api.c create mode 100644 repl/mon/monitor_api_nt.mak create mode 100644 repl/mon/monitor_api_unix.mak create mode 100644 repl/q/README.Q create mode 100644 repl/q/asnqdefq create mode 100644 repl/q/asnqspC.SQC create mode 100644 repl/q/asnqspC.def create mode 100644 repl/q/asnqspC.exp create mode 100644 repl/q/asnqspC.mak create mode 100644 repl/q/asnqspSQL.sql create mode 100644 repl/q/asnqspcreate.sql create mode 100644 repl/q/mq/p2p_2node_remote.pdf create mode 100644 repl/q/mq/pub_local.pdf create mode 100644 repl/q/mq/pub_remote.pdf create mode 100644 repl/q/mq/smart_p2p_2node_remote.pdf create mode 100644 repl/q/mq/smart_uni_remote.pdf create mode 100644 repl/q/mq/uni_remote.pdf create mode 100644 repl/q/mqcap.xsd create mode 100644 repl/q/mqsub.xsd create mode 100644 repl/q/qapply_api.C create mode 100644 repl/q/qapply_api_nt.mak create mode 100644 repl/q/qapply_api_unix.mak create mode 100644 repl/q/qcapture_api.C create mode 100644 repl/q/qcapture_api_nt.mak create mode 100644 repl/q/qcapture_api_unix.mak create mode 100644 repl/sql/ASNDONE.smp create mode 100644 repl/sql/ASNLOAD.smp create mode 100644 repl/sql/README.SQL create mode 100644 repl/sql/apply_api.c create mode 100644 repl/sql/apply_api_nt.mak create mode 100644 repl/sql/apply_api_unix.mak create mode 100644 repl/sql/asnctlw.sql create mode 100644 repl/sql/asnctlz.sql create mode 100644 repl/sql/asnctlz7.sql create mode 100644 repl/sql/asnload.h create mode 100644 repl/sql/asnload.ini create mode 100644 repl/sql/asnmail.smp create mode 100644 repl/sql/asnparseini.C create mode 100644 repl/sql/capture_api.c create mode 100644 repl/sql/capture_api_nt.mak create mode 100644 repl/sql/capture_api_unix.mak create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/ActivateSubscriptionMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/AddColumnMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/Column.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/ColumnSchema.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/ControlMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/DataMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/DeactivateSubscriptionMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/ErrorReportMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/HeartbeatMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/InformationalMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/InvalidateSendQueueMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/LOBMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/LoadDoneControlMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/LoadDoneReceivedMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/Msg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/PublicationMsgListener.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/PublicationMsgProvider.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/PublicationMsgProviderFactory.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/Row.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/RowOperationMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/SubscriptionDeactivatedMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/SubscriptionSchemaMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/TransactionMsg.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/Utils.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/support/PublicationHandler.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/support/PublicationMsgProviderImpl.java create mode 100644 repl/xmlpubtk/com/ibm/db2/tools/repl/publication/support/PublicationParser.java create mode 100644 repl/xmlpubtk/doc/allclasses-frame.html create mode 100644 repl/xmlpubtk/doc/allclasses-noframe.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ActivateSubscriptionMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/AddColumnMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Column.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ColumnSchema.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ControlMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/DataMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/DeactivateSubscriptionMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ErrorReportMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/HeartbeatMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/InformationalMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/InvalidateSendQueueMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LOBMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LoadDoneControlMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LoadDoneReceivedMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Msg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgListener.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgProvider.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgProviderFactory.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Row.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/RowOperationMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/SubscriptionDeactivatedMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/SubscriptionSchemaMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/TransactionMsg.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Utils.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-frame.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-summary.html create mode 100644 repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-tree.html create mode 100644 repl/xmlpubtk/doc/constant-values.html create mode 100644 repl/xmlpubtk/doc/deprecated-list.html create mode 100644 repl/xmlpubtk/doc/help-doc.html create mode 100644 repl/xmlpubtk/doc/index-all.html create mode 100644 repl/xmlpubtk/doc/index.html create mode 100644 repl/xmlpubtk/doc/overview-tree.html create mode 100644 repl/xmlpubtk/doc/package-list create mode 100644 repl/xmlpubtk/doc/packages.html create mode 100644 repl/xmlpubtk/doc/serialized-form.html create mode 100644 repl/xmlpubtk/doc/stylesheet.css create mode 100644 repl/xmlpubtk/loadqueue/LoadQueue.jar create mode 100644 repl/xmlpubtk/loadqueue/LoadQueue.java create mode 100644 repl/xmlpubtk/readme.txt create mode 100644 repl/xmlpubtk/sample1/sample1.jar create mode 100644 repl/xmlpubtk/sample1/sample1.java create mode 100644 repl/xmlpubtk/sample2/Count.java create mode 100644 repl/xmlpubtk/sample2/MonitorFrame.java create mode 100644 repl/xmlpubtk/sample2/MonitorTablePanel.java create mode 100644 repl/xmlpubtk/sample2/PublicationListener.java create mode 100644 repl/xmlpubtk/sample2/sample2.jar create mode 100644 repl/xmlpubtk/sample2/sample2.java create mode 100644 repl/xmlpubtk/sample3/Count.java create mode 100644 repl/xmlpubtk/sample3/MonitorFrame.java create mode 100644 repl/xmlpubtk/sample3/MonitorTablePanel.java create mode 100644 repl/xmlpubtk/sample3/PublicationDataModel.java create mode 100644 repl/xmlpubtk/sample3/PublicationListener.java create mode 100644 repl/xmlpubtk/sample3/PublicationTableCellRenderer.java create mode 100644 repl/xmlpubtk/sample3/PublicationTableModel.java create mode 100644 repl/xmlpubtk/sample3/StringWithInterval.java create mode 100644 repl/xmlpubtk/sample3/SubscriptionDialog.java create mode 100644 repl/xmlpubtk/sample3/TableName.java create mode 100644 repl/xmlpubtk/sample3/sample3.jar create mode 100644 repl/xmlpubtk/sample3/sample3.java create mode 100644 repl/xmlpubtk/xmlpubtk.jar create mode 100644 security/plugins/IBMLDAPauthclient.c create mode 100644 security/plugins/IBMLDAPauthserver.c create mode 100644 security/plugins/IBMLDAPconfig.c create mode 100644 security/plugins/IBMLDAPgroups.c create mode 100644 security/plugins/IBMLDAPutils.c create mode 100644 security/plugins/IBMLDAPutils.h create mode 100644 security/plugins/IBMkrb5.c create mode 100644 security/plugins/README create mode 100644 security/plugins/bldplugin create mode 100644 security/plugins/combined.c create mode 100644 security/plugins/group_file.c create mode 100644 security/plugins/gssapi_simple.c create mode 100644 security/plugins/makefile create mode 100644 selinux/RHEL5/Makefile create mode 100644 selinux/RHEL5/README create mode 100644 selinux/RHEL5/db2.fc create mode 100644 selinux/RHEL5/db2.if create mode 100644 selinux/RHEL5/db2.te create mode 100755 selinux/RHEL5/ibm_db2_semanage_das create mode 100755 selinux/RHEL5/ibm_db2_semanage_db2inst create mode 100644 sql_statements/README create mode 100644 sqlpl/NestedSP.java create mode 100644 sqlpl/README create mode 100644 sqlpl/Util.java create mode 100644 sqlpl/array_stack.db2 create mode 100644 sqlpl/arrays_sqlpl.db2 create mode 100644 sqlpl/basecase.db2 create mode 100644 sqlpl/basecase.sqc create mode 100644 sqlpl/baseif.db2 create mode 100644 sqlpl/baseif.sqc create mode 100755 sqlpl/bldapp create mode 100755 sqlpl/bldcli create mode 100644 sqlpl/defaultparam.db2 create mode 100644 sqlpl/dynamic.db2 create mode 100644 sqlpl/dynamic.sqc create mode 100755 sqlpl/embprep create mode 100644 sqlpl/iterate.db2 create mode 100644 sqlpl/iterate.sqc create mode 100644 sqlpl/leave.db2 create mode 100644 sqlpl/leave.sqc create mode 100644 sqlpl/loop.db2 create mode 100644 sqlpl/loop.sqc create mode 100755 sqlpl/makefile create mode 100644 sqlpl/modules.db2 create mode 100644 sqlpl/nestcase.db2 create mode 100644 sqlpl/nestcase.sqc create mode 100644 sqlpl/nestedsp.db2 create mode 100644 sqlpl/nestedspdrop.db2 create mode 100644 sqlpl/nestif.db2 create mode 100644 sqlpl/nestif.sqc create mode 100644 sqlpl/repeat.db2 create mode 100644 sqlpl/repeat.sqc create mode 100644 sqlpl/rsultset.c create mode 100644 sqlpl/rsultset.db2 create mode 100644 sqlpl/spserver.db2 create mode 100644 sqlpl/tbfn.db2 create mode 100644 sqlpl/tbfnuse.db2 create mode 100644 sqlpl/tbsel.sqc create mode 100644 sqlpl/tbselcreate.db2 create mode 100644 sqlpl/tbseldrop.db2 create mode 100644 sqlpl/utilapi.c create mode 100644 sqlpl/utilapi.h create mode 100644 sqlpl/utilcli.c create mode 100644 sqlpl/utilcli.h create mode 100644 sqlpl/utilemb.h create mode 100644 sqlpl/utilemb.sqc create mode 100644 sqlpl/whiles.db2 create mode 100644 sqlpl/whiles.sqc create mode 100644 webservices/soapsample.sql create mode 100644 wrappers/wrapper_sdk/cc_plugin/README create mode 100644 wrappers/wrapper_sdk/cc_plugin/makefile create mode 100644 wrappers/wrapper_sdk/cc_plugin/sample.db2 create mode 100644 wrappers/wrapper_sdk/cc_plugin/sample.java create mode 100644 wrappers/wrapper_sdk/cc_plugin/sample.properties create mode 100644 wrappers/wrapper_sdk/cc_plugin/sample.xml create mode 100644 wrappers/wrapper_sdk/makefile create mode 100755 wrappers/wrapper_sdk/sample_connection.C create mode 100755 wrappers/wrapper_sdk/sample_connection.h create mode 100644 wrappers/wrapper_sdk/sample_error_reporting.h create mode 100644 wrappers/wrapper_sdk/sample_fenced_nickname.C create mode 100644 wrappers/wrapper_sdk/sample_fenced_nickname.h create mode 100644 wrappers/wrapper_sdk/sample_fenced_server.C create mode 100644 wrappers/wrapper_sdk/sample_fenced_server.h create mode 100644 wrappers/wrapper_sdk/sample_fenced_user.C create mode 100644 wrappers/wrapper_sdk/sample_fenced_user.h create mode 100644 wrappers/wrapper_sdk/sample_fenced_wrapper.C create mode 100644 wrappers/wrapper_sdk/sample_fenced_wrapper.h create mode 100755 wrappers/wrapper_sdk/sample_nickname.C create mode 100755 wrappers/wrapper_sdk/sample_nickname.h create mode 100755 wrappers/wrapper_sdk/sample_operation.C create mode 100755 wrappers/wrapper_sdk/sample_operation.h create mode 100644 wrappers/wrapper_sdk/sample_portability.h create mode 100755 wrappers/wrapper_sdk/sample_server.C create mode 100755 wrappers/wrapper_sdk/sample_server.h create mode 100644 wrappers/wrapper_sdk/sample_typedefs.h create mode 100755 wrappers/wrapper_sdk/sample_user.C create mode 100755 wrappers/wrapper_sdk/sample_user.h create mode 100644 wrappers/wrapper_sdk/sample_utilities.C create mode 100644 wrappers/wrapper_sdk/sample_utilities.h create mode 100755 wrappers/wrapper_sdk/sample_wrapper.C create mode 100755 wrappers/wrapper_sdk/sample_wrapper.h create mode 100644 wrappers/wrapper_sdk_java/FencedFileNickname.java create mode 100644 wrappers/wrapper_sdk_java/FencedFileServer.java create mode 100644 wrappers/wrapper_sdk_java/FencedFileWrapper.java create mode 100644 wrappers/wrapper_sdk_java/FileConnection.java create mode 100644 wrappers/wrapper_sdk_java/FileExecDesc.java create mode 100644 wrappers/wrapper_sdk_java/FileQuery.java create mode 100644 wrappers/wrapper_sdk_java/Readme.txt create mode 100644 wrappers/wrapper_sdk_java/UnfencedFileNickname.java create mode 100644 wrappers/wrapper_sdk_java/UnfencedFileServer.java create mode 100644 wrappers/wrapper_sdk_java/UnfencedFileWrapper.java create mode 100644 wrappers/wrapper_sdk_java/javadoc/allclasses-frame.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/allclasses-noframe.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/CatalogInfo.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/CatalogOption.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ColumnInfo.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Data.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/DefaultRemoteFunction.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericNickname.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericRemoteUser.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericServer.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericWrapper.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedNickname.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedRemoteUser.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedServer.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedWrapper.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/IndexInfo.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Nickname.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/NicknameInfo.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ParsedQueryFragment.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/PredicateList.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Quantifier.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RFuncParmInfo.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteConnection.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteFunctionInfo.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteOperation.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemotePassthru.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteQuery.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteUser.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Reply.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Request.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestConstant.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestExp.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestExpType.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeData.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataDesc.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataDescList.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataList.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Server.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ServerInfo.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericNickname.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericRemoteUser.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericServer.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericWrapper.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedNickname.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedRemoteUser.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedServer.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedWrapper.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UserInfo.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Wrapper.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperException.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperInfo.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperUtilities.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-frame.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-summary.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-tree.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/constant-values.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/help-doc.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/index-all.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/index.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/overview-tree.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/package-list create mode 100644 wrappers/wrapper_sdk_java/javadoc/resources/background.gif create mode 100644 wrappers/wrapper_sdk_java/javadoc/resources/tab.gif create mode 100644 wrappers/wrapper_sdk_java/javadoc/resources/titlebar.gif create mode 100644 wrappers/wrapper_sdk_java/javadoc/resources/titlebar_end.gif create mode 100644 wrappers/wrapper_sdk_java/javadoc/serialized-form.html create mode 100644 wrappers/wrapper_sdk_java/javadoc/stylesheet.css create mode 100644 xml/README create mode 100644 xml/addr.xsd create mode 100644 xml/c/README create mode 100644 xml/c/bldapp create mode 100644 xml/c/bldrtn create mode 100644 xml/c/embprep create mode 100644 xml/c/impexpxml.sqc create mode 100644 xml/c/lobstoxml.sqc create mode 100644 xml/c/makefile create mode 100644 xml/c/recxmldecomp.sqc create mode 100644 xml/c/reltoxmltype.sqc create mode 100644 xml/c/simple_xmlproc.exp create mode 100644 xml/c/simple_xmlproc.sqc create mode 100644 xml/c/simple_xmlproc_client.db2 create mode 100644 xml/c/simple_xmlproc_create.db2 create mode 100644 xml/c/simple_xmlproc_drop.db2 create mode 100644 xml/c/spcat_xml create mode 100644 xml/c/utilapi.c create mode 100644 xml/c/utilapi.h create mode 100644 xml/c/utilemb.h create mode 100644 xml/c/utilemb.sqc create mode 100644 xml/c/xmlcheckconstraint.sqc create mode 100644 xml/c/xmlconst.sqc create mode 100644 xml/c/xmldecomposition.sqc create mode 100644 xml/c/xmlindex.sqc create mode 100644 xml/c/xmlinsert.sqc create mode 100644 xml/c/xmlintegrate.sqc create mode 100644 xml/c/xmlload.sqc create mode 100644 xml/c/xmlread.sqc create mode 100644 xml/c/xmlrunstats.sqc create mode 100644 xml/c/xmlschema.sqc create mode 100644 xml/c/xmltrig.sqc create mode 100644 xml/c/xmludfs.sqc create mode 100644 xml/c/xmlupdel.sqc create mode 100644 xml/c/xmlxslt.sqc create mode 100644 xml/catalog.xsd create mode 100644 xml/cli/README create mode 100644 xml/cli/bldapp create mode 100644 xml/cli/bldrtn create mode 100644 xml/cli/makefile create mode 100644 xml/cli/reltoxmldoc.c create mode 100644 xml/cli/reltoxmlproc.db2 create mode 100644 xml/cli/simple_xmlproc.c create mode 100644 xml/cli/simple_xmlproc.exp create mode 100644 xml/cli/simple_xmlproc_client.c create mode 100644 xml/cli/simple_xmlproc_create.db2 create mode 100644 xml/cli/simple_xmlproc_drop.db2 create mode 100644 xml/cli/spcat_xml create mode 100644 xml/cli/utilcli.c create mode 100644 xml/cli/utilcli.h create mode 100644 xml/cli/xmlconst.c create mode 100644 xml/cli/xmlindex.c create mode 100644 xml/cli/xmlinsert.c create mode 100644 xml/cli/xmlread.c create mode 100644 xml/cli/xmltotable.c create mode 100644 xml/cli/xmludfs.c create mode 100644 xml/cli/xmlupdel.c create mode 100644 xml/cli/xsupdate.c create mode 100644 xml/clp/README create mode 100644 xml/clp/impexpxml.db2 create mode 100644 xml/clp/lobstoxml.db2 create mode 100644 xml/clp/recxmldecomp.db2 create mode 100644 xml/clp/reltoxmldoc.db2 create mode 100644 xml/clp/reltoxmlproc.db2 create mode 100644 xml/clp/reltoxmltype.db2 create mode 100644 xml/clp/simple_xmlproc.db2 create mode 100644 xml/clp/xmlcheckconstraint.db2 create mode 100644 xml/clp/xmlconst.db2 create mode 100644 xml/clp/xmldb2batch.db2 create mode 100644 xml/clp/xmldb2batch_in.sql create mode 100644 xml/clp/xmldb2look.db2 create mode 100644 xml/clp/xmldbafn.db2 create mode 100644 xml/clp/xmldecomposition.db2 create mode 100644 xml/clp/xmlindex.db2 create mode 100644 xml/clp/xmlindgtt.db2 create mode 100644 xml/clp/xmlinsert.db2 create mode 100644 xml/clp/xmlintegrate.db2 create mode 100644 xml/clp/xmlload.db2 create mode 100644 xml/clp/xmlmdc.db2 create mode 100644 xml/clp/xmlolic.db2 create mode 100644 xml/clp/xmlpartition.db2 create mode 100644 xml/clp/xmlrunstats.db2 create mode 100644 xml/clp/xmlschema.db2 create mode 100644 xml/clp/xmltotable.db2 create mode 100644 xml/clp/xmltrig.db2 create mode 100644 xml/clp/xmludfs.db2 create mode 100644 xml/clp/xmlupdel.db2 create mode 100644 xml/clp/xmlxslt.db2 create mode 100644 xml/clp/xrpart.db2 create mode 100644 xml/clp/xsupdate.db2 create mode 100644 xml/customer.xsd create mode 100644 xml/data/bookdetail.xml create mode 100644 xml/data/bookdetail.xsd create mode 100644 xml/data/bookdetails.xml create mode 100644 xml/data/bookdetails.xsd create mode 100644 xml/data/booksreturned.del create mode 100644 xml/data/booksreturned.xsd create mode 100644 xml/data/booksreturned1.xml create mode 100644 xml/data/booksreturned2.xml create mode 100644 xml/data/booksreturned3.xml create mode 100644 xml/data/boots.xsd create mode 100644 xml/data/cleanupfordecomposition.db2 create mode 100644 xml/data/cleanupscript.db2 create mode 100644 xml/data/cust1021.xml create mode 100644 xml/data/cust1022.xml create mode 100644 xml/data/cust1023.xml create mode 100644 xml/data/customer.xsd create mode 100644 xml/data/header.xsd create mode 100644 xml/data/loaddata1.del create mode 100644 xml/data/loaddata2.del create mode 100644 xml/data/loadfile1.xml create mode 100644 xml/data/loadfile2.xml create mode 100644 xml/data/musicplayer.xsd create mode 100644 xml/data/newprod.xsd create mode 100644 xml/data/order.xml create mode 100644 xml/data/order.xsd create mode 100644 xml/data/prod.xsd create mode 100644 xml/data/product.xsd create mode 100644 xml/data/purchaseorder.xml create mode 100644 xml/data/recemp.xml create mode 100644 xml/data/recemp.xsd create mode 100644 xml/data/setupfordecomposition.db2 create mode 100644 xml/data/setupscript.db2 create mode 100644 xml/data/xmldata.del create mode 100644 xml/data/xmlfiles.001.xml create mode 100644 xml/history.xsd create mode 100644 xml/java/jdbc/README create mode 100644 xml/java/jdbc/RecXmlDecomp.java create mode 100644 xml/java/jdbc/RelToXmlDoc.java create mode 100644 xml/java/jdbc/RelToXmlType.java create mode 100644 xml/java/jdbc/Simple_XmlProc.java create mode 100644 xml/java/jdbc/Simple_XmlProc_Client.java create mode 100644 xml/java/jdbc/Simple_XmlProc_Create.db2 create mode 100644 xml/java/jdbc/Simple_XmlProc_Drop.db2 create mode 100644 xml/java/jdbc/Util.java create mode 100644 xml/java/jdbc/XmlCheckConstraint.java create mode 100644 xml/java/jdbc/XmlConst.java create mode 100644 xml/java/jdbc/XmlDecomposition.java create mode 100644 xml/java/jdbc/XmlIndex.java create mode 100644 xml/java/jdbc/XmlInsert.java create mode 100644 xml/java/jdbc/XmlMdc.java create mode 100644 xml/java/jdbc/XmlRead.java create mode 100644 xml/java/jdbc/XmlRunstats.java create mode 100644 xml/java/jdbc/XmlSchema.java create mode 100644 xml/java/jdbc/XmlToTable.java create mode 100644 xml/java/jdbc/XmlTrig.java create mode 100644 xml/java/jdbc/XmlUdfs.java create mode 100644 xml/java/jdbc/XmlUpDel.java create mode 100644 xml/java/jdbc/XsUpdate.java create mode 100644 xml/java/jdbc/makefile create mode 100644 xml/java/jdbc/reltoxmlproc.db2 create mode 100644 xml/java/jdbc/spcat_xml create mode 100644 xml/java/sqlj/README create mode 100644 xml/java/sqlj/RelToXmlDoc.sqlj create mode 100644 xml/java/sqlj/RelToXmlScrpt create mode 100644 xml/java/sqlj/RelToXmlType.sqlj create mode 100644 xml/java/sqlj/Util.sqlj create mode 100644 xml/java/sqlj/XmlConst.sqlj create mode 100644 xml/java/sqlj/XmlIndex.sqlj create mode 100644 xml/java/sqlj/XmlInsert.sqlj create mode 100644 xml/java/sqlj/XmlInsertScrpt create mode 100644 xml/java/sqlj/XmlInsert_cleanup.db2 create mode 100644 xml/java/sqlj/XmlInsert_setup.db2 create mode 100644 xml/java/sqlj/XmlIntegrate.sqlj create mode 100644 xml/java/sqlj/XmlIntegrateScrpt create mode 100644 xml/java/sqlj/XmlIntegrate_cleanup.db2 create mode 100644 xml/java/sqlj/XmlIntegrate_setup.db2 create mode 100644 xml/java/sqlj/XmlRead.sqlj create mode 100644 xml/java/sqlj/XmlSchema.sqlj create mode 100644 xml/java/sqlj/XmlToTable.sqlj create mode 100644 xml/java/sqlj/XmlToTableScrpt create mode 100644 xml/java/sqlj/XmlToTable_cleanup.db2 create mode 100644 xml/java/sqlj/XmlToTable_setup.db2 create mode 100644 xml/java/sqlj/XmlUpDel.sqlj create mode 100644 xml/java/sqlj/XmlUpDelScrpt create mode 100644 xml/java/sqlj/XmlUpDel_cleanup.db2 create mode 100644 xml/java/sqlj/XmlUpDel_setup.db2 create mode 100644 xml/java/sqlj/XmlXslt.sqlj create mode 100644 xml/java/sqlj/XmlXsltScrpt create mode 100644 xml/java/sqlj/XmlXslt_cleanup.db2 create mode 100644 xml/java/sqlj/XmlXslt_setup.db2 create mode 100644 xml/java/sqlj/bldsqlj create mode 100644 xml/java/sqlj/makefile create mode 100644 xml/java/sqlj/reltoxmlproc.db2 create mode 100644 xml/java/sqlj/reltoxmlprocScrpt create mode 100644 xml/java/sqlj/reltoxmlprocdrop.db2 create mode 100644 xml/porder.xsd create mode 100644 xml/product.xsd create mode 100644 xml/supplier.xsd create mode 100644 xml/xquery/README create mode 100644 xml/xquery/c/bldapp create mode 100644 xml/xquery/c/bldrtn create mode 100644 xml/xquery/c/client_xquery_xmlproc.sqc create mode 100644 xml/xquery/c/embprep create mode 100644 xml/xquery/c/flwor.sqc create mode 100644 xml/xquery/c/makefile create mode 100644 xml/xquery/c/spcat_xquery create mode 100644 xml/xquery/c/sqlxquery.sqc create mode 100644 xml/xquery/c/utilapi.c create mode 100644 xml/xquery/c/utilapi.h create mode 100644 xml/xquery/c/utilemb.h create mode 100644 xml/xquery/c/utilemb.sqc create mode 100644 xml/xquery/c/xpath.sqc create mode 100644 xml/xquery/c/xquery.sqc create mode 100644 xml/xquery/c/xquery_xmlproc.exp create mode 100644 xml/xquery/c/xquery_xmlproc.sqc create mode 100644 xml/xquery/c/xquery_xmlproc_create.db2 create mode 100644 xml/xquery/c/xquery_xmlproc_drop.db2 create mode 100644 xml/xquery/c/xqueryparam.sqc create mode 100755 xml/xquery/c/xupdate.sqc create mode 100644 xml/xquery/cli/bldapp create mode 100644 xml/xquery/cli/bldrtn create mode 100644 xml/xquery/cli/flwor.c create mode 100644 xml/xquery/cli/makefile create mode 100644 xml/xquery/cli/spcat_xquery create mode 100644 xml/xquery/cli/sqlxquery.c create mode 100644 xml/xquery/cli/utilcli.c create mode 100644 xml/xquery/cli/utilcli.h create mode 100644 xml/xquery/cli/xpath.c create mode 100644 xml/xquery/cli/xquery.c create mode 100644 xml/xquery/cli/xquery_xmlproc.c create mode 100644 xml/xquery/cli/xquery_xmlproc.exp create mode 100644 xml/xquery/cli/xquery_xmlproc_client.c create mode 100644 xml/xquery/cli/xquery_xmlproc_create.db2 create mode 100644 xml/xquery/cli/xquery_xmlproc_drop.db2 create mode 100644 xml/xquery/clp/flwor.db2 create mode 100644 xml/xquery/clp/sqlxquery.db2 create mode 100644 xml/xquery/clp/xpath.db2 create mode 100644 xml/xquery/clp/xquery.db2 create mode 100644 xml/xquery/clp/xquery_explain.db2 create mode 100644 xml/xquery/clp/xquery_xmlproc.db2 create mode 100644 xml/xquery/clp/xqueryparam.db2 create mode 100644 xml/xquery/clp/xupdate.db2 create mode 100644 xml/xquery/java/jdbc/Flwor.java create mode 100644 xml/xquery/java/jdbc/SqlXQuery.java create mode 100644 xml/xquery/java/jdbc/XPath.java create mode 100644 xml/xquery/java/jdbc/XQuery.java create mode 100644 xml/xquery/java/jdbc/XQueryParam.java create mode 100644 xml/xquery/java/jdbc/XUpdate.java create mode 100644 xml/xquery/java/jdbc/Xquery_XmlProc.java create mode 100644 xml/xquery/java/jdbc/Xquery_XmlProc_Client.java create mode 100644 xml/xquery/java/jdbc/Xquery_XmlProc_Create.db2 create mode 100644 xml/xquery/java/jdbc/Xquery_XmlProc_Drop.db2 create mode 100644 xml/xquery/java/jdbc/makefile create mode 100644 xml/xquery/java/jdbc/spcat_xquery create mode 100644 xml/xquery/java/sqlj/Flwor.sqlj create mode 100644 xml/xquery/java/sqlj/SqlXQuery.sqlj create mode 100644 xml/xquery/java/sqlj/XPath.sqlj create mode 100644 xml/xquery/java/sqlj/XQuery.sqlj create mode 100644 xml/xquery/java/sqlj/bldsqlj create mode 100644 xml/xquery/java/sqlj/makefile diff --git a/BARVendor/ACS_scripts/acs_ibmstor.sh b/BARVendor/ACS_scripts/acs_ibmstor.sh new file mode 100644 index 0000000..d2ec721 --- /dev/null +++ b/BARVendor/ACS_scripts/acs_ibmstor.sh @@ -0,0 +1,1559 @@ +#!/usr/bin/ksh +#--------------------------------------------------------------------------- +# (c) Copyright IBM Corp. 2012 All rights reserved. +# +# Script Name: acs_ibmstor.sh +# +# Purpose: implement the scripted interface for DB2 ACS using IBM System Storage DS4800 and Storage Manager. +# This script is called by DB2 to make snapshot backups of paths provided by DB2. +# +# Please see developerwork article for details: https://www.ibm.com/developerworks/data/library/techarticle/dm-1506scriptdb2copy4/dm-1506scriptdb2copy4-pdf.pdf +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +#--------------------------------------------------------------------------- + +# print out debug info +# set X for Debug, +# DEBUG=X + +# IBM Storage Manager path and exes +SMINST="/usr/SMclient" +SMBIN=$SMINST +SMCLI="$SMBIN/SMcli" +# SM_HOST="10.17.200.86" +SM_HOST="10.17.200.73 10.17.200.86" +SM_PASSWORD="dashb0ard" + +MOUNT=/usr/sbin/mount +UMOUNT=/usr/sbin/umount +LSPV=/usr/sbin/lspv +LSDEV=/usr/sbin/lsdev +LSVG=/usr/sbin/lsvg +VARYOFFVG=/usr/sbin/varyoffvg +VARYONVG=/usr/sbin/varyonvg +EXPORTVG=/usr/sbin/exportvg +RECREATEVG=/usr/sbin/recreatevg +GREP=/usr/bin/grep + +# Log file +LOGPREFIX="storage_snap" +LOGPOSTFIX="AMT" +LOG=/tmp/${LOGPREFIX}_${LOGPOSTFIX}.log + +# Protocol Backup directory +PROT_BKP_DIR="/db2/db2amt/scriptACS/prot_bkp/" +# Mapping file for FlashCopy Logical Drives +FC_MAPPING_FILE="/db2/db2amt/fc_mapping.txt" + +# User defined entries in the protocol file +USER_DB2FS="USER_DB2FS" +USER_FC="USER_FC" + +# Tempfile names +TMPDIR=/tmp +TMP=${TMPDIR}/${LOGPREFIX}_${LOGPOSTFIX}.tmp +TMP_=${TMPDIR}/${LOGPREFIX}_${LOGPOSTFIX}.tmp_ +BGND_RC_FILE=${TMPDIR}/${LOGPREFIX}_BGND_RC_${LOGPOSTFIX}.tmp +SM_CMD_OUT=${TMPDIR}/${LOGPREFIX}_SM_CMD_OUT_${LOGPOSTFIX}.tmp +SM_CMD_ERR=${TMPDIR}/${LOGPREFIX}_SM_CMD_ERR_${LOGPOSTFIX}.tmp +FILESYSTEMS=${TMPDIR}/${LOGPREFIX}_${LOGPOSTFIX}_fs.tmp +PHYS_VOLUMES=${TMPDIR}/${LOGPREFIX}_${LOGPOSTFIX}_hdisk.tmp +VOLGRP=${TMPDIR}/${LOGPREFIX}_${LOGPOSTFIX}_volgrp.tmp + +# Constants +SM_SNAP_PREFIX="snap_" +SM_SNAP_PREFIX_DATA="snap_DATA_" +SM_SNAP_PREFIX_LOG="snap_LOG_" +D="Done." +S="Starting" +D_PATH="DATAPATH_" +L_PATH="LOGPATH_" +DB2BACKUP_LOGS="DB2BACKUP_LOGS" + +# Returncode +RC_PREP_ERROR=40 +RC_SNAP_ERROR=50 +RC_VFY_ERROR=60 +RC_RBCK_ERROR=70 +RC_STORE_METADATA_ERROR=80 +RC_REST_ERROR=90 +RC_DELETE_ERROR=100 +RC_EXPORTVG_ERROR=110 +RC_RECREATEVG_ERROR=120 +RC_BUILD_VGLIST_ERROR=130 +RC_MAPPING_ERROR=140 +RC_TIMEOUT_ERROR=150 + +# Variables +CMD="" +CMD_OUT="" +TIMESTAMP="" +OBJ_HOST="" + +################## +function if_error +################## +# check return code passed to function +# if rc not equal 0 then print error msg, finalize log and exit with latest rc +{ + RC=$? + if [[ $RC -ne 0 ]] + then + write_log "$1 RC=$RC" + finalize_log + exit $RC + fi +} + +################## +function debug_info +################## +# write into log file if DEBUG=X +# +{ + if [[ $DEBUG == "X" ]] + then + write_log "DEBUG: $1" + fi +} + +################## +function check_config_file +################## +# checks if the provided config file is a file +{ + if [ ! -f $config ] + then + write_log " Configuration file: $config is not a file" + RC=1 + fi + return $RC +} + +################## +function init_log +################## +# init the log file +{ + print "=====================================" >> $LOG + print "== Starting customer script =========" >> $LOG + print "=====================================" >> $LOG +} + +################## +function finalize_log +################## +# finalize the log file +{ + print "=====================================" >> $LOG + print "== Ending customer skript ===========" >> $LOG + print "=====================================" >> $LOG +} + +################## +function write_log +################## +# writes messages to the log file +{ + print "$*" >> $LOG +} + +################## +function storeSetting +################## +# writes customer option to protocol file +{ + print "$*" >> $config +} + +################## +function getSetting +################## +# gets options from protocol file +{ + useConfig=$config + if [ "$3" != "" ] + then + useConfig=$3 + fi + cmd="awk -F= '/^${1}/ { print \$2 }' $useConfig | head -1" + _setting=`eval $cmd` + if [ "$2" != "" -a "$_setting" = "" ] + then + _setting=$2 + fi +} + + +function cleanup_tempfiles +################## +# cleans up temp files +{ + debug_info "entry: cleanup_tempfiles" + if [[ $DEBUG == "X" ]] + then + debug_info "In Debug mode do not remove temp files" + debug_info " $TMP $TMP_ $FILESYSTEMS" + else + CMD="rm $TMP $TMP_ $FILESYSTEMS $BGND_RC_FILE $SM_CMD_OUT $SM_CMD_ERR >> $LOG 2>&1" + write_log $S "cleanup temp files ...." + write_log " $CMD" + eval $CMD + if [[ $? -ne 0 ]] + then + write_log " WARNING: the command $CMD failed." + fi + write_log $D + fi + debug_info "exit: cleanup_tempfiles" +} + +function timeout_pid +################## +# kills pid after timeout +# parameter $1 : timeout period in sec +# parameter $2 : PID to watch +{ + debug_info "entry: timeout_pid" + + debug_info "data: TIMEOUT=$1 " + debug_info "data: WATCH_PID=$2 " + TIMEOUT=$1 + WATCH_PID=$2 + DURATION=0 + SLEEPTIME=2 + IS_RUNNING=0 + RC=0 + + # check if process is running + ps -fp $WATCH_PID > /dev/null + if [[ $? -eq 0 ]]; then IS_RUNNING=true; else IS_RUNNING=false; fi + + # wait for process to complete or run into timeout + debug_info "data: entering while loop (sleep $SLEEPTIME)" + while $IS_RUNNING + do + debug_info "data: PID: $WATCH_PID IS_RUNNING: $IS_RUNNING DURATION: $DURATION TIMEOUT: $TIMEOUT" + let 'DURATION = DURATION + SLEEPTIME' + sleep $SLEEPTIME + + # check if still running after sleep time + ps -fp $WATCH_PID > /dev/null + if [[ $? -eq 0 ]]; then IS_RUNNING=true; else IS_RUNNING=false; fi + + # if TIMEOUT is exceeded AND process still runs -> kill it + if [[ $DURATION -gt $TIMEOUT ]] && [[ $IS_RUNNING == "true" ]] + then + write_log " TIMEOUT: $TIMEOUT sec reached. PID $WATCH_PID will be killed..." + kill -9 $WATCH_PID; RC=$? + if [[ $RC -eq 0 ]] + then + write_log " ... PID $WATCH_PID was killed." + IS_RUNNING=false + RC=$RC_TIMEOUT_ERROR + else + write_log " ... Error killing PID $WATCH_PID. " + return $RC + fi + fi + done + debug_info "data: exiting while loop" + + return $RC + debug_info "exit: timeout_pid" +} + +################## +function prepare_delete_command +################## +# checks if the delete command exists +# currently not used +{ + debug_info "entry: prepare_delete_command" + write_log $S "checking delete commands ...." + + write_log $D + debug_info "exit: prepare_delete_command" + return $RC +} + +################## +function prepare_snapshot_command +################## +# checks if the snapshot command exists +{ + debug_info "entry: prepare_snapshot_command" + write_log " checking snapshot commands ...." + RC=0 + + debug_info "data: check if $SMCLI exits." + if [[ -e $SMCLI ]] + then + write_log " $SMCLI exists." + else + write_log " $SMCLI does NOT exist." + RC=$RC_PREP_ERROR + fi + + debug_info "exit: prepare_snapshot_command" + return $RC +} + +################## +function mount_filesystems +################## +# mounts the filesystems in file $FILESYSTEMS +# +{ + debug_info "entry: mount_filesystems" + write_log " mounting filesystems ... " + + TMP_RC=0 + + while read x + do + # set parm1 for the mount command + PARM1=`echo $x | awk '{print $3}'` + + CMD="sudo $MOUNT" + write_log " $CMD ${PARM1}" + eval $CMD ${PARM1} >> $LOG 2>&1 + RC=$? + + if [[ $RC -ne 0 ]] + then + # increment counter, if command did not return 0 + let "TMP_RC = TMP_RC + 1" + write_log " **** ERROR: mount of this filesystem failed." + fi + done < $FILESYSTEMS + + if [[ $TMP_RC -eq 0 ]] + then + write_log " All filesystem mounted. RC=0." + RC=0 + else + write_log " **** ERROR: at least one filesystem was not mounted. RC=$RC_REST_ERROR." + RC=$RC_REST_ERROR + fi + + debug_info "exit: mount_filesystems" + return $RC +} + + +################## +function umount_filesystems +################## +# umounts the filesystems in file $FILESYSTEMS +# before executing umount, check if filesystem is mounted +# +{ + debug_info "entry: umount_filesystems" + write_log " unmount filesystems ... " + TMP_RC=0 + + debug_info "data: sort (reverse) list of filesystems to workaround dependecies" + CMD="mv ${FILESYSTEMS} $TMP" + debug_info "data: executing $CMD" + eval $CMD + if_error "Error: $CMD failed" + + CMD="sort -rk2 $TMP" + debug_info "data: executing $CMD" + eval $CMD > $FILESYSTEMS + if_error "Error: $CMD failed" + + while read x + do + # extract devicename for filesystem from $FILESYSTEMS + PARM1=`echo $x | awk '{print $3}'` + + # check if FS is mounted + CMD="$MOUNT | $GREP" + debug_info "data: $CMD ${PARM1}" + eval $CMD ${PARM1} 2>> $LOG + # eval $CMD ${PARM1} >> $LOG 2>&1 + RC=$? + if [[ $RC -eq 1 ]] then ISMOUNTED="false"; else ISMOUNTED="true"; fi + + debug_info "data: Filesystem ${PARM1} -- ISMOUNTED=$ISMOUNTED" + if [[ $ISMOUNTED == "true" ]] + then + CMD="sudo $UMOUNT" + write_log " $CMD ${PARM1}" + eval $CMD ${PARM1} >> $LOG 2>&1 + RC=$? + + if [[ $RC -ne 0 ]] + then + # increment counter, if command did not return 0 + let "TMP_RC = TMP_RC + 1" + write_log " ... umount of this filesystem failed." + fi + fi + done < $FILESYSTEMS + + if [[ $TMP_RC -eq 0 ]] + then + write_log " All filesystem umounted. RC=0." + RC=0 + else + write_log " **** ERROR: at least one filesystem was not umounted. RC=$RC_REST_ERROR." + RC=$RC_REST_ERROR + fi + + debug_info "exit: umount_filesystems" + return $RC +} + +################## +function export_vgs +################## +# varyoff and export all Volume Groups in $VOLGRP +# (ONLY if list $VOLGRP exists) +# if vg exists, vary off and exportvg +# looks in $FlashCopyTarget for the asssociated backup hdisks and AIX vg names +{ + debug_info "entry: export_vgs" + + TMP_RC=0 + VG_NAME="" + + if [[ -f $VOLGRP ]] + then + while read VG_NAME + do + # only if vg_name currently exists, varyoffvg and exportvg + write_log " varyoff and export Volume Groups..." + debug_info: "data: lsvg $VG_NAME" + CMD="$LSVG $VG_NAME" + eval $CMD > /dev/null 2>&1 + RC=$? + if [[ RC -eq 0 ]] + then + debug_info: "data: varyoffvg $VG_NAME" + CMD="sudo $VARYOFFVG $VG_NAME" + debug_info "data: $CMD" + eval $CMD >> $LOG 2>&1 + RC=$? + if [[ RC -eq 0 ]] + then + CMD="sudo $EXPORTVG $VG_NAME" + debug_info "data: $CMD " + eval $CMD >> $LOG 2>&1 + RC=$? + # if exportvg fails incr error counter + if [[ RC -ne 0 ]] + then + let "TMP_RC = TMP_RC + 1" + write_log " $CMD failed" + else + write_log " $VG_NAME complete" + fi + else + # if varyoffvg fails incr error counter + let "TMP_RC = TMP_RC + 1" + write_log " $CMD failed" + fi + fi + done < $VOLGRP + fi + + # exit if any of the vgs in the list cannot be varied off or exported + # investigate the reason for this manually + if [[ $TMP_RC -eq 0 ]] + then + write_log " All Volume Groups varied off and exported. RC=0." + RC=0 + else + write_log " **** ERROR: at least one Volume group was not exported. RC=$RC_EXPORTVG_ERROR." + write_log " **** Check manually if there are open filesystems on this Volume Group(s)." + return $RC_EXPORTVG_ERROR + fi + debug_info "exit: export_vgs" +} + +################## +function recreate_vgs +################## +# read from list $VOLGRP which AIX Volume Group to recreate +# read from $FlashCopyTarget which hdisk belongs to which VG +# eg. recreatevg -y sapAMT3vg -p -Y NA -L / hdisk6 +{ + debug_info "entry: recreate_vgs" + TMP_RC=0 + while read VG_NAME + do + # get all backup hdisks for one Volumegroup from $FlashCopyTarget + # all hdisks must be in one space separated list created by the awk printf command + CMD="awk -vVG_NAME=$VG_NAME '\$5 == \"$VG_NAME\" { printf \"%s\", \$3; printf \"%c\", \" \" }' $FlashCopyTarget" + debug_info "data: command to create string of hdisks for recreatevg cmd: $CMD" + LOCAL_HDISK_BKP=`eval $CMD` + debug_info "data: hdisk list: $LOCAL_HDISK_BKP" + + CMD="sudo $RECREATEVG -y $VG_NAME -p -Y NA -L / $LOCAL_HDISK_BKP" + debug_info "data: recreatevg: $CMD" + write_log " Recreating VG : $CMD" + eval $CMD >> $LOG 2>&1 + RC=$? + if [[ RC -ne 0 ]] + then + let "TMP_RC = TMP_RC + 1" + write_log " $CMD failed" + fi + done < $VOLGRP + + if [[ TMP_RC -eq 0 ]] + then + write_log " All Volumegroups recreated successfully." + else + write_log " ERROR: At least one Volumegroup could not be recreated." + return $RC_RECREATEVG_ERROR + fi + debug_info "exit: recreate_vgs" +} + +################## +function build_vglist +################## +# build the list of AIX Volume Groups to vary off and export +# reads in each hdisk from $PHYS_VOLUMES, +# looks in protocol file for its Volume Group (key=USER_FC) +# writes out file $VOLGRP +{ + debug_info "entry: build_vglist" + # clear tmp file if exists + if [[ -f $VOLGRP ]]; then CMD="rm $VOLGRP"; eval $CMD; fi + + debug_info "data: restoreConfig= $restoreConfig" + + # build the list of vgs to vary off and export, loop for each hdisk + while read x + do + debug_info "data: reading line $x" + # read original hdisk name from $PHYS_VOLUMES + LOCAL_HDISK_ORI=`echo $x | awk '{print $2}'` + + # get volume group name for each hdisk from protocol file + # keyword=USER_FC, 3rd field = hdisk, 6th field = volumegroup + CMD="awk -F\"=| \" '\$1 == \"$USER_FC\" && \$3 == \"$LOCAL_HDISK_ORI\" { print \$6}' " + debug_info "data: VG_NAME=\`eval $CMD $restoreConfig\`" + VG_NAME=`eval $CMD $restoreConfig` + + # exit if VG_NAME for current LOCAL_HDISK_ORI is not found in protocol file + # If it happens, it means the protocol file incorrect. + # else append the VG to the list $VOLGRP + if [[ -z $VG_NAME ]] + then + write_log " **** ERROR: No Volumegroup name found for $LOCAL_HDISK_ORI in $restoreConfig." + write_log " **** key=$USER_FC. Terminating $0." + return $RC_BUILD_VGLIST_ERROR + else + debug_info "data: Volume Group for $LOCAL_HDISK_ORI is $VG_NAME." + write_log " Adding Volume Group $VG_NAME to list $VOLGRP." + echo $VG_NAME >> $VOLGRP + if_error "Error: $CMD failed" + fi + done < $PHYS_VOLUMES + debug_info "exit: build_vglist" +} + +################## +function restore_pvs +################## +# restore the hdisks (physical volumes = pvs) from flashcopies +{ + debug_info "entry: restore_pvs" + write_log " Restoring pvs in AIX Volume Group ...." + + # build the list of vgs to vary off and export + debug_info "data: restoreConfig $restoreConfig" + build_vglist + if_error "Error: build_vglist failed" + + # varyoff and export volume groups + export_vgs + if_error "Error: export_vgs failed" + + # recreate the vg + recreate_vgs + if_error "Error: recreate_vgs failed" + + debug_info "exit: restore_pvs" +} + +################## +function get_used_filesystems_for_restore +################## +# get the filesystems to be restored from protocol file +# and stores them in $FILESYSTEMS +{ + debug_info "entry: get_used_filesystems_for_restore" + write_log " find the filesystems for restore... " + RC=0 + + getSetting "OBJ_ID" + result_file_no=$_setting + key="RESULT_"${result_file_no}"_FILE" + getSetting $key + restoreConfig=$_setting + + # grep for all snapshots first (data and log) + write_log " looking in $restoreConfig" + write_log " for (keyword=$USER_DB2FS) and and write them to $FILESYSTEMS " + + CMD="awk -F\"=| \" '/^USER_DB2FS/ {print \$2 \" \" \$3 \" \" \$4}' $restoreConfig" + debug_info "data: executing $CMD" + eval $CMD > $FILESYSTEMS + if_error "Error: $CMD failed" + + # if option ACTION = DB2ACS_ACTION_READ_BY_OBJECT -> inlcude log in restore + # if option ACTION = DB2ACS_ACTION_READ_BY_GROUP -> exlcude log from restore + debug_info "data: grep parameter ACTION from $restoreConfig" + getSetting "ACTION" + WHAT_TODO_WITH_LOGS=$_setting + debug_info "data: parameter ACTION is $WHAT_TODO_WITH_LOGS" + + if [[ $WHAT_TODO_WITH_LOGS == "DB2ACS_ACTION_READ_BY_GROUP" ]] + then + # remove the snapped log volumes from the list in $FILESYSTEMS + write_log " LOG volumes are not restored, option ACTION = $WHAT_TODO_WITH_LOGS" + debug_info "data: removing line with ${SM_SNAP_PREFIX_LOG} from $FILESYSTEMS" + + CMD="grep -v ${SM_SNAP_PREFIX_LOG} $FILESYSTEMS" + debug_info "data: $CMD" + eval $CMD > $TMP + if_error "Error: $CMD failed" + + CMD="mv $TMP $FILESYSTEMS" + debug_info "data: $CMD" + eval $CMD + if_error "Error: $CMD failed" + fi + + debug_info "exit: get_used_filesystems_for_restore" +} + +################## +function get_used_pvs_for_restore +################## +# get the physical volumes (hdisks) to be restored from protocol file +# and write them to file $PHYS_VOLUMES +{ + debug_info "entry: get_used_pvs_for_restore" + write_log " Looking for key $USER_FC in $restoreConfig" + + # first look for all backup hdisks (data and log), later remove log if required + write_log " and write them to $PHYS_VOLUMES" + + CMD="awk -F\"=| \" '\$1 == \"$USER_FC\" {print \$2 \" \" \$3 \" \" \$4}' $restoreConfig" + debug_info "data: executing $CMD" + # eval $CMD > $FILESYSTEMS + eval $CMD > $PHYS_VOLUMES + if_error "Error: $CMD failed" + + # if option ACTION = DB2ACS_ACTION_READ_BY_OBJECT -> inlcude log in restore + # if option ACTION = DB2ACS_ACTION_READ_BY_GROUP -> exlcude log from restore + debug_info "data: grep parameter ACTION from $restoreConfig" + getSetting "ACTION" + WHAT_TODO_WITH_LOGS=$_setting + debug_info "data: parameter ACTION is $WHAT_TODO_WITH_LOGS" + + if [[ $WHAT_TODO_WITH_LOGS == "DB2ACS_ACTION_READ_BY_GROUP" ]] + then + # remove the hdisks with logs from the list in $PHYS_VOLUMES + write_log " LOG volumes are not restored, option ACTION = $WHAT_TODO_WITH_LOGS" + debug_info "data: removing line with ${SM_SNAP_PREFIX_LOG} from $PHYS_VOLUMES" + + CMD="grep -v ${SM_SNAP_PREFIX_LOG} $PHYS_VOLUMES" + debug_info "data: $CMD" + eval $CMD > $TMP + if_error "Error: $CMD failed" + + CMD="mv $TMP $PHYS_VOLUMES" + debug_info "data: $CMD" + eval $CMD + if_error "Error: $CMD failed" + fi + debug_info "exit: get_used_pvs_for_restore" +} + +################## +function get_used_pvs_for_backup +################## +# creates a list of all used AIX physical volumes to be backuped up +# reads filesystem names from $FILESYSTEMS +# determines the used hdisks for each filesystem +# and writes them to file $PHYS_VOLUMES +{ + debug_info "entry: get_used_pvs_for_backup" + RC=0 + write_log " Reading filesystems from $FILESYSTEMS..." + + # delete $TMP before using it + debug_info "data: remove file $TMP" + CMD="rm $TMP" + eval $CMD + if_error "Error: $CMD failed" + + debug_info "data: reading from $FILESYSTEMS" + + while read x + do + # parse df -M output with awk to get device names: + # if first character in first field is a "/" -> means it a local filesystem + # if not we assume it is as a NFS filesystem (host:/fs1) + # before output, substitute substring "/dev/" with "" + type=`echo $x | awk '{print $1}'` + fsname=`echo $x | awk '{print $2}'` + + CMD="df -M $fsname | awk '\$1 ~ /^\// { sub(/\/dev\//,\"\",\$1); print \$1 }'" + debug_info "data: CMD: $CMD" + device=`eval $CMD` + if_error "Error: $CMD failed" + debug_info "data: TYPE/DEVICE: $type / $device" + + # get list of pvs for logical volumes + CMD="/usr/sbin/lslv -l $device | awk -v type=$type '\$1 ~ /^hdisk/ {print type \" \" \$1 }'" + debug_info "data: CMD: $CMD" + eval $CMD >> $TMP + if_error "Error: $CMD failed" + debug_info "data: writing the hdisks to $TMP" + + done < $FILESYSTEMS + + if_error "Error: reading or writing $FILESYSTEMS or $TMP" + + debug_info "data: eliminating duplicates in $TMP " + + CMD="sort -u $TMP" + eval $CMD > $PHYS_VOLUMES + if_error "Error: $CMD failed" + + # check for duplicate hdisks, if a duplicate is found, set RC. + # this reveals hdisks with both DATA and LOG files + debug_info "data: check for DATA and LOG not separated" + + awk '{print $2}' $PHYS_VOLUMES | sort -u | while read line + do + debug_info "data: searching for $line" + if [[ `grep -c $line $PHYS_VOLUMES` -ne 1 ]] + then + write_log " ERROR: $line: contains DATA and LOG files" + write_log " ERROR: setting RC=$RC_PREP_ERROR" + RC=$RC_PREP_ERROR + fi + done + + write_log " Storing local hdisks for snapshot in $PHYS_VOLUMES " + debug_info "exit: get_used_pvs_for_backup. RC=$RC" + return $RC +} + + +################## +function get_used_filesystems_for_backup +################## +# creates a list of filesystems to backup +# and writes them to file $FILESYSTEMS +# $FILESYSTEMS has 2 columns: first is identifier DATA or LOG +# second is filesystem name (not mount point) +{ + debug_info "entry: get_used_filesystems_for_backup" + + # look for all entries in $config starting with DATAPATH_ + # label each line with DATA, write to file $TMP + CMD="awk -F= '/^${D_PATH}/ {print \"${SM_SNAP_PREFIX_DATA} \" \$2}' $config" + + write_log " Retrieving db and storage paths from protocol file..." + write_log " writing them to $TMP" + debug_info "data: executing $CMD > $TMP" + eval $CMD > $TMP + if_error "Error: $CMD failed" + write_log $D + + # if logs must be included , then append the file by the log paths + # get setting from config file (DB2BACKUP_LOGS) + debug_info "data: grep parameter DB2BACKUP_LOGS from $config" + getSetting $DB2BACKUP_LOGS + WHAT_TODO_WITH_LOGS=$_setting + + debug_info "data: WHAT_TODO_WITH_LOGS: $WHAT_TODO_WITH_LOGS" + debug_info "data: protocolfile $config" + + if [[ $WHAT_TODO_WITH_LOGS == "INCLUDE" ]] + then + debug_info "data: append log volumes" + # look for lines starting with LOGPATH_ from config file + # label each line with LOG, write to file $TMP + CMD="awk -F= '/^${L_PATH}/ {print \"${SM_SNAP_PREFIX_LOG} \" \$2}' $config" + + write_log $S "Retrieving log paths from protocol file..." + write_log " appending them to $TMP" + debug_info "data: executing $CMD >> $TMP" + eval $CMD >> $TMP + if_error "Error: $CMD failed" + write_log $D + fi + + # read the DB2 path names from file $TMP and extract the filesystem name + # write the filesystm names to file $TMP_ + # no error checking here, we trust in what is delivered by the DB + debug_info "data: reading from $TMP" + while read x + do + TYPE=`echo $x | awk '{print $1}'` + FS_PATH=`echo $x | awk '{print $2}'` + debug_info "data: filessystemname= df -M $FS_PATH | awk '\$2 ~ /^\// { print \$1 }'" + DEVICE=`df -M $FS_PATH | awk '$2 ~ /^\// { print $1 }'` + FS=`df -M $FS_PATH | awk '$2 ~ /^\// { print $2 }'` + echo "$TYPE $DEVICE $FS" + done < $TMP > $TMP_ + + if_error "Error: reading or writing $TMP or $TMP_" + + debug_info "data: writing to $TMP_" + # remove duplicate filesystem entries resulting from db2 query on paths + # a filesystem typically holds many directories and paths + # use sort -u to remove duplicates and save in file $FILESYSTEMS + + debug_info "data: eliminating duplicates in $TMP_ " + CMD="sort -u $TMP_" + eval $CMD > $FILESYSTEMS + if_error "Error: $CMD failed" + debug_info "data: storing filesystem for snapshot in $FILESYSTEMS " + + # save the filesystem also in the protocol file. This is mandatory for restore. + debug_info "data: storing filesystems in current protocol file" + debug_info "data: $config" + + while read x + do + TYPE=`echo $x | awk '{print $1}'` + DEVICE=`echo $x | awk '{print $2}'` + MOUNTPOINT=`echo $x | awk '{print $3}'` + debug_info "data: $USER_DB2FS=$TYPE $MOUNTPOINT $DEVICE" + storeSetting "$USER_DB2FS=$TYPE $MOUNTPOINT $DEVICE" + done < $FILESYSTEMS + + debug_info "exit: get_used_filesystems_for_backup" +} + + +################## +function check_hdisks_available +################## +# reads in the list of local hdisks used for restore. +# The hdisks must be in status "Available" AND NOT in use in any Volume Group +# If they are in a VG and filesystems are mounted, contents +# will be deleted by the drop db command preceeding the next call of the script (doRestore) +{ + debug_info "entry: check_hdisks_available" + write_log " Checking availability of target hdisks" + RC=0 + TMP_RC=0 + LOCAL_HDISK="" + + debug_info "data: reading from file $FlashCopyTarget" + while read x + do + # ignore lines starting with # or empty lines + # third column should be the local hdisk for restore + debug_info "data: Now processing line: $x" + FIRST_COLUMN=`echo $x | awk '{ print $1 }' ` + + if ! [[ $FIRST_COLUMN == "#" || $FIRST_COLUMN == "" ]] + then + debug_info "data: echo $x | awk '{ print \$3 }'" + CMD="echo $x | awk '{ print \$3 }' " + LOCAL_HDISK=`eval $CMD` + + debug_info "data: checking if local hdisk $LOCAL_HDISK is available ..." + debug_info "data: $LSDEV -l $LOCAL_HDISK | awk ' { print \$2 }'" + + # get the status of the LOCAL_HDISK with lsdev command + CMD="$LSDEV -l $LOCAL_HDISK | awk '{ print \$2 }' " + LOCAL_HDISK_STATUS=`eval $CMD` + + # get the Volume Group name of the LOCAL_HDISK with lspv command + CMD="$LSPV ${LOCAL_HDISK} | awk -F: '/VOLUME GROUP/ { sub(/ */,\"\", \$3); print \$3 }'" + LOCAL_VOLGRP=`eval $CMD` + + # if LOCAL_HDISK is Available and NOT assigned to a Volume Group, continue + # else increase error counter TMP_RC + if [[ $LOCAL_HDISK_STATUS == "Available" ]] && [[ -z $LOCAL_VOLGRP ]] + then + write_log " $LOCAL_HDISK: can be used for restore" + else + write_log " $LOCAL_HDISK: can NOT be used. State is not \"Available\" OR is used in VG $LOCAL_VOLGRP" + let "TMP_RC = TMP_RC + 1" + fi + fi + + done < $FlashCopyTarget + + debug_info "data: TMP_RC= $TMP_RC" + debug_info "data: LOCAL_HDISK= $LOCAL_HDISK" + + # return error if error counter TMP_RC is set or LOCAL_HDISK does not exist + if [[ $TMP_RC -ne 0 || LOCAL_HDISK == "" ]] + then + write_log " **** ERROR: At least one local target hdisk can not be used" + write_log " **** ERROR: or no local hdisk was provided in $FlashCopyTarget. RC: $RC_PREP_ERROR" + RC=$RC_PREP_ERROR + else + write_log " All local target hdisks are available. Setting RC: 0." + RC=0 + fi + + debug_info "exit: check_hdisks_available" + return $RC +} + + +################## +function doPrepare +################## +# runs preparation for each script action (snapshot, restore. delete) +{ + debug_info "entry: doPrepare" + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + debug_info "data: checking the config file" + check_config_file + if_error "Error: check_config_file." + + write_log " Using protocol file: $config" + + getSetting "OPERATION" + operation=$_setting + + write_log " preparation for $operation ..." + + case $operation in + "SNAPSHOT") + # prepare for action snapshot + # check needed commands + prepare_snapshot_command + if_error "Error: prepare_snapshot_command failed." + + # get the filesystems and store them in file $FILESYSTEMS + get_used_filesystems_for_backup + + # get the used pvs for backup and store them in file $PHYS_VOLUMES + get_used_pvs_for_backup + if_error "Error: get_used_pvs_for_backup failed." + ;; + "RESTORE") + # prepare for action restore + # check needed commands + prepare_snapshot_command + if_error "Error: prepare_snapshot_command failed." + + # check if target local hdisks are available + check_hdisks_available + if_error "Error: check_hdisks_available failed." + + # copy backup protocol files into place if the repository is empty + # get_used_filesystems_for_restore, umount, restore, mount in doRestore function + ;; + "DELETE") + # prepare for deletion of snapshot images + # check needed commands, currently not used + ;; + *) + # default + write_log " Nothing specific to be prepared." + ;; + esac + + write_log $D + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + + # test to simulate doPrepare failure + # RC=$RC_PREP_ERROR + + finalize_log + debug_info "exit: doPrepare" +} + +################## +function doDelete +################## +# flashcopy snapshots are NOT deleted from the storage system, instead +# they will only be removed from the scripted interface repository +# vital paramters are passed as arguments of the delete call +# from the ACS library +# -o objectID is the object id +# -t is not used in this function in this function +{ + debug_info "entry: doDelete" + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + RC=0 + TMP_RC=0 + IGNORE_RC=0 + + # look for the backup protocol file + debug_info "data: get option RESULT_${objectId}_FILE from current\ + protocol file $config" + key="RESULT_"${objectId}"_FILE" + getSetting $key + deleteConfig=$_setting + + debug_info "data: objectId: ${objectId}" + debug_info "data: deleteConfig: $deleteConfig" + + # look for the snapshot names in the backup protocol file (KEY=USER_FC) + write_log " Retrieving snapshots from protocol file $deleteConfig" + write_log " flashcopy snaphot will be removed from repository:" + CMD="awk -F= '\$1 == \"$USER_FC\" {print \$2 }' $deleteConfig" + debug_info "data: executing $CMD > $TMP" + eval $CMD > $TMP + if_error "Error: $CMD failed" + + debug_info "data: reading from $TMP" + while read x + do + # print name and timestamp of flashcopy snapshot + FC_NAME=`echo $x | awk '{ print $3 }'` + FC_TIMESTAMP=`echo $x | awk '{ print $4 }'` + write_log " $FC_NAME with timestamp $FC_TIMESTAMP" + + done < $TMP + + # cleanup + cleanup_tempfiles + + write_log $D + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + + # test to simulate doDelete failure + # RC=$RC_DELETE_ERROR + + finalize_log + debug_info "exit: doDelete" + return $RC +} + + +################## +function doRestore +################## +# performs the restore of the FlashCopy(ies) +# mapping of Storage Logical Drives, VIO physical hdisks, local hdisks is handled +# externally in file $FC_MAPPING_FILE +{ + debug_info "entry: doRestore" + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + # get_used_filesystems_on_hdisks, umount, restore, mount in restore function + # use $FILESYSTEMS as input + + debug_info "data: get option OBJ_ID from current protocol file $config" + getSetting "OBJ_ID" + result_file_no=$_setting + + debug_info "data: get option RESULT_${result_file_no}_FILE from current\ + protocol file $config" + key="RESULT_"${result_file_no}"_FILE" + getSetting $key + restoreConfig=$_setting + + # unmount all filesystems + get_used_filesystems_for_restore + umount_filesystems + if_error "Error: $CMD failed" + + # restore flashcopied pvs + get_used_pvs_for_restore + restore_pvs + if_error "Error: $CMD failed" + + # mount all filesystems + get_used_filesystems_for_restore + mount_filesystems + if_error "Error: $CMD failed" + + write_log $D + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + finalize_log + + debug_info "exit: doRestore" + # test to simulate doRestore failure + # RC=$RC_REST_ERROR + # return $RC +} + + +################## +function doStoreMetaData +################## +# performs post processing after successful backup +{ + debug_info "entry: doStoreMetaData" + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + # Post Processing Tasks: + # must be executed n both cases, if snapshot ok in Store Metadata + # if NOT in Rollback + # cleanup + cleanup_tempfiles + + # save the protocol file + CMD="cp $config $PROT_BKP_DIR" + write_log " Saving the protocol file $config" + write_log " to $PROT_BKP_DIR" + debig_info "data: $CMD" + eval $CMD >> $LOG + # give a warning instead of ERROR in this phase + + if [[ $? -ne 0 ]] + then + # copy failed, print a warning in $LOG, + write_log " WARNING **** : protocol file could not be saved" + fi + + write_log $D + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + finalize_log + + debug_info "exit: doStoreMetaData" +} + +################## +function doSnapshot +################## +# reads in local hdisks to backup from file $PHYS_VOLUMES +# and creates flashcopy for each entry +{ + debug_info "entry doSnapshot" + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + FC_TIMESTAMP="" + + debug_info "data: reading from $PHYS_VOLUMES" + while read x + do + # name of the FlashCopyLogicalDrive is defined externally + # should contain the TYPE in the name (DATA or lOG) + TYPE=`echo $x | awk '{print $1}'` + LOCAL_HDISK=`echo $x | awk '{print $2}'` + + # look for $LOCAL_HDISK in file $FlashCopyTarget + debug_info "data: awk ' \$1 ~ /^$LOCAL_HDISK/ { print \$2 }' $FlashCopyTarget" + CMD="awk ' \$1 ~ /^$LOCAL_HDISK/ { print \$2 }' $FlashCopyTarget" + FC_LOGICALDRIVE=`eval $CMD` + + # if FC_LOGICALDRIVE was not found, return with error + if [[ -z $FC_LOGICALDRIVE ]] + then + write_log "**** ERROR: no FlashCopyLogicalDrive for $LOCAL_HDISK in $FlashCopyTarget. Terminating $0." + RC=$RC_SNAP_ERROR + return $RC + fi + + # recreate the flashcopy on a prepared storage flashcopy logical drive + debug_info "data: flashcopy of local hdisk $LOCAL_HDISK to fc_logicaldrive $FC_LOGICALDRIVE" + write_log "$S FlashCopy ...." + + SMCLI_RECREATE="$SMCLI $SM_HOST -c 'recreate Flashcopy LogicalDrive [\"$FC_LOGICALDRIVE\"];' -p $SM_PASSWORD" + write_log " recreate Flashcopy LogicalDrive $FC_LOGICALDRIVE" + CMD="sudo $SMCLI_RECREATE 1>$SM_CMD_OUT 2>$SM_CMD_ERR; echo \$?>$BGND_RC_FILE " + debug_info "data: $CMD" + #eval $CMD >> $LOG 2>&1 & + eval $CMD & + timeout_pid 10 $! + if_error "Error: Storage Manager Command exceeded timeout. Exiting $0." + # check rc of flashcopy command + CMD="awk '{print \$1}' $BGND_RC_FILE" + debug_info "data: check RC of backgrounded command in BGND_RC_FILE" + debug_info "data: CMD=$CMD" + if [[ `eval $CMD` -ne 0 ]] + then + write_log " recreate Flashcopy LogicalDrive $FC_LOGICALDRIVE failed. Exiting $0." + write_log " STDERR of last Storage Manager Command:" + write_log " `cat $SM_CMD_ERR`" + write_log " STDOUT of last Storage Manager Command:" + write_log " `cat $SM_CMD_OUT`" + write_log " Exiting $0." + exit $RC_SNAP_ERROR + fi + + # request the flashcopy creation timestamp from the storage manager + debug_info "data: requesting creation timestamp....." + SMCLI_VERIFY="$SMCLI $SM_HOST -c 'show LogicalDrive [\"$FC_LOGICALDRIVE\"];' | awk '/Creation timestamp/ { print \$3 \" \" \$4 \" \" \$5 }' " + CMD="sudo $SMCLI_VERIFY" + debug_info "data: $CMD" + # store the output of the command in CMD_OUT + CMD_OUT=`eval $CMD 2>> $LOG` + RC=$? + if [[ $RC -eq 0 ]] + then + debug_info "data: request returned $CMD_OUT" + FC_TIMESTAMP=`echo $CMD_OUT | sed 's/ /_/g' ` + else + FC_TIMESTAMP="unknown" + fi + + # lookup current Volume Group name of LOCAL_HDISK + CMD="$LSPV ${LOCAL_HDISK} | awk -F: '/VOLUME GROUP/ { sub(/ */,\"\", \$3); print \$3 }'" + VG_NAME=`eval $CMD` + if_error "Error: $CMD failed. Exiting $0." + + # write local hdisk, current volumegroup name, flashcopy logical drive name and + # timestamp to protocol file + debug_info "data: $USER_FC=${TYPE} ${LOCAL_HDISK} ${FC_LOGICALDRIVE} ${FC_TIMESTAMP} ${VG_NAME}" + storeSetting "$USER_FC=${TYPE} ${LOCAL_HDISK} ${FC_LOGICALDRIVE} ${FC_TIMESTAMP} ${VG_NAME}" + write_log $D + + done < $PHYS_VOLUMES + + if_error "Error: Processing Snapshots for Filesystems in $PHYS_VOLUMES failed. " + + # set return code for DB2 backup call + write_log " All snapshots complete. Setting RC=0." + write_log $D. + RC=0; + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + + finalize_log + debug_info "exit: doSnapshot" +} + +################## +function doRollback +################## +# function is called when the preceeding call of the script failed +# in case of prepare: +# - no rollback activity needed +# in case of snapshot: +# - delete the failed snapshot images from protocol files +# - deletion of flashcopy in storage manager must be done manually +# - name and timestamp is provided in the log file $LOG of the script +# in case of verify: +# - delete the failed snapshot images +# in case of storemetadata: +# - remove the backup copy of the protocol file +# in case of restore: +# - try to umount the filesystems, export the Volume Group activated by restore +# in case of delete: +# - to be defined + +{ + debug_info "entry: doRollback" + # init_log + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + # initialize RC + RC=0 + TMP_RC=0 + + # get the failed step. There is only one with RC != 0 + # escape the $1 and $2 in the awk program, this is the field not shell variable + # $1 ~ /...../ && $2 != 0 means: the 1st field must match any of RC_.... + # the 2nd field must be != 0 + + debug_info "data: searching for the failed step in the protocol file" + CMD="awk -F= '\$1 ~ /^RC_PREPARE|^RC_SNAPSHOT|^RC_VERIFY|^RC_RESTORE|^RC_DELETE|\ +^RC_STORE_METADATA/ && \$2 != 0 {print \$1 }' $config" + CMD_OUT=`eval $CMD` + debug_info "data: Executed: $CMD" + + case $CMD_OUT in + "RC_SNAPSHOT" | "RC_VERIFY") + # perform clean up of failed flashcopy snapshot images + # delete all flshcopy snapshot images if doVerify returns an invalid status + write_log " Found: $CMD_OUT is != 0." + write_log " Specific Rollback activities for failed SNAPSHOT, VERIFY" + + write_log $S "listing failed flashcopy snapshot ...." + CMD="awk -F= '\$1 == \"$USER_FC\" { print \$2 }' $config" + eval $CMD > $TMP + + if [[ -s $TMP ]] + then + # if the file $TMP exists and is greater than size 0 + # means that at least one flashcopy snapshot is found for deletion + while read x + do + # print name and timestamp of flashcopy snapshot + FC_NAME=`echo $x | awk '{ print $3 }'` + FC_TIMESTAMP=`echo $x | awk '{ print $4 }'` + + write_log " Manually remove flashcopy snaphot:" + write_log " $FC_NAME with timestamp $FC_TIMESTAMP" + done < $TMP + else + # No flshcopy snapshot found for deletion + write_log " No flashcopy snapshot to be deleted." + fi + ;; + "RC_STORE_METADATA") + # remove the backup copy of the protocol file + write_log " Found: $CMD_OUT is != 0." + write_log " Specific Rollback activities for failed STORE_METADATA" + + # construct path and filename for protocolfile backup + write_log " Removing protocolfile backup..." + CMD="`echo $config | awk -F/ '{print \$NF }'`" + write_log " rm ${PROT_BKP_DIR}$CMD" + eval "rm ${PROT_BKP_DIR}${CMD} 2>> $LOG" + + if [[ $? -ne 0 ]] + then + write_log " WARNING: File ${PROT_BKP_DIR}$CMD could not be removed." + fi + + write_log $D + ;; + "RC_RESTORE") + # umount fs and export backup vgs. + debug_info "entry: case RC_RESTORE" + write_log $S "Trying to unmount and export backup Volume Groups ...." + + # get_used_filesystems_for_restore + umount_filesystems + + if [[ $? -eq 0 ]] + then + debug_info "data: all fs unmounted. " + + # varyoff and export volume groups + export_vgs + if_error "Error: export_vgs failed" + else + write_log " WARNING: Filesystems could not be unmounted " + RC=$RC_RBCK_ERROR + fi + + write_log $D + debug_info "exit: case RC_RESTORE" + ;; + *) + # default, do nothing + write_log " Nothing specific to rollback for failed step: $CMD_OUT" + ;; + esac + + # Post Processing Tasks: + # must be executed n both cases, if snapshot ok in Store Metadata + # if NOT in Rollback + # cleanup + cleanup_tempfiles + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "Ending $0 at $TIMESTAMP ." + finalize_log + + debug_info "exit: doRollback" + return $RC +} + +################## +function doVerify +################## +# verifies the snapshot images created in doSnapshot +# +{ + debug_info "entry: doVerify" + # init_log + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + # initialize global RC variable + RC=0 + + # initialize counter for function return code + TMP_RC=0 + + write_log " verifing all Flashcopies ...." + debug_info "data: reading key $USER_FC from $config and store in $TMP" + CMD="awk -F= '\$1 == \"$USER_FC\" { print \$2 }' $config" + debug_info "data: using command: $CMD" + eval $CMD > $TMP + + debug_info "data: reading FlashCopy LogicalDrive from $TMP" + while read x + do + # prepare SMcli show LogicalDrive command paramter Name + FC_LOGICALDRIVE=`echo $x | awk '{ print $3 }'` + + SMCLI_VERIFY="$SMCLI $SM_HOST -c 'show LogicalDrive [\"$FC_LOGICALDRIVE\"];' | awk '/Status/ { print \$2 }' " + CMD="sudo $SMCLI_VERIFY" + debug_info "data: $CMD" + # store the output of the command in CMD_OUT + CMD_OUT=`eval $CMD 2>> $LOG` + RC=$? + + if [[ $RC -eq 0 ]] + then + if [[ $CMD_OUT == "Optimal" ]]; + then + write_log " Verification of Flashcopy $FC_LOGICALDRIVE succeeded." + fi + else + # increment counter, if command did not return "Optimal" + let "TMP_RC = TMP_RC + 1" + write_log " Verification of Flashcopy $FC_LOGICALDRIVE failed." + fi + + write_log " LogicalDrive Status $FC_LOGICALDRIVE = \"$CMD_OUT\"." + + done < $TMP + + # set the final return code + if [[ $TMP_RC -eq 0 ]] + then + write_log " All snapshots successfully verified." + RC=0 + else + write_log " **** ERROR: at least one snapshot image is not in state: valid. rc=$RC_VFY_ERROR" + RC=$RC_VFY_ERROR + fi + + # test to simulate doVerify failure + # RC=$RC_VFY_ERROR + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + finalize_log + + debug_info "exit: doVerify" + return $RC +} + + +# +# M A I N +# +# -------------------------------------- + +init_log + +debug_info "entry main: parsing of options" + +# COLLECT PARAMS PROVIDED BY DB2 ACS API +# -------------------------------------- + +while getopts a:c:o:t: OPTION +do + case ${OPTION} in + a) action=${OPTARG} + debug_info "data: -a=${OPTARG}" + ;; + c) config=${OPTARG} + debug_info "data: -c=${OPTARG}" + ;; + o) objectId=${OPTARG} + debug_info "data: -o=${OPTARG}" + ;; + t) timestamp=${OPTARG} + debug_info "data: -t=${OPTARG}" + ;; + \?) echo "# Unknown parameter '$1'" + esac +done +debug_info "data: parsing of options done." + +# COLLECT OPTIONS PROVIDED BY THE USER +# IN THE BACKUP COMMAND +# -------------------------------------- +# additional arguments such as and + +debug_info "data: parsing secondary options" +debug_info "data: no. of arguments before shift: $#" + +# OPTIND (von getopts) zaehlt programname mit, $# nicht +shift `expr $OPTIND - 1` +debug_info "data: no. of arguments after shift: $#" + +if [ $# -eq 0 ] # no 2ndary options +then + write_log "no external options from DB2 backup command" +else + # search in the remaining arguments for "FlashCopyTarget=" + debug_info "data: \$*: $*" + for i in $* + do + if [[ "$i" == FlashCopyTarget=* ]] + then + FlashCopyTarget=`echo $i | awk -F= '{ print \$2 }'` + write_log "Found $FlashCopyTarget as secondary option" + fi + done +fi +debug_info "data: parsing secondary options done" + +# exit if Mapping file was not found +if [[ -z $FlashCopyTarget ]] +then + write_log "Specify mapping file in the USE SNAPSHOT clause" + write_log "e.g. ... USE SNAPSHOT ... OPTIONS \"FlashCopyTarget=\" " + write_log "No mapping file found. Exiting." + exit $RC_MAPPING_ERROR +fi + + + +# WORK +# -------------------------------------- + +case "$action" in + prepare) + doPrepare + ;; + snapshot) + doSnapshot + ;; + restore) + doRestore + ;; + delete) + doDelete + ;; + verify) + doVerify + ;; + store_metadata) + doStoreMetaData + ;; + rollback) + doRollback + ;; +esac +debug_info "exit main." +exit $RC + diff --git a/BARVendor/ACS_scripts/dm-1310acs_lvm.sh b/BARVendor/ACS_scripts/dm-1310acs_lvm.sh new file mode 100644 index 0000000..8ebb3c3 --- /dev/null +++ b/BARVendor/ACS_scripts/dm-1310acs_lvm.sh @@ -0,0 +1,371 @@ +#!/bin/sh +#--------------------------------------------------------------------------- +# (c) Copyright IBM Corp. 2013 All rights reserved. +# +# Script Name: dm-1310acs_lvm.sh +# +# Purpose: implement the scripted interface for DB2 ACS using Linux LVM. +# +# Please see developerwork article for details: https://www.ibm.com/developerworks/data/library/techarticle/dm-1310scriptdb2copy2/dm-1310scriptdb2copy2-pdf.pdf +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +#--------------------------------------------------------------------------- + + +# CONSTANTS +######################################################################### +# Possible return codes +RC_OK=0 +RC_COMM_ERROR=2 +RC_INV_ACTION=4 +RC_NOT_ENOUGH_SPACE=28 +RC_DEV_ERROR=18 +RC_INV_DEV_HANDLE=12 +RC_IO_ERROR=25 +RC_ERROR=30 + +RC=$RC_OK + +# HELPER +######################################################################### +# getSetting() +# +# Searches for setting in the protocol file identified +# by its keyword $1 and stores its value in the tmp variable +# _setting +# @param $1 - Setting's keyword +# @param $2 - Default value if setting's keyword was not found +# (optional, if not set $_setting will be empty) +# @param $3 - Configuration file to be opened (optional, if not +# set, $config will be used) +######################################################################## +getSetting() { + useConfig=$config + if [ "$3" != "" ] + then + useConfig=$3 + fi + + cmd="awk -F= '/^${1}/ { print \$2 }' $useConfig | head -1" + _setting=`eval $cmd` + if [ "$2" != "" -a "$_setting" = "" ] + then + _setting=$2 + fi +} + +# storeSetting() +# +# Stores a local variable in the protocol file which can be +# used later using getSetting +# @param $1 Setting's key +# $2 Settings' value +####################################################################### +storeSetting() { + echo "$1=$2" +} + +doPrepare() { +# +# P R E P A R E +# +# -------------------------------------- + freespace=`sudo pvdisplay -c | awk -F":" '{print $10}'` + neededspace=0 + for i in `grep "^DATAPATH" $config | awk -F= '{print $2}' | xargs -I\{\} df \{\} | grep '^/' | awk '{print $1;}' | uniq ` + do + currentspace=`lvdisplay -c $i | awk -F":" '{print $8}'` + neededspace=`expr $neededspace + $currentspace` + done + getSetting "DB2BACKUP_LOGS" + includeLogs=$_setting + if [ $includeLogs = "INCLUDE" -a $RC -eq 0 ] + then + for i in `grep "^LOGPATH" $config | awk -F= '{print $2}' | xargs -I\{\} df \{\} | grep '^/' | awk '{print $1;}' | uniq ` + do + currentspace=`lvdisplay -c $i | awk -F":" '{print $8}'` + neededspace=`expr $neededspace + $currentspace` + done + fi + if [ $neededspace -gt $freespace ] + then + RC=$RC_NOT_ENOUGH_SPACE + fi +# -------------------------------------- +} + +doSnapshot() { +# +# S N A P S H O T +# +# -------------------------------------- + getSetting "TIMESTAMP" + timestamp=$_setting + for i in `grep "^DATAPATH" $config | awk -F= '{print $2}' | xargs -I\{\} df \{\} | grep '^/' | awk '{print $1;}' | uniq ` + do + vol=`sudo lvdisplay -c $i | awk -F: '{print $1;}'` + storeSetting "VOLUME_DATA" $vol + snapName=`basename $vol`_snap_$timestamp + cmd="sudo lvcreate -s -n $snapName -l100%ORIGIN $vol" + $RC=`eval $cmd` + if [ $RC -neq 0 ] + then + echo "# Snapshotting of $vol failed" + break + fi + done + getSetting "DB2BACKUP_LOGS" + includeLogs=$_setting + if [ $includeLogs = "INCLUDE" -a $RC -eq 0 ] + then + for i in `grep "^LOGPATH" $config | awk -F= '{print $2}' | xargs -I\{\} df \{\} | grep '^/' | awk '{print $1;}' | uniq ` + do + vol=`sudo lvdisplay -c $i | awk -F: '{print $1;}'` + storeSetting "VOLUME_LOG" $vol + snapName=`basename $vol`"_snap_"$timestamp + cmd="sudo lvcreate -s -n $snapName -l100%ORIGIN $vol" + $RC=`eval $cmd` + if [ $RC -neq 0 ] + then + echo "# Snapshotting of $vol failed" + break + fi + done + fi +# -------------------------------------- +} + +doRestore() { +# +# R E S T O R E +# +# -------------------------------------- + + getSetting "OBJ_ID" + id=$_setting + # Construct key to search for in currenct protocol file + key="RESULT_"$id"_FILE" + getSetting $key + oldConfig=$_setting + + getSetting "TIMESTAMP" "" $oldConfig + timestamp=$_setting + for i in `grep "^VOLUME_DATA" $oldConfig | awk -F= '{print $2}'` + do + vol=$i"_snap_"$timestamp + echo "# Unmounting volume $vol" + sudo umount -f $i + echo "# Merging volume $vol" + sudo lvconvert --merge --background $vol + if [ $? -neq 0 ] + then + echo "# Deactivating volume $vol" + sudo lvchange -an $i + echo "# Activating volume $vol" + sudo lvchange -ay $i + fi + echo "# Mounting volume $vol" + sudo mount $i + echo "# Take the backup of volume $vol again" + sudo lvcreate -s -n $vol -l100%ORIGIN $i + done + # if logs included + getSetting "ACTION" + readAction=$_setting + if [ $readAction = "DB2ACS_ACTION_READ_BY_OBJECT" ] + then + for i in `grep "^VOLUME_LOG" $oldConfig | awk -F= '{print $2}'` + do + vol=$i"_snap_"${timestamp} + echo "# Umounting volume $vol" + sudo umount -f $i + echo "# Merging volume $vol" + sudo lvconvert --merge --background $vol + if [ $? -neq 0 ] + then + echo "# Deactivating volume $vol" + sudo lvchange -an $i + echo "# Activating volume $vol" + sudo lvchange -ay $i + fi + echo "# Mounting volume $vol" + sudo mount $i + echo "# Take the backup of volume $vol again" + sudo lvcreate -s -n $vol -l100%ORIGIN $i + done + fi +# -------------------------------------- +} + +doDelete() { +# +# D E L E T E +# +# -------------------------------------- + getSetting "RESULT_"${objectId}"_FILE" + oldConfig=$_setting + getSetting "TIMESTAMP" "" $oldConfig + timestamp=$_setting + for i in `grep "^VOLUME_DATA" $oldConfig | awk -F= '{print $2}'` + do + vol=$i"_snap_"${timestamp} + echo "# Volume $vol" + echo "# "`sudo lvremove -f $vol` + done + getSetting "DB2BACKUP_LOGS" "" $oldConfig + includeLogs=$_setting + if [ $includeLogs = "INCLUDE" ] + then + for i in `grep "^VOLUME_LOG" $oldConfig | awk -F= '{print $2}'` + do + vol=$i"_snap_"${timestamp} + echo "# Volume $vol" + echo "# "`sudo lvremove -f $vol` + done + fi + rm $oldConfig +# -------------------------------------- +} + +doVerify() { +# +# V E R I F Y +# +# -------------------------------------- + mkdir /tmp/verify + getSetting "TIMESTAMP" "" $oldConfig + timestamp=$_setting + for i in `grep "^VOLUME_DATA" $config | awk -F= '{print $2}'` + do + vol=$i"_snap_"$timestamp + sudo mount $vol /tmp/verify + $RC=$? + sudo umount /tmp/verify + if [ $RC -neq 0 ] + then + echo "# Mounting of $vol failed" + break + fi + echo "# Volume $i checked" + done + getSetting "DB2BACKUP_LOGS" + includeLogs=$_setting + if [ $includeLogs = "INCLUDE" -a $RC -eq 0 ] + then + for i in `grep "^VOLUME_LOG" $config | awk -F= '{print $2}'` + do + vol=$i"_snap_"$timestamp + sudo mount $vol /tmp/verify + $RC=$? + sudo umount /tmp/verify + if [ $RC -neq 0 ] + then + echo "# Mounting of $vol failed" + break + fi + echo "# Volume $i checked" + done + fi + rmdir /tmp/verify +# -------------------------------------- +} + +doStoreMetaData() { +# +# S T O R E M E T A D A T A +# +# -------------------------------------- +# The snapshot is successful +# The protocol file can be saved, +# only some non important lines will be added + : # noop +# -------------------------------------- +} + +doRollback() { +# +# R O L L B A C K +# +# -------------------------------------- + for i in `grep "^VOLUME_DATA" $config | awk -F= '{print $2}'` + do + sudo lvremove $i_snap_$timestamp + done + getSetting "DB2BACKUP_LOGS" + includeLogs=$_setting + if [ $includeLogs = "INCLUDE" -a $RC -eq 0 ] + then + for i in `grep "^VOLUME_LOG" $config | awk -F= '{print $2}'` + do + sudo lvremove $i_snap_$timestamp + done + fi +# -------------------------------------- +} + + +# +# M A I N +# +# -------------------------------------- +# COLLECT PARAMS +# -------------------------------------- +while getopts a:c:o:t: OPTION +do + case ${OPTION} in + a) action=${OPTARG} + ;; + c) config=${OPTARG} + ;; + o) objectId=${OPTARG} + ;; + t) timestamp=${OPTARG} + ;; + \?) echo "# Unknown parameter '$1'" + esac +done + +repository="`dirname $config`/" + +# WORK +# -------------------------------------- + +case "$action" in + prepare) + doPrepare + ;; + snapshot) + doSnapshot + ;; + restore) + doRestore + ;; + delete) + doDelete + ;; + verify) + doVerify + ;; + store_metadata) + doStoreMetaData + ;; + rollback) + doRollback + ;; +esac + +exit $RC diff --git a/BARVendor/ACS_scripts/dm-1311acs_gpfs.sh b/BARVendor/ACS_scripts/dm-1311acs_gpfs.sh new file mode 100644 index 0000000..3787950 --- /dev/null +++ b/BARVendor/ACS_scripts/dm-1311acs_gpfs.sh @@ -0,0 +1,1178 @@ +#!/usr/bin/ksh +#--------------------------------------------------------------------------- +# (c) Copyright IBM Corp. 2012 All rights reserved. +# +# Script Name: dm-1311acs_gpfs.sh +# +# Purpose: implement the scripted interface for DB2 ACS using IBM GPFS.This +# script is called by DB2 to make GPFS snapshot backups of paths +# provided by DB2. +# +# Please see developerwork article for details: https://www.ibm.com/developerworks/data/library/techarticle/dm-1311scriptdb2copy3/dm-1311scriptdb2copy3-pdf.pdf +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +#--------------------------------------------------------------------------- + + +# print out debug info +# set X for Debug, +# DEBUG=X + +# GPFS path and exes +GPFSINST=/usr/lpp/mmfs +GPFSBIN=$GPFSINST/bin +GPFSSNAP=$GPFSBIN/mmcrsnapshot +GPFSVFY=$GPFSBIN/mmlssnapshot +GPFSDEL=$GPFSBIN/mmdelsnapshot +GPFSREST=$GPFSBIN/mmrestorefs +GPFSMOUNT=$GPFSBIN/mmmount +GPFSUMOUNT=$GPFSBIN/mmumount + +# Log file +LOGPREFIX="gpfs_snap" +LOGPOSTFIX="BWP" +LOG=/tmp/${LOGPREFIX}_${LOGPOSTFIX}.log + +# Protocol Backup directory +PROT_BKP_DIR="/db2/db2bwp/scriptACS/prot_bkp/" + +# User defined entries in the protocol file +USER_GPFSSNAP="USER_GPFSSNAP" + +# Tempfile names +TMPDIR=/tmp +TMP=${TMPDIR}/${LOGPREFIX}_${LOGPOSTFIX}.tmp +TMP_=${TMPDIR}/${LOGPREFIX}_${LOGPOSTFIX}.tmp_ +FILESYSTEMS=${TMPDIR}/${LOGPREFIX}_${LOGPOSTFIX}_fs.tmp + +# Constants +GPFS_SNAP_PREFIX="snap_" +GPFS_SNAP_PREFIX_DATA="snap_DATA_" +GPFS_SNAP_PREFIX_LOG="snap_LOG_" +D="Done." +S="Starting" +D_PATH="DATAPATH_" +L_PATH="LOGPATH_" +DB2BACKUP_LOGS="DB2BACKUP_LOGS" + +# Returncode +RC_OK=0 +RC_COMM_ERROR=2 +RC_INV_ACTION=4 +RC_NOT_ENOUGH_SPACE=28 +RC_DEV_ERROR=18 +RC_INV_DEV_HANDLE=12 +RC_IO_ERROR=25 +RC_ERROR=30 +RC_PREP_ERROR=40 +RC_SNAP_ERROR=50 +RC_VFY_ERROR=60 +RC_RBCK_ERROR=70 +RC_STORE_METADATA_ERROR=80 +RC_REST_ERROR=90 +RC_DELETE_ERROR=100 + +# Variables +CMD="" +CMD_OUT="" +TIMESTAMP="" +GPFS_PARM1="" +GPFS_PARM2="" +GPFS_SNAP_STATUS="" +VOLUMEGROUPS="" +LUNID="" +OBJ_HOST="" + +################## +function if_error +################## +# check return code passed to function +# if rc not equal 0 then print error msg, finalize log and exit with latest rc +{ + RC=$? + if [[ $RC -ne 0 ]] + then + #print "$1 RC=$RC" | tee -a $LOG + write_log "$i RC=$RC" + + finalize_log + exit $RC + fi +} + +################## +function debug_info +################## +# write into log file if DEBUG=X +# +{ + if [[ $DEBUG == "X" ]] + then + write_log "DEBUG: $1" + fi +} + +################## +function check_config_file +################## +# checks if the provided config file is a file +{ + if [ ! -f $config ] + then + write_log " Configuration file: $config is not a file" + RC=1 + fi + return $RC +} + +################## +function init_log +################## +# init the log file +{ + print "=====================================" >> $LOG + print "== Starting customer script =========" >> $LOG + print "=====================================" >> $LOG +} + +################## +function finalize_log +################## +# finalize the log file +{ + print "=====================================" >> $LOG + print "== Ending customer skript ===========" >> $LOG + print "=====================================" >> $LOG +} + +################## +function write_log +################## +# writes messages to the log file +{ + print "$*" >> $LOG +} + +################## +function storeSetting +################## +# writes customer option to protocol file +{ + print "$*" >> $config +} + +################## +function getSetting +################## +# gets options from protocol file +{ + useConfig=$config + if [ "$3" != "" ] + then + useConfig=$3 + fi + cmd="awk -F= '/^${1}/ { print \$2 }' $useConfig | head -1" + _setting=`eval $cmd` + if [ "$2" != "" -a "$_setting" = "" ] + then + _setting=$2 + fi +} + +################## +function cleanup_tempfiles +################## +# cleans up temp files +{ + debug_info "entry: cleanup_tempfiles" + CMD="rm $TMP $TMP_ $FILESYSTEMS >> $LOG 2>&1" + write_log $S "cleanup temp files ...." + write_log " $CMD" + eval $CMD + if [[ $? -ne 0 ]] + then + write_log " WARNING: the command $CMD failed." + fi + write_log $D + debug_info "exit: cleanup_tempfiles" +} + +################## +function prepare_restore_command +################## +# checks if the restore command exists +{ + debug_info "entry: prepare_restore_command" + write_log $S "checking restore commands ...." + TMP_RC=0 + RC=0 + + for i in $GPFSREST $GPFSMOUNT $GPFSUMOUNT + do + debug_info "data: check if $i exits." + if [[ -e $i ]] + then + write_log " $i exists." + else + write_log " $i does NOT exist." + let "TMP_RC = TMP_RC + 1" + fi + done + + # set the final return code + if [[ $TMP_RC -ne 0 ]] + then + write_log " At least one GPFS command is missing." + RC=$RC_PREP_ERROR + fi + + write_log $D + debug_info "exit: prepare_restore_command" + return $RC +} + +function prepare_delete_command +################## +# checks if the delete command exists +{ + debug_info "entry: prepare_delete_command" + write_log $S "checking delete commands ...." + TMP_RC=0 + RC=0 + + for i in $GPFSDEL + do + debug_info "data: check if $i exits." + if [[ -e $i ]] + then + write_log " $i exists." + else + write_log " $i does NOT exist." + let "TMP_RC = TMP_RC + 1" + fi + done + + # set the final return code + if [[ $TMP_RC -ne 0 ]] + then + write_log " At least one GPFS command is missing." + RC=$RC_PREP_ERROR + fi + + write_log $D + debug_info "exit: prepare_delete_command" + return $RC +} + +################## +function prepare_snapshot_command +################## +# checks if the snapshot command exists +{ + debug_info "entry: prepare_snapshot_command" + write_log $S "checking snapshot commands ...." + TMP_RC=0 + RC=0 + + for i in $GPFSSNAP $GPFSVFY $GPFSDEL + do + debug_info "data: check if $i exits." + if [[ -e $i ]] + then + write_log " $i exists." + else + write_log " $i does NOT exist." + let "TMP_RC = TMP_RC + 1" + fi + done + + # set the final return code + if [[ $TMP_RC -ne 0 ]] + then + write_log " At least one GPFS command is missing." + RC=$RC_PREP_ERROR + fi + + write_log $D + debug_info "exit: prepare_snapshot_command" + return $RC +} + +################## +function mount_filesystems +################## +# mounts the GPFS devices/filesystems in file $FILESYSTEMS +# +{ + debug_info "entry: mount_filesystems" + write_log $S "GPFS mnount ... " + + TMP_RC=0 + + while read x + do + # set parm1 for the GPFS mount command + GPFS_PARM1=`echo $x | awk '{print $1}'` + # set parm2 for the GPFS mount command + GPFS_PARM2="-a" + + CMD="sudo $GPFSMOUNT" + write_log " $CMD ${GPFS_PARM1} ${GPFS_PARM2}" + eval $CMD ${GPFS_PARM1} ${GPFS_PARM2} >> $LOG 2>&1 + RC=$? + + if [[ $RC -ne 0 ]] + then + # increment counter, if command did not return 0 + let "TMP_RC = TMP_RC + 1" + write_log " **** ERROR: mount of this filesystem failed." + fi + done < $FILESYSTEMS + + if [[ $TMP_RC -eq 0 ]] + then + write_log " All filesystem mounted. RC=0." + RC=0 + else + write_log " **** ERROR: at least one filesystem was not mounted. RC=$RC_REST_ERROR." + RC=$RC_REST_ERROR + fi + + write_log $D + debug_info "exit: mount_filesystems" + return $RC +} + + +################## +function umount_filesystems +################## +# umounts the GPFS devices/filesystems in file $FILESYSTEMS +# +{ + debug_info "entry: umount_filesystems" + write_log $S "GPFS umnount ... " + + TMP_RC=0 + + while read x + do + # set parm1 for the GPFS umount command + GPFS_PARM1=`echo $x | awk '{print $1}'` + # set parm2 for the GPFS umount command + GPFS_PARM2="-a" + + CMD="sudo $GPFSUMOUNT" + write_log " $CMD ${GPFS_PARM1} ${GPFS_PARM2}" + eval $CMD ${GPFS_PARM1} ${GPFS_PARM2} >> $LOG 2>&1 + RC=$? + + if [[ $RC -ne 0 ]] + then + # increment counter, if command did not return 0 + let "TMP_RC = TMP_RC + 1" + write_log " ... umount of this filesystem failed." + fi + done < $FILESYSTEMS + + if [[ $TMP_RC -eq 0 ]] + then + write_log " All filesystem umounted. RC=0." + RC=0 + else + write_log " **** ERROR: at least one filesystem was not umounted. RC=$RC_REST_ERROR." + RC=$RC_REST_ERROR + fi + + write_log $D + debug_info "exit: umount_filesystems" + return $RC +} + + +################## +function restore_filesystems +################## +# restore the filesystems from snapshots +# uses $FILESYSTEMS +# function tries to restore all required filesystems. If an error occurs +# during the restorefs command the next filesystem is processed. +# This gives the user the possibility to fix all errors (e.g out of space errors) +# at once, instead of repeating the restore several time and fix the errors one by one +{ + debug_info "entry: restore_filesystems" + write_log $S "GPFS restore from snapshot ...." + TMP_RC=0 + + while read x + do + # set parm1 and parm2 for the GPFS mmrestorefs command + GPFS_PARM1=`echo $x | awk '{print $1}'` + GPFS_PARM2=`echo $x | awk '{print $2}'` + + CMD="sudo $GPFSREST" + write_log " $CMD ${GPFS_PARM1} ${GPFS_PARM2}" + eval $CMD ${GPFS_PARM1} ${GPFS_PARM2} >> $LOG 2>&1 + RC=$? + + if [[ $RC -ne 0 ]] + then + # increment counter, if command did not return "Valid" + let "TMP_RC = TMP_RC + 1" + write_log " **** ERROR: restore of this snapshot failed." + fi + done < $FILESYSTEMS + + if [[ $TMP_RC -eq 0 ]] + then + write_log " All restores from snapshot complete. Setting RC=0." + RC=0 + else + write_log " **** ERROR: at least one snapshot was not restored. rc=$RC_REST_ERROR" + RC=$RC_REST_ERROR + fi + + write_log $D + debug_info "exit: restore_filesystems" + return $RC +} + +################## +function get_used_filesystems_for_restore +################## +# get the fs for restore from the protocol file of the selected backup +# grep for all entries starting with USER_GPFSSNAP +{ + debug_info "entry: get_used_filesystems_for_restore" + write_log $S "build the protocol file name to use for the restore... " + RC=0 + + getSetting "OBJ_ID" + result_file_no=$_setting + key="RESULT_"${result_file_no}"_FILE" + getSetting $key + restoreConfig=$_setting + + # grep for all snapshots first (data and log) + write_log " looking for GPFS devices / filesystem to restore in: $restoreConfig " + write_log " and write them to $FILESYSTEMS" + + CMD="awk -F= '/^USER_GPFSSNAP/ {print \$2}' $restoreConfig" + debug_info "data: executing $CMD" + eval $CMD > $FILESYSTEMS + if_error "Error: $CMD failed" + + # if option ACTION = DB2ACS_ACTION_READ_BY_OBJECT -> inlcude log in restore + # if option ACTION = DB2ACS_ACTION_READ_BY_GROUP -> exlcude log from restore + + debug_info "data: grep parameter ACTION from $restoreConfig" + getSetting "ACTION" + WHAT_TODO_WITH_LOGS=$_setting + debug_info "data: parameter ACTION is $WHAT_TODO_WITH_LOGS" + + if [[ $WHAT_TODO_WITH_LOGS == "DB2ACS_ACTION_READ_BY_GROUP" ]] + then + # remove the snapped log volumes form the list in $FILESYSTEMS + write_log " LOG volumes are not restored, option ACTION = $WHAT_TODO_WITH_LOGS" + debug_info "data: removing line with ${GPFS_SNAP_PREFIX_LOG} from $FILESYSTEMS" + + CMD="grep -v ${GPFS_SNAP_PREFIX_LOG} $FILESYSTEMS" + debug_info "data: $CMD" + eval $CMD > $TMP + if_error "Error: $CMD failed" + + CMD="mv $TMP $FILESYSTEMS" + debug_info "data: $CMD" + eval $CMD + if_error "Error: $CMD failed" + fi + + write_log $D + debug_info "exit: get_used_filesystems_for_restore" + +} + +################## +function get_used_filesystems_for_backup +################## +# creates a list of filesystems for backup +# and writes them to file $FILESYSTEMS +{ + debug_info "entry: get_used_filesystems_for_backup" + + # grep all entries in $config starting with DATAPATH_ + CMD="awk -F= '/^${D_PATH}/ {print \"DATA \" \$2}' $config" + + write_log $S "Retrieving db and storage paths from protocol file..." + write_log " writing them to $TMP" + debug_info "data: executing $CMD > $TMP" + eval $CMD > $TMP + if_error "Error: $CMD failed" + write_log $D + + # if logs must be included , then append the file by the log paths + # get setting from config file (DB2BACKUP_LOGS) + debug_info "data: grep parameter DB2BACKUP_LOGS from $config" + getSetting $DB2BACKUP_LOGS + WHAT_TODO_WITH_LOGS=$_setting + + debug_info "data: WHAT_TODO_WITH_LOGS: $WHAT_TODO_WITH_LOGS" + debug_info "data: protocolfile $config" + + if [[ $WHAT_TODO_WITH_LOGS == "INCLUDE" ]] + then + debug_info "data: append log volumes" + # grep lines starting with LOGPATH_ from config file + # label each line with LOG + CMD="awk -F= '/^${L_PATH}/ {print \"LOG \" \$2}' $config" + + write_log $S "Retrieving log paths from protocol file..." + write_log " appending them to $TMP" + debug_info "data: executing $CMD >> $TMP" + eval $CMD >> $TMP + if_error "Error: $CMD failed" + write_log $D + fi + + # read the DB2 path names from file $TMP and extract the filesystem name + # write the filesystm names to file $TMP_ + # no error checking here, we trust in what is delivered by the DB + + debug_info "data: reading from $TMP" + + while read x + do + type=`echo $x | awk '{print $1}'` + path=`echo $x | awk '{print $2}'` + debug_info "data: filessystemname= df -M $path | awk '\$2 ~ /^\// { print \$1 }'" + device=`df -M $path | awk '$2 ~ /^\// { print $1 }'` + echo "$type $device" + done < $TMP > $TMP_ + + if_error "Error: reading or writing $TMP or $TMP_" + + debug_info "data: writing to $TMP_" + + # remove duplicate filesystem entries resulting from db2 query on paths + # a filesystem typically holds many directories and paths + # use sort -u to remove duplicates and save in file $FILESYSTEMS + + debug_info "data: eliminating duplicates in $TMP_ " + CMD="sort -u $TMP_" + eval $CMD > $FILESYSTEMS + if_error "Error: $CMD failed" + debug_info "data: storing filesystem for snapshot in $FILESYSTEMS " + + debug_info "exit: get_used_filesystems_for_backup" +} + +################## +function doPrepare +################## +# reads in file and paths to be backed up from DB2 +# maps files and paths to a unique list of filesystems +# checks if snapshot command is available +# reads in backup option in/exclude logs +{ + debug_info "entry: doPrepare" + init_log + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + debug_info "data: checking the config file" + check_config_file + if_error "Error: check_config_file." + + write_log "Using $config..." + + getSetting "OPERATION" + operation=$_setting + + write_log "$S preparation for $operation ..." + + case $operation in + "SNAPSHOT") + # prepare for snapshot + # check needed GPFS commands + prepare_snapshot_command + if_error "Error: prepare_snapshot_command failed." + + # get the filesystems and store them in file $FILESYSTEMS + get_used_filesystems_for_backup + ;; + "RESTORE") + # prepare for restore + # check needed commands + prepare_restore_command + if_error "Error: prepare_restore_command failed." + + # copy backup protocol files into place if the repository is empty + # get_used_filesystems_for_restore, umount, restore, mount in doRestore function + ;; + "DELETE") + # prepare for deletion of snapshot images + # check needed commands + prepare_delete_command + if_error "Error: prepare_delete_command failed." + ;; + *) + # default + write_log " Nothing specific to be prepared." + ;; + esac + + write_log $D + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + + # test to simulate doPrepare failure + # RC=$RC_PREP_ERROR + + finalize_log + debug_info "exit: doPrepare" +} + +################## +function doDelete +################## +# deletes the GPFS snapshots linked to a backup image +# vital paramters are passed as arguments of the delete call +# from the ACS library +# -o objectID is the object id +# -t is not used in this function in this function +{ + debug_info "entry: doDelete" + init_log + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + RC=0 + TMP_RC=0 + IGNORE_RC=0 + + debug_info "data: grep the option RESULT_${objectId}_FILE from current\ + protocol file $config" + key="RESULT_"${objectId}"_FILE" + getSetting $key + deleteConfig=$_setting + + debug_info "data: objectId: ${objectId}" + debug_info "data: deleteConfig: $deleteConfig" + + # for all lines starting with USER_GPFSSNAP, get the GPFS device name + # and the snapshotname + CMD="awk -F= '/^USER_GPFSSNAP/ {print \$2\" \"\$3}' $deleteConfig" + + write_log $S "Retrieving GPFS snapshots from protocol file..." + write_log " writing them to $TMP" + debug_info "data: executing $CMD > $TMP" + eval $CMD > $TMP + if_error "Error: $CMD failed" + + debug_info "data: reading from $TMP" + while read x + do + # set parm1 and parm2 for the GPFS commands + GPFS_PARM1=`echo $x | awk '{print $1}'` + GPFS_PARM2=`echo $x | awk '{print $2}'` + + # if snap image exists exists evaluate RC (normal delete) + # if not ignore RC (cleanup delete) + CMD="sudo $GPFSVFY" + write_log " $CMD ${GPFS_PARM1} -s ${GPFS_PARM2}" + eval $CMD ${GPFS_PARM1} -s ${GPFS_PARM2} >> $LOG 2>&1 + RC=$? + if [[ $RC -ne 0 ]] + then + write_log " Snap does not exist. Ignoring the following $GPFSDEL error." + IGNORE_RC=1 + fi + + CMD="sudo $GPFSDEL" + write_log " $CMD ${GPFS_PARM1} ${GPFS_PARM2}" + eval $CMD ${GPFS_PARM1} ${GPFS_PARM2} >> $LOG 2>&1 + RC=$? + + debug_info "data: RC: $RC and IGNORE_RC:$IGNORE_RC" + if [[ $RC -ne 0 ]] && [[ $IGNORE_RC -eq 0 ]] + then + # increment counter, if command did not return 0 + let "TMP_RC = TMP_RC + 1" + debug_info "data: normal delete, report errors." + write_log " WARNING **** : Can't delete this snapshot:" + write_log " ${GPFS_PARM1} ${GPFS_PARM2}" + fi + + # reset the variable for next iteration + IGNORE_RC=0 + done < $TMP + + if [[ $TMP_RC -eq 0 ]] + then + write_log " All snapshots deleted. Setting RC: 0." + RC=0 + else + write_log " Error *****: At least one snapshot was not deleted. RC: $RC_DELETE_ERROR" + RC=$RC_DELETE_ERROR + fi + + # cleanup + cleanup_tempfiles + + write_log $D + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + + # test to simulate doDelete failure + # RC=$RC_DELETE_ERROR + + finalize_log + debug_info "exit: doDelete" + return $RC +} + + + +################## +function doRestore +################## +# performs thre restore of GPFS snapshots +{ + debug_info "entry: doRestore" + init_log + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + # get_used_filesystems_for_restore, umount, restore, mount in restore function + # use $FILESYSTEMS as input + + debug_info "data: grep the option OBJ_ID from current protocol file $config" + getSetting "OBJ_ID" + result_file_no=$_setting + + debug_info "data: grep the option RESULT_${result_file_no}_FILE from current\ + protocol file $config" + key="RESULT_"${result_file_no}"_FILE" + getSetting $key + restoreConfig=$_setting + + debug_info "data: calling get_used_filesystems_for_restore " + get_used_filesystems_for_restore + + # unmount all + umount_filesystems + if_error "Error: $CMD failed" + + restore_filesystems + if_error "Error: $CMD failed" + + # mount all + mount_filesystems + if_error "Error: $CMD failed" + + write_log $D + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + finalize_log + + # test to simulate doRestore failure + # RC=$RC_STORE_REST_ERROR + + debug_info "exit: doRestore" +} + + +################## +function doStoreMetaData +################## +# performs post processing after successful backup +{ + debug_info "entry: doStoreMetaData" + init_log + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + # Post Processing Tasks: + # must be executed n both cases, if snapshot ok in Store Metadata + # if NOT in Rollback + # cleanup + cleanup_tempfiles + + # save the protocol file + CMD="cp $config $PROT_BKP_DIR" + write_log "Starting saving the protocol file to another directory" + write_log " $CMD" + eval $CMD >> $LOG + # give a warning instead of ERROR in this phase + + if [[ $? -ne 0 ]] + then + # copy failed, print a warning in $LOG, + write_log " WARNING **** : protocol file could not be saved" + fi + + write_log $D + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + finalize_log + + debug_info "exit: doStoreMetaData" +} + +################## +function doSnapshot +################## +# reads in filesystems to backup from file $FILESYSTEMS +# an makes GPFS snapshot for each entry +{ + debug_info "entry doSnapshot" + init_log + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + debug_info "data. reading from $FILESYSTEMS" + while read x + do + # remove the /dev from the 2nd filed in each line and use as parm1 + # parm1 = name of the gpfs filesystem + GPFS_PARM1=`echo $x | awk '{print $2}' | sed 's/^\/dev\///'` + + # generate name for snapshot and use as parm2 + # different snapshotnames for log and sapdata filesystems + # TYPE can be DATA or LOG + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + TYPE=`echo $x | awk '{print $1"_"}'` + GPFS_PARM2=${GPFS_SNAP_PREFIX}${TYPE}${TIMESTAMP} + + write_log "$S GPFS snapshot ...." + CMD="sudo $GPFSSNAP" + write_log " $CMD ${GPFS_PARM1} ${GPFS_PARM2}" + eval $CMD ${GPFS_PARM1} ${GPFS_PARM2} >> $LOG 2>&1 + + if_error "Error: $CMD ${GPFS_PARM1} ${GPFS_PARM2} failed. Exiting $0." + + storeSetting "USER_GPFSSNAP=${GPFS_PARM1} ${GPFS_PARM2}" + + write_log $D + + done < $FILESYSTEMS + + if_error "Error: Processing Snapshots for Filesystems in $FILESYSTEMS failed. " + + # set return code for DB2 backup call + write_log " All snapshots complete. Setting RC=0." + RC=0; + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + + finalize_log + debug_info "exit: doSnapshot" +} + +################## +function doRollback +################## +# function is called when the preceeding call of the script failed +# in case of prepare: +# - no rollback activity needed +# in case of snapshot: +# - delete the failed snapshot images +# in case of verify: +# - delete the failed snapshot images +# in case of storemetadata: +# - remove the backup copy of the protocol file +# in case of restore: +# - try to mount the filesystem again. The user can then repeat another +# restore without having to manually mount the db filesystems +# in case of delete: +# - to be defined + +{ + debug_info "entry: doRollback" + init_log + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + # initialize RC + RC=0 + TMP_RC=0 + + # get the failed step. There is only one with RC != 0 + # escape the $1 and $2 in the awk program, this is the field not shell variable + # $1 ~ /...../ && $2 != 0 means: the 1st field must match any of RC_.... + # the 2nd field must be != 0 + + write_log "Searching for the failed step in the protocol file..." + CMD="awk -F= '\$1 ~ /^RC_PREPARE|^RC_SNAPSHOT|^RC_VERIFY|^RC_RESTORE|^RC_DELETE|\ +^RC_STORE_METADATA/ && \$2 != 0 {print \$1 }' $config" + CMD_OUT=`eval $CMD` + debug_info "data: Executed: $CMD" + + case $CMD_OUT in + "RC_SNAPSHOT" | "RC_VERIFY") + # perform clean up of failed GPFS snapshot images + # delete all GPFS snapshot images if doVerify returns an invalid status + write_log "Found: $CMD_OUT is != 0." + write_log "Specific Rollback activities for failed SNAPSHOT, VERIFY" + + write_log $S "deleting failed GPFS snapshot ...." + CMD="awk -F= '/^USER_GPFSSNAP/ { print \$2 }' $config" + eval $CMD > $TMP + + if [[ -s $TMP ]] + then + # if the file $TMP exists and is greater than size 0 + # means that at least one GPFS snapshot is found for deletion + while read x + do + # prepare GPFS command paramters Device and Snapshotname + GPFS_PARM1=`echo $x | awk '{ print $1 }'` + GPFS_PARM2=`echo $x | awk '{ print $2 }'` + + CMD="sudo $GPFSDEL ${GPFS_PARM1} ${GPFS_PARM2}" + write_log " $CMD" + eval $CMD 2>> $LOG + RC=$? + + if [[ $RC -ne 0 ]] + then + # increment counter, if command failed in the loop + let "TMP_RC = TMP_RC + 1" + write_log " ... Deletion of snapshot failed." + fi + done < $TMP + + + # set the final return code + if [[ $TMP_RC -eq 0 ]] + then + write_log " All snapshots successfully deleted. " + RC=0 + else + write_log " **** ERROR: at least one snapshot image could not\ + be deleted. rc=$RC_RBCK_ERROR" + RC=$RC_RBCK_ERROR + fi + + else + # No GPFS snapshot found for deletion + write_log " No GPFS snapshot to be deleted." + fi + + ;; + "RC_STORE_METADATA") + # remove the backup copy of the protocol file + write_log "Found: $CMD_OUT is != 0." + write_log "Specific Rollback activities for failed STORE_METADATA" + + # construct path and filename for protocolfile backup + write_log " Removing protocolfile backup..." + CMD="`echo $config | awk -F/ '{print \$NF }'`" + write_log " rm ${PROT_BKP_DIR}$CMD" + eval "rm ${PROT_BKP_DIR}${CMD} 2>> $LOG" + + if [[ $? -ne 0 ]] + then + write_log " WARNING: File ${PROT_BKP_DIR}$CMD could not be removed." + fi + + write_log $D + + ;; + "RC_RESTORE") + # try to mount the filesystems again. This gives the user the chance to + # repeat the restore without having to mount the filesystems manually + debug_info "entry: case RC_RESTORE" + + write_log " Trying to mount filesystems again...." + mount_filesystems + if [[ $? -ne 0 ]] + then + write_log " WARNING: Filesystems could not be mounted " + RC=$RC_RBCK_ERROR + fi + + write_log $D + + debug_info "exit: case RC_RESTORE" + + ;; + *) + # default, do nothing + write_log "Nothing specific to rollback for failed step: $CMD_OUT" + ;; + esac + + # Post Processing Tasks: + # must be executed n both cases, if snapshot ok in Store Metadata + # if NOT in Rollback + # cleanup + write_log "Default rollback activities:" + cleanup_tempfiles + + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + finalize_log + + debug_info "exit: doRollback" + return $RC +} + +################## +function doVerify +################## +# verifies the snapshot images created in doSnapshot +# +{ + debug_info "entry: doVerify" + init_log + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "$S $0 at $TIMESTAMP ." + + # initlaize global RC variable + RC=0 + + # initialize counter for function return code + TMP_RC=0 + + write_log $S "verify GPFS snapshot ...." + debug_info "data: writing GPFS snapshotnames to verify to $TMP" + CMD="awk -F= '/^USER_GPFSSNAP/ { print \$2 }' $config" + debug_info "data: using command: $CMD" + eval $CMD > $TMP + + debug_info "data: reading from $TMP" + while read x + do + # prepare GPFS command paramters Device and Snapshotname + GPFS_PARM1=`echo $x | awk '{ print $1 }'` + GPFS_PARM2=`echo $x | awk '{ print $2 }'` + + CMD="sudo $GPFSVFY ${GPFS_PARM1} -s ${GPFS_PARM2}" + write_log " $CMD" + + # store the output of the command in CMD_OUT + CMD_OUT=`eval $CMD 2>> $LOG` + RC=$? + + if [[ $RC -eq 0 ]] + then + # check the result of the verify command, double qoutes to preserve LF + # grep 3rd line, 3rd field of the output + # /usr/lpp/mmfs/bin/mmlssnapshot database_dir -s snap_20130522162002 | + # awk '{ if(NR==3) print $3}' + + GPFS_SNAP_STATUS=`echo "$CMD_OUT" | awk '{ if(NR==3) print $3}'` + write_log " ... returns: $GPFS_SNAP_STATUS." + + if [[ $GPFS_SNAP_STATUS != "Valid" ]]; + then + # increment counter, if command did not return "Valid" + let "TMP_RC = TMP_RC + 1" + write_log " ... Verification of snapshot failed." + write_log " ... Status is not equal to \"Valid\"." + fi + + else + # increment counter, if command failed in the loop + let "TMP_RC = TMP_RC + 1" + write_log " ... Verification of snapshot failed." + fi + + done < $TMP + + # set the final return code + + if [[ $TMP_RC -eq 0 ]] + then + write_log " All snapshots successfully verified." + RC=0 + else + write_log " **** ERROR: at least one snapshot image is not in state: valid. rc=$RC_VFY_ERROR" + RC=$RC_VFY_ERROR + fi + + # test to simulate doVerify failure + # RC=$RC_VFY_ERROR + + write_log $D + TIMESTAMP=`date +'%Y%m%d%H%M%S'` + write_log "\nEnding $0 at $TIMESTAMP ." + finalize_log + + debug_info "exit: doVerify" + return $RC +} + + +# +# M A I N +# +# -------------------------------------- +# COLLECT PARAMS +# -------------------------------------- +while getopts a:c:o:t: OPTION +do + case ${OPTION} in + a) action=${OPTARG} + ;; + c) config=${OPTARG} + ;; + o) objectId=${OPTARG} + ;; + t) timestamp=${OPTARG} + ;; + \?) echo "# Unknown parameter '$1'" + esac +done + +# WORK +# -------------------------------------- + +case "$action" in + prepare) + doPrepare + ;; + snapshot) + doSnapshot + ;; + restore) + doRestore + ;; + delete) + doDelete + ;; + verify) + doVerify + ;; + store_metadata) + doStoreMetaData + ;; + rollback) + doRollback + ;; +esac +exit $RC + diff --git a/BARVendor/README b/BARVendor/README new file mode 100644 index 0000000..2d2b493 --- /dev/null +++ b/BARVendor/README @@ -0,0 +1,128 @@ +***************************************************************************** +* +* README for Backup/Restore Vendor API Samples +* +* Last update : May 2002 +* +* These sample files are for the C++ programming language, and can be found +* in the "sqllib/samples/BARVendor" directory. Copy these files to your +* working directory prior to building the sample programs. +* +***************************************************************************** +* +* During the operation of backup/restore, DB2 will issue calls to the +* following functions which are implemented in the vendor.C file: +* sqluvint - Initialization media vendor session +* sqluvget - Retrieve data from media vendor +* sqluvput - Sends data to media vendor +* sqluvend - End of media vendor session +* sqluvdel - Delete media vendor session data +* +* Details on how to use these vendor functions can be found in the +* Administrative API Reference Appendix D. "Backup and Restore APIs for +* Vendor Products" +* +* Some descriptions and guidelines are also provided in the function +* header descriptions of the vendor.C sample file. +* +* *** NOTE *** +* The shared library or DLL code will be run as part of the database +* engine. Therefore, it must be reentrant and thoroughly debugged. +* DB2 takes steps to protect itself from most signals or exceptions +* in the code which means most programming errors should not crash the +* DB2 instance. However, an overwrite of DB2 memory blocks can not be +* detected at this time and will cause memory corruption that might +* bring down the instance. As well, a programming error in functions +* handling data buffers may compromise data integrity of the database. +* Because of this, you are advised to run this sample against a test +* database in a separate instance from your production instance. As +* well, any vendor code you create should be tested against a test +* database and test instance for the same reasons. +* +***************************************************************************** +* +* QUICK START +* +* 1) Copy sqllib/samples/BARVendor/* to a working directory +* 2) Compile vendor.C as a shared library, linking in a library +* implementation of XBSA (XOpen Backup Services API). +* Compile and link libvend.a and vendor.C with the appropriate command(s) +* depending on your operating system, where: +* DB2PATH is set to your instance path, +* XBSA_LIB_PATH is set to the path of the XBSA library, and +* XBSA_LIB is set to the name of the XBSA library +* +* AIX: +* cc_r -I$DB2PATH/include -G -o libvend.a vendor.C -L$XBSA_LIB_PATH\ +* -l$XBSA_LIB +* If you have the source to your own XBSA implementation, you may +* compile the source and link the objects in directly: +* cc_r -I$DB2PATH/include -G -o libvend.a vendor.C xbsasource.C +* +* HP-UX: +* A) Compile: +* aCC +DAportable +u1 +z -ext -mt -I$DB2PATH/include -c vendor.C +* (use +DA2.0W for 64 bit) +* B) Link: +* aCC +DAportable -mt -b -o libvend.sl vendor.o -L$XBSA_LIB_PATH\ +* -l$XBSA_LIB (use +DA2.0W for 64 bit library) +* +* Linux: +* A) Compile: +* g++ -fpic -I$DB2PATH/include -c $vendor.C -D_REENTRANT +* B) Link: +* g++ -shared -o libvend vendor.o -Wl,-rpath,$DB2PATH/lib\ +* -L$XBSA_LIB_PATH -l$XBSA_LIB -lpthread +* +* Solaris: +* A) Compile: +* CC -xarch=v8plusa -mt -DUSE_UI_THREADS -Kpic -I$DB2PATH/include\ +* -c vendor.C +* (For SPARC v9 64-bit use -xarch=v9) +* (For Solaris x86 64-bit use -xarch=amd64 and -xarch=sse2) +* B) Link: +* CC -xarch=v8plusa -mt -G -o libvend.so vendor.o -L$XBSA_LIB_PATH\ +* -R"$DB2PATH/lib" -l$XBSA_LIB +* (For SPARC v9 64-bit use -xarch=v9) +* (For Solaris x86 64-bit use -xarch=amd64 and -xarch=sse2) +* +* Windows: +* A) Compile: (eg with Microsoft C/C++ Compiler) +* cl -Zi -Od -c -W2 -DWIN32 vendor.C +* B) Link: +* link -debug -out libvend.dll -dll vendor.obj $XBSA_LIB\ +* -def:vendor.def +* +* +* 3) DB2 loads your vendor library during a backup or restore operation when +* you specify the LOAD library name on the command line. +* eg. db2 backup database sample load /fullyqualifiedpath/libvend.a +* +* Note: A fully qualified path MUST be given. +* +***************************************************************************** +* Documentation: +* +* For information on developing C++ applications, see the Application +* Development Guide. +* +* For more information on Backup & Restore APIs for Vendor Products, refer +* to Appendix D in the Administrative API Reference. +* +* For the latest information on programming, compiling, and running DB2 +* applications, visit the DB2 application development web site: +* http://www.software.ibm.com/data/db2/udb/ad +***************************************************************************** +* +* File Descriptions: +* +***************************************************************************** +* README - this file! +***************************************************************************** +* custom.h - XBSA header file +* policy.h - XBSA header file (not used but included for your information as +* part of the XBSA API set) +* vendor.C - Implements DB2 Backup/Restore Vendor API with XBSA Draft 0.8 +* level API +* xbsa.h - XBSA header file +***************************************************************************** diff --git a/BARVendor/custom.h b/BARVendor/custom.h new file mode 100644 index 0000000..82e6996 --- /dev/null +++ b/BARVendor/custom.h @@ -0,0 +1,63 @@ +/* custom.h + * + * This is a sample C header file describing the XBSA. + * + * This appendix is not a normative part of the + * specification and is provided for illustrative + * purposes only. + * + * Implementations must ensure that the sizes of integer + * datatypes match their names, not necessarily the typedefs + * presented in this example. + * + */ + +#ifndef _BSA_CUSTOM_H_ +#define _BSA_CUSTOM_H_ + + +/* BSA_Boolean + */ +typedef char BSA_Boolean; + +/* BSA_Int16 + */ +typedef short BSA_Int16; + +/* BSA_Int32 + */ +typedef long BSA_Int32; + + +/* BSA_UInt16 + */ +typedef unsigned short BSA_UInt16; + +/* BSA_UInt32 + */ +typedef unsigned long BSA_UInt32; + +/* BSA_Int64 + */ +typedef struct { /* defined as two 32-bit integers */ + BSA_Int32 left; + BSA_UInt32 right; +} BSA_Int64; + +/* BSA_UInt64 + */ +typedef struct { /* defined as two unsigned 32-bit integers*/ + BSA_UInt32 left; + BSA_UInt32 right; +} BSA_UInt64; + +#define BSA_API_VERSION 1 +#define BSA_API_RELEASE 1 +#define BSA_API_LEVEL 1 + +/* Return Codes Used + */ +#define BSA_RC_OK 0x00 +#define BSA_RC_SUCCESS 0x00 + +#endif diff --git a/BARVendor/libacssc.sh b/BARVendor/libacssc.sh new file mode 100755 index 0000000..17f70f6 --- /dev/null +++ b/BARVendor/libacssc.sh @@ -0,0 +1,391 @@ +#!/bin/sh +#--------------------------------------------------------------------------- +# (c) Copyright IBM Corp. 2012 All rights reserved. +# +# Script Name: libacssc.sh +# +# Purpose: implement the scripted interface for DB2 ACS using tar command. It is supported on all UNIX and Linux platforms where DB2 is certified on. +# +# Please see developerwork article for details: +# https://www.ibm.com/developerworks/data/library/techarticle/dm-1308scriptdb2copy/dm-1308scriptdb2copy-pdf.pdf +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +#--------------------------------------------------------------------------- + + +# CONSTANTS +######################################################################### +# Possible return codes +RC_OK=0 +RC_COMM_ERROR=2 +RC_INV_ACTION=4 +RC_NOT_ENOUGH_SPACE=28 +RC_DEV_ERROR=18 +RC_INV_DEV_HANDLE=12 +RC_IO_ERROR=25 +RC_ERROR=30 + +# Variables +######################################################################### +RC=$RC_OK +_setting=0 +action=0 +config=0 +instance=0 +db_name=0 +dbpartnum=0 +repository="/tmp/" +objectId=0 +timestamp=0 + +# HELPER +######################################################################### +# getSetting() +# +# Searches for setting in the protocol file identified +# by its keyword $1 and stores its value in the tmp variable +# _setting +# @param $1 - Setting's keyword +# @param $2 - Default value if setting's keyword was not found +# (optional, if not set $_setting will be empty) +# @param $3 - Configuration file to be opened (optional, if not +# set, $config will be used) +######################################################################## +getSetting() { + useConfig=$config + if [ "$3" != "" ] + then + useConfig=$3 + fi + + cmd="awk -F= '/^${1}/ { print \$2 }' $useConfig | head -1" + _setting=`eval $cmd` + if [ "$2" != "" -a "$_setting" = "" ] + then + _setting=$2 + fi +} + +# storeSetting() +# +# Stores a local variable in the protocol file which can be +# used later using getSetting +# @param $1 Setting's key +# $2 Settings' value +####################################################################### +storeSetting() { + echo "$1=$2" +} + +# collectSettings() +# +# Collects common settings from the protocol file and +# populates the global variables like handle, db_name and timestamp +# @param void +######################################################################## +collectSettings() { + getSetting "INSTANCE" + instance=$_setting + getSetting "DB_NAME" + db_name=$_setting + getSetting "DBPARTNUM" + dbpartnum=$_setting + getSetting "TIMESTAMP" + timestamp=$_setting +} + +doPrepare() { +# +# P R E P A R E +# +# -------------------------------------- +# getSetting "OPERATION" +# operation=$_setting +# +# case "$operation" in +# snapshot) +# ;; +# delete) +# ;; +# restore) +# ;; +# query) +# ;; + : # noop +# -------------------------------------- +} + +doSnapshot() { +# +# S N A P S H O T +# +# -------------------------------------- +# Snapshot action here: build temporary backup +# file name and create TAR archive of all known +# paths to protocol file repository + + # Construct file name of backup file + # and store it in the protocol file + file="${repository}${db_name}.0.${instance}.${dbpartnum}.${timestamp}.001.tar" + storeSetting "BACKUP_FILE" $file + + # Create TAR archive from all storage paths: + # Use AWK to extract all *_PATH settings from $config file and pipe them to + # tar to create a tar archive + cmd="awk -F= '/^DATAPATH/ { print \$2; }' $config | xargs tar -cf $file 2>/dev/null && echo 0 || echo 1" + echo "# cmd: $cmd" + + # execute command + RC=`eval $cmd` + echo "# backup tar created, rc=$RC" + + # if logs included + getSetting "DB2BACKUP_LOGS" + includeLogs=$_setting + if [ $includeLogs = "INCLUDE" -a $RC -eq 0 ] + then + echo "# Logs to be included" + # Construct file name of logs file: + logs="${repository}${db_name}.0.${instance}.${dbpartnum}.${timestamp}.log.tar" + # store backup file name to config + storeSetting "BACKUP_LOGS" $logs + cmd="awk -F= '/^LOGPATH/ { print \$2; }' $config | xargs tar -cf $logs 2>/dev/null && echo 0 || echo 1" + echo "# cmd: $cmd" + + # execute command + RC=`eval $cmd` + echo "# tar for logs created, rc=$RC" + fi +# -------------------------------------- +} + +doRestore() { +# +# R E S T O R E +# +# -------------------------------------- + + getSetting "OBJ_ID" + objectId=$_setting + # Construct key to search for in currenct protocol file + key="RESULT_${objectId}_FILE" + getSetting $key + oldConfig=$_setting + # Read setting BACKUP_FILE from $oldConfig... + getSetting "BACKUP_FILE" "" $oldConfig + # ... and store it in $oldBackup + oldBackup=$_setting + + # Run command to extract old backup + cmd="tar -xf $oldBackup && echo 0 || echo 1" + echo "# cmd: $cmd" + RC=`eval $cmd` + echo "# tar extracted, rc=$RC" + + # if logs included + getSetting "ACTION" + readAction=$_setting + if [ $readAction = "DB2ACS_ACTION_READ_BY_OBJECT" -a $RC -eq 0 ] + then + # Read setting BACKUP_LOGS from $oldConfig... + getSetting "BACKUP_LOGS" "" $oldConfig + # ... and store it in $oldBackup + oldLogs=$_setting + + # Run command to extract old backup + cmd="tar -xf $oldLogs && echo 0 || echo 1" + echo "# cmd: $cmd" + RC=`eval $cmd` + echo "# logs extracted, rc=$RC" + fi +# -------------------------------------- +} + +doDelete() { +# +# D E L E T E +# +# -------------------------------------- +# We may use $objectId or $timestamp to identify +# files to be deleted. In this sample case, we +# use $objectId to get the protocol file name +# in $oldConfig and read the backup file from this +# file to $oldBackup + + # Construct key to search for in current protocol file + key="RESULT_${objectId}_FILE" + # Read setting RESULT_i_FILE and store it in oldConfig + getSetting $key + oldConfig=$_setting + # Read setting BACKUP_FILE from $oldConfig... + getSetting "BACKUP_FILE" "" $oldConfig + # ... and store it in $oldBackup + oldBackup=$_setting + + # Delete old backup and protocol file + echo "# Delete old backup file and logs: $oldBackup" + rm $oldBackup + + # If logs were included remove the tar file of the logs + getSetting "DB2BACKUP_LOGS" "" $oldConfig + includeLogs=$_setting + if [ $includeLogs = "INCLUDE" ] + then + getSetting "BACKUP_LOGS" "" $oldConfig + oldLogs=$_setting + echo "# Delete old backup file : $oldLogs" + # Delete old logs file + rm $oldLogs + fi +# -------------------------------------- +} + +doVerify() { +# +# V E R I F Y +# +# -------------------------------------- + +# check if the TAR archive is available + getSetting "BACKUP_FILE" + file=$_setting + if [ -f "$file" -a -s "$file" ] + then + echo "# Backup '$file' exist" + getSetting "BACKUP_LOGS" + logs=$_setting + # if logs included + getSetting "DB2BACKUP_LOGS" + includeLogs=$_setting + if [ $includeLogs = "INCLUDE" ] + then + if [ -f "$logs" -a -s "$logs" ] + then + echo "# Logs '$logs' exist" + else + echo "# ERROR: Backup '$logs' does not exists or is empty!" + ((RC= $RC | $RC_ERROR)) + fi + fi + else + echo "# ERROR: Backup '$file' does not exists or is empty!" + ((RC= $RC | $RC_ERROR)) + fi +# -------------------------------------- +} + +doStoreMetaData() { +# +# S T O R E M E T A D A T A +# +# -------------------------------------- +# The snapshot is successful +# The protocol file can be saved, +# only some non important lines will be added + : # noop +# -------------------------------------- +} + +doRollback() { +# +# R O L L B A C K +# +# -------------------------------------- +# Your commands here + + # Do we run backup + getSetting "OPERATION" + operation=$_setting + if [ $operation = "SNAPSHOT" ] + then + # Read setting BACKUP_FILE from $oldConfig... + getSetting "BACKUP_FILE" + # ... and store it in $oldBackup + oldBackup=$_setting + + # Delete old backup file + echo "# Delete old backup file : $oldBackup" + rm $oldBackup + + # If logs were included remove the tar file of the logs + getSetting "DB2BACKUP_LOGS" + includeLogs=$_setting + if [ $includeLogs = "INCLUDE" ] + then + getSetting "BACKUP_LOGS" + oldLogs=$_setting + echo "# Delete old backup file : $oldLogs" + # Delete old logs file + rm $oldLogs + fi + fi +# -------------------------------------- +} + + +# +# M A I N +# +# -------------------------------------- +# COLLECT PARAMS +# -------------------------------------- +while getopts a:c:o:t: OPTION +do + case ${OPTION} in + a) action=${OPTARG} + ;; + c) config=${OPTARG} + ;; + o) objectId=${OPTARG} + ;; + t) timestamp=${OPTARG} + ;; + \?) echo "# Unknown parameter '$1'" + esac +done + +repository="`dirname $config`/" + +# WORK +# -------------------------------------- +collectSettings + +case "$action" in + prepare) + doPrepare + ;; + snapshot) + doSnapshot + ;; + restore) + doRestore + ;; + delete) + doDelete + ;; + verify) + doVerify + ;; + store_metadata) + doStoreMetaData + ;; + rollback) + doRollback + ;; +esac + +exit $RC diff --git a/BARVendor/policy.h b/BARVendor/policy.h new file mode 100644 index 0000000..ec768ba --- /dev/null +++ b/BARVendor/policy.h @@ -0,0 +1,358 @@ +/* policy.h + * + * This is a sample C header file describing the XBSA. + * + * This appendix is not a normative part of the + * specification and is provided for illustrative + * purposes only. + * + * Implementations must ensure that the sizes of integer + * datatypes match their names, not necessarily the typedefs + * presented in this example. + * + */ +/* policy.h + */ + +#ifndef _BSA_POLICY_H_ +#define _BSA_POLICY_H_ + +#include "xbsa.h" + +/* AdminName + */ +typedef char AdminName[BSA_MAX_ADMIN_NAME]; + +/* Administrator + * + * Field Value Explanation + * ----- ----- ----------- + * system True Has XBSA Backup Services privileges. + * False Does not have XBSA Backup Services privileges. + * policy True Has XBSA policy privileges. + * False Does not have XBSA policy privileges. + */ +typedef struct { + AdminName name; /* Name of the administrator */ + Description desc; /* Descriptive info re the administrator */ + BSA_Boolean system; + BSA_Boolean policy; + char * policyList[BSA_MAX_POLICYDOMAINS]; /* List of policy domains */ + /* for which the administrator has privileges */ +} Administrator; + +/* FilterRuleSet + * + * The following notation is used to specify the syntax + * to be used for the definition of a Filter Rule Set: + * Elements enclosed in {} may be repeated zero or more times. + * Rules separated by | are alternate production rules. + * Literal words are specified as all uppercase characters. + * FilterRuleSet ::= FilterRule {FilterRule XBSADELIMITER} + * FilterRule ::= Predicate {AND Predicate} LGName + * Predicate ::= empty | + * EqualityPredicate | + * RelationalPredicate + * EqualityPredicate ::= XBSAUSERNAME = "XBSAUserName" | + * APPUSERNAME = "AppUserName" | + * FILESPACENAME = "filespaceName" | + * PATHNAME = "pathname" | + * RESOURCETYPE = "ResourceType" | + * OBJECTTYPE = "ObjectType" + * + * RelationalPredicate ::= OBJECTSIZE RelOp Number + * RelOp ::= = | <> | < | <= | > | >= + * Number ::= digit {digit} any sequence of digits that + * can be represented as an + * unsigned 64 bit integer + * LGName ::= a valid life cycle group name + * ObjectType ::= any of the allowed values for ObjectType + * + * The predicate for the last rule in a filter rule set + * is always assumed to be true. + * + * XBSAUserName, AppUserName, filespaceName, pathname, + * and ResourceType are character strings that do not exceed + * the valid length for these types of character arrays (as + * defined in the type definitions). These character strings + * may include the character "*" which matches zero or + * more characters. The character "\" is used as an escape + * character to allow the use of " or * as valid characters + * in a character string. Specifying "\\" would allow the use + * of the backslash character. + * There can be no spaces in EqualityPredicates. + */ + typedef char FilterRuleSet[BSA_MAX_FILTERRULESET]; + +/* LifeCycleGroup + */ +typedef struct { + LGName name; /* Lifecycle Group name */ + Description desc; /* Lifecycle Group description */ + CopyGroup * copyGroups[BSA_MAX_COPYGROUPS]; +} LifecycleGroup; + +/* PolicySetName + */ +typedef char PolicySetName[ BSA_MAX_POLICYSET_NAME]; + +/* PolicySetDescriptor + */ +typedef struct { + PolicySetName policySetName; + Description desc; + LGName lGNameList[BSA_MAX_LIFECYCLEGROUPS]; +} PolicySetDescriptor; + +/* PolicyDomainDescriptor + */ +typedef struct { + DomainName policyDomName; + Description desc; + PolicySetDescriptor policySetList[BSA_MAX_POLICYSETS]; +} PolicyDomainDescriptor; + +/* PolicyDomainList + */ +typedef struct { + DomainName policyDomList[BSA_MAX_POLICYDOMAINS]; +} PolicyDomainList; + +/* Function Prototypes : include these for full XBSA Compliance, + * together with the Data Movement API Subset, which is defined + * in header file "xbsa.h" + */ + +extern BSA_Int16 +BSAActivatePolicySet +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr +); + +extern BSA_Int16 +BSACreateAccessRule +( BSA_UInt32 bsaHandle, + AccessRule *accessRulePtr, + RuleId *ruleIdPtr +); + +extern BSA_Int16 +BSACreateAdministrator +( BSA_UInt32 bsaHandle, + Administrator *administratorPtr +); + +extern BSA_Int16 +BSACreateFilterRuleSet +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr, + FilterRuleSet *filterRulePtr +); + +extern BSA_Int16 +BSACreateLifecycleGroup +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr, + LifecycleGroup *lifecycleGroupPtr +); + +extern BSA_Int16 +BSACreatePolicyDomain +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *desc +); + +extern BSA_Int16 +BSACreatePolicySet +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr, + char *desc +); + +extern BSA_Int16 +BSACreateSchedule +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + Schedule *schedulePtr +); + +extern BSA_Int16 +BSACreateUser +( BSA_UInt32 bsaHandle, + char *name, + char *domainNamePtr, + char *desc +); + +extern BSA_Int16 +BSADeleteAccessRule +( BSA_UInt32 bsaHandle, + RuleId ruleId +); + +extern BSA_Int16 +BSADeleteAdministrator +( BSA_UInt32 bsaHandle, + char *name +); + +extern BSA_Int16 +BSADeleteFilterRuleSet +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr +); + +extern BSA_Int16 +BSADeleteLifecycleGroup +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr, + char *lifecycleGroupName +); + +extern BSA_Int16 +BSADeletePolicyDomain +( BSA_UInt32 bsaHandle, + char *domainNamePtr +); + +extern BSA_Int16 +BSADeletePolicySet +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr +); + +extern BSA_Int16 +BSADeleteSchedule +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + Schedule scheduleId +); + +extern BSA_Int16 +BSADeleteUser +( BSA_UInt32 bsaHandle, + char *name +); + +extern BSA_Int16 +BSAGetEvent +( BSA_UInt32 bsaHandle, + BSAEvent *eventPtr, + BSA_Boolean flags +); + +extern BSA_Int16 +BSAGetNextAccessRule +( BSA_UInt32 bsaHandle, + AccessRule *accessRulePtr +); + +extern BSA_Int16 +BSAGetNextAdmin +( BSA_UInt32 bsaHandle, + Administrator *administratorPtr +); + +/* BSAGetNextQueryObject defined in xbsa.h because it should be part + * of the Data Movement subset. + */ + +extern BSA_Int16 +BSAGetNextSchedule +( BSA_UInt32 bsaHandle, + Schedule *schedulePtr +); + +extern BSA_Int16 +BSAGetNextUser +( BSA_UInt32 bsaHandle, + UserDescriptor *userDescPtr +); + +extern BSA_Int16 +BSAGetPolicyDomainList +( BSA_UInt32 bsaHandle, + PolicyDomainList *policyDomListPtr +); + +extern BSA_Int16 +BSAQueryAccessRule +( BSA_UInt32 bsaHandle, + char *objectName, + AccessRule *accessRulePtr +); + +extern BSA_Int16 +BSAQueryAdministrator +( BSA_UInt32 bsaHandle, + char *name, + Administrator *administratorPtr +); + +extern BSA_Int16 +BSAQueryFilterRuleSet +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr, + FilterRuleSet *filterRuleSetPtr +); + +extern BSA_Int16 +BSAQueryLifecycleGroup +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr, + char *lifecycleGroupName, + LifecycleGroup *lGPtr +); + +extern BSA_Int16 +BSAQueryPolicyDomain +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + PolicyDomainDescriptor *pDDescriptorPtr +); + +extern BSA_Int16 +BSAQueryPolicySet +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + char *policySetNamePtr, + PolicySetDescriptor *pSDescriptorPtr +); + +extern BSA_Int16 +BSAQuerySchedule +( BSA_UInt32 bsaHandle, + char *domainNamePtr, + Schedule *schedulePtr +); + +extern BSA_Int16 +BSAQueryUser +( BSA_UInt32 bsaHandle, + char *name, + UserDescriptor *userDescPtr +); + +extern BSA_Int16 +BSAResolveLifecycleGroup +( BSA_UInt32 bsaHandle, + ObjectDescriptor *objectDescriptorPtr +); + +extern BSA_Int16 +BSASetEventStatus +( BSA_UInt32 bsaHandle, + BSAEvent *eventPtr +); + +#endif diff --git a/BARVendor/vendor.C b/BARVendor/vendor.C new file mode 100644 index 0000000..2df236e --- /dev/null +++ b/BARVendor/vendor.C @@ -0,0 +1,1541 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 1995 - 2002 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: vendor.C +** +** SAMPLE: Implements the DB2 Backup/Restore Vendor APIs +** using the XBSA Draft 0.8 level API +** +** FUNCTIONS USED: +** sqluvint - Initialization media vendor session +** sqluvget - Retrieve data from media vendor +** sqluvput - Sends data to media vendor +** sqluvend - End of media vendor session +** sqluvdel - Delete media vendor session data +** +***************************************************************************** +* +* For information on developing C++ applications, see the Application +* Development Guide. +* +* For more information on Backup & Restore APIs for Vendor Products, refer +* to Appendix D in the Administrative API Reference. +* +* For the latest information on programming, compiling, and running DB2 +* applications, visit the DB2 application development website: +* http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "xbsa.h" + + +#ifndef WIN32 +#include "unistd.h" +#endif + +#include "sqlutil.h" +#include "sqluvend.h" +#include "sqluv.h" + +// ---------------------------------------------------------------------------- +// This is an internally used constant passed to bldObjName +// as backup type when we don't know what type of restore +// we are doing. +// ---------------------------------------------------------------------------- +#define CREATE_OBJECT_INITIAL_SIZE 1000 + +#define SET_ERR_REASON( return_code, rc ) \ +{ \ + return_code->reserve = NULL; \ + return_code->return_code = (sqlint32) rc; \ + sprintf(return_code->description, "%ld %ld", __LINE__, rc); \ +} + +// ---------------------------------------------------------------------------- +// XBSA related data +// ---------------------------------------------------------------------------- + +typedef struct _xbsahandle +{ + BSA_UInt32 xbsaHandle; + int status; + ObjectDescriptor *ObjectDescPtr; + QueryDescriptor *QueryDescPtr; + char *ptr; +} DB2XBSAHANDLE; + +// State Bits +#define INIT_DONE 0x01 +#define READ_BEGUN 0x02 +#define BACKUP 0x04 +#define RESTORE 0x08 + +int bldWriteObjDesc ( ObjectDescriptor *, + QueryDescriptor *, + DB2_info *, + sqluint32 , + sqluint32 ); + +int bldReadObjDesc ( ObjectDescriptor *, + QueryDescriptor *, + DB2_info *); + +int getLatestCopy ( QueryDescriptor *, + ObjectDescriptor *, + sqluint32 *, + sqluint16); + +void initBSAStructures( ObjectDescriptor *objDesc, + QueryDescriptor *qryDesc, + DB2_info *db2_info); + + +#define INIT_MAX_XBSA_OBJS 100 +#ifndef WIN32 + #define PATH_SEP '/' + #define PATH_SEP_STR "/" +#else + #define PATH_SEP '\\' + #define PATH_SEP_STR "\\" +#endif + +// ---------------------------------------------------------------------------- +// +// SQLUVINT +// +// This function is where initialization and allocation of all the +// resources needed for the vendor media session are done. This includes +// such items as memory, devices, and programs/processes. This sample +// allocates memory blocks and initializes the XBSA interface that is +// used as the storage mechanism. +// +// DB2 sends information through the 'Init_input' structure referenced +// here by the pointer 'in'. Please see sqluvend.h for exact structure +// definitions and other defines. The Init_input structure holds the DB2 +// information for the session in 'DB2_info', which includes DB2 UDB +// product version and levels ('DB2_id', 'version', 'release', and +// 'level') of the DB2 server. This structure also contains the +// following information: +// A caller action ('action') indicates what type of operation is to +// occur for the session; 'SQLUV_WRITE' or 'SQLUV_READ'. +// 'filename' - The image name, represented in the following format +// on UNIX .... +// .. Filename is not +// used by Backup, or restore, however, it is used to provide +// recovery for a Load Copy image. +// 'server_id' - name of the DB2 UDB server starting this media +// session. +// 'db2instance' - DB2 instance name of the database we are operating +// on. +// The 'type' for backup or restore: (defined in sqlutil.h and sqluv.h) +// +// backup (SQLUV_WRITE) SQLUB_DB - full database backup +// SQLUB_FULL - full database backup +// SQLUB_TABLESPACE - table space level backup +// SQLUB_LOAD_COPY - Load Copy image +// SQLUB_INCREMENTAL - Incremental +// SQLUB_DELTA - Incremental Delta +// restore (SQLUV_READ) SQLUD_DB - full database image +// SQLUD_FULL - full database backup +// SQLUD_ONLINE_TABLESPACE - online table space +// SQLUD_TABLESPACE - table space +// SQLUD_HISTORY - history file restore +// SQLUD_INCREMENTAL - restore of incremental image +// SQLUD_AUTOMATIC - automatic restore +// +// This 'type' is a an image action type and is sent as a bit mask +// and should be separated out with SQLUB_TYPE_MASK and SQLUB_INCR_MASK +// for backup and SQLUD_TYPE_MASK SQLUD_INCR_MASK for restore. +// +// 'dbname' - database name we are performing backup/restore on. +// 'alias' - database alias we are performing backup/restore on. +// 'timestamp' of the backup being made or image to be recovered. +// 'sequence' number of backup image. This corresponds to the unique +// number for the media session during backup/restore. +// Range is (001,999) for backup. +// Restore use of sequence is a little more intricate. For restore +// the value of sequence will be zero since we don't know +// yet what image sequences exist yet until we do a query for the +// image objects. This function must return the number of sequences +// or objects found for image in num_objects_in_backup (see +// below describing 'Vendor_info') Subsequent calls by DB2 +// to sqluvget will provide a specific sequence number +// as 'obj_num'. (see sqluvget). +// 'max_bytes_per_txn' The maximum number of bytes DB2 wants to use +// for data transfer in a buffer. +// 'nodeNum' - DB2 Database Partition on which the backup/restore +// is happening. +// +// The following input variables are for use by the vendor server +// you are using, or have implemented, if one exists. (A la TSM) +// 'nodename' - Name of physical node on which image is to be or was +// generated from. +// 'password' for the above node. +// 'owner' or originator, a user id of who 'owns' the image. The +// user who invoked the operation. +// 'mcNameP' - Management Class +// +// Other input variables in Init_input are: +// - the vendor options specified by the DB2 API caller. (size_options +// contains the size of the data block being referenced by the +// 'options' pointer). +// - Estimated database size (size_HI_order, size_LOW_order) which +// you may use in resource pre-allocation if needed. +// - Number of media sessions started by DB2 (num_sessions). +// +// For subsequent vendor calls DB2 needs information returned in the +// the structure 'Init_output' and referenced by pointer 'out' +// The following should be returned within the 'Init_output' structure: +// +// pointer to 'Vendor_info' ('vendor_session') and pointer to +// allocated memory for the vendor control block 'pVendorCB'. +// +// Memory which these pointers reference must be allocated by you the +// vendor. You are responsible for cleaning up and de-allocating this +// memory when the session terminates. (abnormally, or not). This is +// to be done in sqluvend. +// +// 'Vendor_info' contains : +// - a string identifying the vendor, ('vendor_id') +// - the current product info for the vendor - Can be used to +// store the version of any interface you are using in turn to +// store/retrieve data. -e.g. XBSA release/level as in this +// sample, or TSM API level ('version', 'release', 'level'). +// - Name that identifies database server ('server_id'). +// - Maximum bytes for transfer the vendor can support. +// ('max_bytes_per_txn') +// - Number of objects found for restore ('num_objects_in_backup'). +// This is the number of storage objects found by you that match +// the information given about backup image. (query made +// up of 'dbname', 'nodeNum', 'timestamp', etc. from 'DB2_info' +// Note: timestamp may be partial causing multiple matches on +// a search. It is possible to find no match as well. +// 'nodeNum' here refers to the database partition number.) +// +// The vendor control block is a structure defined by you. It's +// purpose is to keep track of resources used between vendor calls. +// In this example we have defined DB2XBSAHANDLE structure to keep +// track of handles, descriptors and status needed for XBSA. +// +// DB2 also needs the return code information. It is held in the +// 'Return_code' structure and is referenced by 'return_code' pointer. +// This must also be allocated in sqluvint. The contents of this +// structure are simply the integer variable 'return_code' and +// description string. They are used return message strings to the user +// and for the db2diag.log. The value of the return_code may be +// anything you wish to define, and may be a value returned from other +// functions or APIs. +// +// The sqluvint function itself must return a value when done processing. +// The values you may use are in defined in sqluvend.h. The following are +// some of the defined error codes and what actions they produce in DB2: +// +// SQLUV_OK Initialization OK - DB2 proceeds normally. +// +// Media Access Error Codes: +// SQLUV_LINK_EXIST, SQLUV_INIT_FAILED, SQLUV_DEV_ERROR, +// SQLUV_COMM_ERROR, SQLUV_COMMIT_FAILED, SQLUV_ABORT_FAILED, +// SQLUV_WARNING, SQLUV_LINK_NOT_EXIST, SQLUV_NO_DEV_AVAIL +// +// Api Error codes +// SQLUV_INV_VERSION, SQLUV_INV_ACTION, SQLUV_INV_USERID, +// SQLUV_INV_OPTIONS, SQLUV_INV_DEV_HANDLE, SQLUV_BUFF_SIZE, +// SQLUV_UNEXPECTED_ERROR, SQLUV_INV_PASSWORD +// +// For both Media Access Errors and Api Errors DB2 will fail +// initialization of this session and of the Media Controller process +// requesting the session. +// +// ---------------------------------------------------------------------------- + +int sqluvint ( struct Init_input *in, + struct Init_output *out, + struct Return_code *return_code) +{ + ApiVersion ApiVersion = {0}; + int rc = SQLUV_OK; + BSA_Int16 xbsaRC = BSA_RC_OK; + int searchCount = 0; + DB2XBSAHANDLE *handle = NULL; + Vendor_info *VendorInfo = NULL; + SecurityToken *secTokenPtr = NULL; + char *cptr = NULL; + DataBlock dataBlk = {0}; + sqluint32 type = 0; + sqluint32 incr = 0; + sqluint16 DBPartitionNum = 0; + int uniqueBackup = 0; + char *tptr = NULL; + int timestampLen = SQLU_TIME_STAMP_LEN; + char timestamp[SQLU_TIME_STAMP_LEN+1] = {0}; + + + + // Allocate space to keep track BSA information (DB2XBSAHANDLE) + // This will eventually be returned as the Vendor Control Block (pVendorCB) + // ------------------------------------------------------------------------- + handle = (DB2XBSAHANDLE *) malloc ( sizeof (DB2XBSAHANDLE) ); + if (handle == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, errno ); + goto exit; + } + memset ( handle, 0x00, sizeof (DB2XBSAHANDLE)); + + secTokenPtr = (SecurityToken*)malloc(BSA_MAX_TOKEN_SIZE); + if (secTokenPtr == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, errno ); + goto exit; + } + memset(secTokenPtr, 0x00, BSA_MAX_TOKEN_SIZE); + + handle->ObjectDescPtr = (ObjectDescriptor*)malloc(sizeof(ObjectDescriptor)); + if (handle->ObjectDescPtr == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, errno ); + goto exit; + } + memset(handle->ObjectDescPtr, 0x00, sizeof(ObjectDescriptor)); + + handle->QueryDescPtr = (QueryDescriptor*)malloc(sizeof(QueryDescriptor)); + if (handle->QueryDescPtr == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, errno ); + goto exit; + } + memset(handle->QueryDescPtr, 0x00, sizeof(QueryDescriptor)); + + if ((*(in->DB2_session->action) != SQLUV_WRITE) && + (*(in->DB2_session->action) != SQLUV_READ)) + { + rc = SQLUV_INV_ACTION; + SET_ERR_REASON(return_code, 0 ); + goto exit; + } + + // The backup type and possibly incremental info are both sent + // as bit masks in the 'type' field. Separate them out for use here. + // ------------------------------------------------------------------------- + type = incr = strtoul(in->DB2_session->type, NULL, 16); + type &= SQLUB_TYPE_MASK; + incr &= SQLUB_INCR_MASK; + + + BSAQueryApiVersion(&ApiVersion); + + + handle->ObjectDescPtr->objName.objectSpaceName[0] = '\0'; + handle->ObjectDescPtr->objName.pathName[0] = '\0'; + handle->ObjectDescPtr->status = BSAObjectStatus_ACTIVE; + + // + // Initialize the BSA structures + // ------------------------------------------------------------------------- + initBSAStructures(handle->ObjectDescPtr, handle->QueryDescPtr, in->DB2_session); + + // Start XBSA session. + // ------------------------------------------------------------------------- + xbsaRC = BSAInit(&handle->xbsaHandle, /* Will contain session handle on return. */ + secTokenPtr, /* password */ + &handle->ObjectDescPtr->Owner, /* Node name and Owner name */ + NULL); + + if (xbsaRC != BSA_RC_SUCCESS) + { + SET_ERR_REASON(return_code, xbsaRC ); + rc = SQLUV_INIT_FAILED; + goto exit; + } + + // To begin an XBSA transaction. + // ------------------------------------------------------------------------- + xbsaRC = BSABeginTxn ( handle->xbsaHandle ); + if ( xbsaRC != BSA_RC_SUCCESS) + { + SET_ERR_REASON(return_code, xbsaRC ); + rc = SQLUV_INIT_FAILED; + goto exit; + } + + // ------------------------------------------------------------------------- + // If BACKUP do the following. + // ------------------------------------------------------------------------- + if (*(in->DB2_session->action) == SQLUV_WRITE) + { + char *SendBuffer; + + // Build the object name + // + // On restore do not set the type for the object and query + // descriptor or we will not be able to restore a table space from + // a full DB image + // ---------------------------------------------------------------------- + rc = bldWriteObjDesc(handle->ObjectDescPtr, + handle->QueryDescPtr, + in->DB2_session, + type, incr); + if (((in->size_HI_order == 0) && (in->size_LOW_order == 0)) ) + { + in->size_HI_order = 0; + in->size_LOW_order = SQL_MAXRECL_4K * CREATE_OBJECT_INITIAL_SIZE; + } + handle->ObjectDescPtr->size.left = in->size_HI_order; + handle->ObjectDescPtr->size.right = in->size_LOW_order; + + // Must have a buffer allocated to create an object + // A size of CREATE_OBJECT_INITIAL_SIZE is being used, + // this is an arbitrary value + // ---------------------------------------------------------------------- + SendBuffer = (char *)malloc(CREATE_OBJECT_INITIAL_SIZE); + if (SendBuffer == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, errno ); + goto exit; + } + memset(SendBuffer,0x00,CREATE_OBJECT_INITIAL_SIZE); + dataBlk.bufferLen = CREATE_OBJECT_INITIAL_SIZE; + dataBlk.numBytes = 0; + dataBlk.bufferPtr = SendBuffer; + + // Create the object + // ---------------------------------------------------------------------- + xbsaRC = BSACreateObject( handle->xbsaHandle, /* BSA session Handle */ + handle->ObjectDescPtr, + &dataBlk); + if ( xbsaRC != BSA_RC_SUCCESS) + { + SET_ERR_REASON(return_code, xbsaRC ); + rc = SQLUV_INIT_FAILED; + free(SendBuffer); + goto exit; + } + + free(SendBuffer); + handle->status = INIT_DONE | BACKUP; + + } // Backup init ends. + + // ------------------------------------------------------------------------- + // If RESTORE do the following. + // ------------------------------------------------------------------------- + else if (*(in->DB2_session->action) == SQLUV_READ) + { + // Build the object name + // + // On restore do not set the type for the object and query descriptor or + // we will not be able to restore a table space from a full DB image + // ---------------------------------------------------------------------- + rc = bldReadObjDesc(handle->ObjectDescPtr, + handle->QueryDescPtr, + in->DB2_session); + + // If timestamp is not provided, assume restoring from latest backup. + // ---------------------------------------------------------------------- + if ((in->DB2_session->timestamp == NULL) || + (in->DB2_session->timestamp[0] == '\0')) + { + // Do query to match the backup image. + // After calling this function and rc > 0, the objName in QueryDesc + // contains the full objName except the seq_no. + // ------------------------------------------------------------------- + rc = getLatestCopy (handle->QueryDescPtr, + handle->ObjectDescPtr, + &handle->xbsaHandle, + in->DB2_session->nodeNum ); + if (rc != 0) + { + SET_ERR_REASON(return_code, rc); + goto exit; + } + handle->QueryDescPtr->objName = handle->ObjectDescPtr->objName; + } + + // At this point, QueryDesc contains timestamp. + // ---------------------------------------------------------------------- + xbsaRC = BSAQueryObject ( handle->xbsaHandle, handle->QueryDescPtr, + handle->ObjectDescPtr); + if ( (xbsaRC != BSA_RC_SUCCESS) + && (xbsaRC != BSA_RC_NO_MORE_DATA) + && (xbsaRC != BSA_RC_MORE_DATA)) + { + SET_ERR_REASON(return_code, xbsaRC ); + rc = SQLUV_OBJ_NOT_FOUND; + goto exit; + } + + while ( (xbsaRC == BSA_RC_MORE_DATA) + || (xbsaRC == BSA_RC_NO_MORE_DATA) + || ( xbsaRC == BSA_RC_SUCCESS)) + { + + // Ensure we are looking for data for this DB partition number only + // ------------------------------------------------------------------- + tptr = strrchr(handle->ObjectDescPtr->objName.objectSpaceName, + PATH_SEP); + if (tptr == NULL) + tptr = handle->ObjectDescPtr->objName.objectSpaceName; + else + tptr+=strlen("/NODE"); + + DBPartitionNum = (sqluint16)atoi(tptr); + if (in->DB2_session->nodeNum == DBPartitionNum) + { + // Check the sequence number. If it's a 1, then this is + // a new backup image. If it's not a 1, then it's + // just part of a backup we've already counted. + // ---------------------------------------------------------------- + int stringLen = strlen(handle->ObjectDescPtr->objName.pathName); + if ((handle->ObjectDescPtr->objName.pathName[stringLen-2] == '.') && + (handle->ObjectDescPtr->objName.pathName[stringLen-1] == '1')) + uniqueBackup++; + + searchCount++; + } + + // + // Just processes the last item + // ------------------------------------------------------------------- + if (xbsaRC == BSA_RC_NO_MORE_DATA) + break; + + xbsaRC = BSAGetNextQueryObject (handle->xbsaHandle, + handle->ObjectDescPtr); + if (xbsaRC == BSA_RC_NO_MATCH) + break; + } + + // + // No BSA object match found on server for backup image given + // ---------------------------------------------------------------------- + if (searchCount == 0) + { + rc = SQLUV_OBJ_NOT_FOUND; + SET_ERR_REASON(return_code, rc ); + goto exit; + } + + // Error occured other than no match or no more data + // ---------------------------------------------------------------------- + if ((xbsaRC != BSA_RC_NO_MATCH) && (xbsaRC != BSA_RC_NO_MORE_DATA)) + { + SET_ERR_REASON(return_code, rc ); + rc = SQLUV_DEV_ERROR; + goto exit; + } + + // If we have reached this point we have initialized BSA successfully and + // got at least one image match. + // ---------------------------------------------------------------------- + rc = SQLUV_OK; + + // If one than more match found, then notify DB2 as this is an error + // condition will cause an error message to be returned to the DB2 user. + // ---------------------------------------------------------------------- + if (uniqueBackup > 1) + { + SET_ERR_REASON(return_code, rc ); + rc = SQLUV_OBJS_FOUND; + goto exit; + } + + // Update our internal status flag for this session + // ---------------------------------------------------------------------- + handle->status = INIT_DONE | RESTORE; + + } // Restore init ends. + +success: // Construct return structure. + + // Allocate space for the Vendor information block for output pointer + // vendor_session + // ------------------------------------------------------------------------- + handle->ptr = (char *) malloc (sizeof(Return_code)+sizeof(Vendor_info)); + if (handle->ptr == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, errno ); + goto exit; + } + memset(handle->ptr, 0x00, sizeof(Return_code)+sizeof(Vendor_info)); + cptr = handle->ptr ; + + // Fill in vendor information for BSA vendor session + // ------------------------------------------------------------------------- + + // Vendor Id. + VendorInfo = out->vendor_session = (Vendor_info *) cptr; + cptr += sizeof (Vendor_info); + + out->vendor_session->vendor_id = "XBSA"; + + // Version. + sprintf(cptr, "%d", ApiVersion.version); + out->vendor_session->version = cptr; + cptr += strlen(cptr); // point to next available position. + + // Release. + sprintf(cptr, "%d", ApiVersion.release); + out->vendor_session->release = cptr; + cptr += strlen(cptr); // point to next available position. + + // Level + sprintf(cptr, "%d", ApiVersion.level); + out->vendor_session->level = cptr; + cptr += strlen(cptr); // point to next available position. + + // Reserve + out->vendor_session->reserve = NULL; + + // Device Handle. + // Return the BSA handle as the vendor control block + // ------------------------------------------------------------------------- + out->pVendorCB = (void *)handle; + + // Reserve + out->reserve = NULL; + + // Matches found for image object criteria + // ------------------------------------------------------------------------- + out->vendor_session->num_objects_in_backup = searchCount; + +// Error exit +// ---------------------------------------------------------------------------- +exit: + if (secTokenPtr != NULL) + free(secTokenPtr); + + // Free all memory and terminate BSA session (if started) if an error was + // encountered. + // ------------------------------------------------------------------------- + if ((handle != NULL) && !(handle->status & INIT_DONE)) + { + if (handle->xbsaHandle != 0) + BSATerminate (handle->xbsaHandle); + if (handle->ptr) + { + free(handle->ptr); + handle->ptr = NULL; + } + if (handle->QueryDescPtr) + { + free(handle->QueryDescPtr); + handle->QueryDescPtr = NULL; + } + if (handle->ObjectDescPtr) + { + free(handle->ObjectDescPtr); + handle->ObjectDescPtr = NULL; + } + free (handle); + handle = NULL; + } + return(rc); + +} + + +// ---------------------------------------------------------------------------- +// +// SQLUVGET +// +// This function is called by DB2 once a session has been successfully +// initialized to get or retrieve data from storage. DB2 will send you +// a handle ('hdle'), which is actually a pointer to the vendor control +// block that was described and setup in sqluvint. +// +// The pointer 'data' to the 'Data' structure is for input and output. +// On restore the 'Data' structure indicates which object or sequence +// is to be read. ('obj_num'). (Range is 0 to 998 so must add one to +// get actual sequence number.) +// 'buff_size' contains the buffer's size, that is, how much data DB2 +// wants sqluvget to try to retrieve at once. DO NOT attempt to +// return more to DB2 than what this indicates, as it will overflow +// the allocated memory space. +// 'actual_buff_size' is an output field and is the actual bytes read +// by you, the vendor. +// 'dataptr' is the pointer to the data buffer. It is pre-allocated +// and managed by DB2. This is where you put the data you read +// from storage. Be careful not to write outside the allocated +// space! (specified by 'buff_size'). +// +// The return code info is returned by a pointer 'return_code' to the +// 'Return_code' structure (see sqluvint). +// Function return values are in sqluvend.h. Ensure you return the correct +// value for the situation. +// +// SQLUV_OK - DB2 continues, expects more data so calls sqluvget again. +// SQLUV_MORE_DATA - Same as SQLUV_OK. +// +// SQLUV_ENDOFMEDIA_NO_DATA - Reached end of media didn't read any data. +// SQLUV_ENDOFMEDIA - Reached end of media while reading data. +// +// Depending on what stage DB2 is in, the above two values may or may not +// result in a successful operation. For example, during a read media +// header operation, if we return SQLUV_ENDOFMEDIA and the amount of data +// read doesn't equal the defined media header size, then the DB2 +// restore will fail. If it is of equal size the operation is OK because +// it is possible to have an image with just a media header. If this is +// a regular call to sqluvget then both of these return codes will prompt +// DB2 to call sqluvend to end the session normally. +// +// SQLUV_WARNING - DB2 will call sqluvend to end the session with vote +// set to SQLUV_COMMIT. +// Any other error - DB2 will call sqluvend with vote set to SQLUV_TERMINATE +// to indicate we need close down the session as +// quickly as possible. +// ---------------------------------------------------------------------------- +int sqluvget ( void *hdle, + struct Data *data, + struct Return_code *return_code) +{ + int rc = SQLUV_OK; + BSA_Int16 xbsaRC = BSA_RC_OK; + DataBlock dataBlk = {0}; + DB2XBSAHANDLE *handle = (DB2XBSAHANDLE *)hdle; + int bytestoread = 0; + char *workptr = (char *)data->dataptr; + int sequenceNum = 0; + char *ptr = NULL; + + if ( !(handle->status & RESTORE) ) + { + rc = SQLUV_INV_ACTION; + SET_ERR_REASON(return_code, 0 ); + goto exit; + } + + // Reset the sequence number at the end of the object descriptor + // ------------------------------------------------------------------------- + sequenceNum = data->obj_num+1; + + ptr = strrchr(handle->ObjectDescPtr->objName.pathName,'.'); + if (ptr != NULL) + sprintf(ptr, ".%d", sequenceNum); + + handle->QueryDescPtr->objName = handle->ObjectDescPtr->objName; + if ( !( handle->status & READ_BEGUN )) + { + // First query the object so that the ObjectDescPtr structure is set + // correctly + // ---------------------------------------------------------------------- + xbsaRC = BSAQueryObject ( handle->xbsaHandle, handle->QueryDescPtr, + handle->ObjectDescPtr); + if ( (xbsaRC != BSA_RC_SUCCESS) + && (xbsaRC != BSA_RC_NO_MORE_DATA) + && (xbsaRC != BSA_RC_MORE_DATA)) + { + SET_ERR_REASON(return_code, xbsaRC ); + rc = SQLUV_OBJ_NOT_FOUND; + goto exit; + } + + handle->status |= READ_BEGUN; + + dataBlk.bufferPtr = (char *)data->dataptr; + dataBlk.bufferLen = data->buff_size; // data size expect. + dataBlk.numBytes = data->buff_size; + xbsaRC = BSAGetObject ( handle->xbsaHandle, handle->ObjectDescPtr, + &dataBlk); + data->actual_buff_size = dataBlk.numBytes; + + if (xbsaRC == BSA_RC_MORE_DATA) + { + data->actual_buff_size = 0; + bytestoread= data->buff_size; + dataBlk.bufferLen = data->buff_size; + dataBlk.bufferPtr = (char *)data->dataptr; + xbsaRC = BSAGetData ( handle->xbsaHandle, &dataBlk ); + + data->actual_buff_size += dataBlk.numBytes; + + SET_ERR_REASON(return_code, xbsaRC ); + + if (xbsaRC == BSA_RC_MORE_DATA) + { + rc = SQLUV_MORE_DATA; + goto exit; + } + } + + if ( xbsaRC != BSA_RC_SUCCESS) + { + SET_ERR_REASON(return_code, xbsaRC ); + if (xbsaRC == BSA_RC_NO_MATCH) + // Notify DB2 if we could not find a match to the image on the + // server. An error message indicating such will be returned + // to the DB2 user. + // ---------------------------------------------------------------- + rc = SQLUV_OBJ_NOT_FOUND; + else + rc = SQLUV_IO_ERROR; + goto exit; + } + } + else // if not first get. + { + data->actual_buff_size = 0; + dataBlk.bufferLen = data->buff_size; + dataBlk.bufferPtr = (char *)data->dataptr; + + bytestoread = data->buff_size; + workptr = (char *)data->dataptr; + // + // Split up the large buffer to fit into the 16 bit interface + // (XBSA API Draft 0.8 restriction/limitation) + // ------------------------------------------------------------------- + do + { + if (bytestoread >= USHRT_MAX) + dataBlk.bufferLen= USHRT_MAX - 16; + else + dataBlk.bufferLen=bytestoread; + + dataBlk.bufferPtr = workptr; + dataBlk.numBytes = dataBlk.bufferLen; + xbsaRC = BSAGetData ( handle->xbsaHandle, &dataBlk ); + data->actual_buff_size += dataBlk.numBytes; + + SET_ERR_REASON(return_code, xbsaRC ); + + if (xbsaRC == BSA_RC_MORE_DATA) + rc = SQLUV_MORE_DATA; + else if (xbsaRC != BSA_RC_NO_MORE_DATA) + { + rc = SQLUV_IO_ERROR; + goto exit; + } + + workptr += dataBlk.numBytes; + bytestoread -= dataBlk.numBytes; + + } while (bytestoread > 0 && rc == SQLUV_MORE_DATA); + } + if (xbsaRC == BSA_RC_NO_MORE_DATA) + { + rc = SQLUV_ENDOFMEDIA; + } + SET_ERR_REASON(return_code, xbsaRC ); + +exit: + + return(rc); + +} // sqluvget() + + +// ---------------------------------------------------------------------------- +// +// SQLUVPUT +// +// Once a session has been successfully initialized this function is called +// by DB2 to put or write data to storage. +// DB2 will send you a handle ('hdle'), which is actually a pointer the +// vendor control block, that is setup and initialized in sqluvint. +// +// The pointer 'data' to the 'Data' structure is for input and output. +// 'buff_size' contains the buffers size that is being used, that is +// how much data DB2 wants sqluvput to try to write. +// 'actual_buff_size' is an output field and is the actual bytes +// written, or processed by sqluvput. If this field ends up being +// less than buff_size, then do not return SQLUV_OK, unless it is +// OK to lose the remaining data in the buffer. Return another value +// that indicates an error. This will result in the buffer being put +// back on DB2's buffer queue for another session (if it exists) +// to process. If is possible to redo this buffer in it's entirety, +// then ask DB2 to re-send the buffer. +// +// 'dataptr' is an input pointer to the data (DB2 data buffer) to +// process. +// +// The return code info is returned by a pointer 'return_code' to struct +// 'Return_code' (see sqluvint) +// +// Function return values are in sqluvend.h. +// The next actions of DB2 may differ depending on what is value is returned +// here. +// Returning SQLUV_OK - DB2 will continue, as long as there is more buffers +// to send. If not, it will begin normal vendor session +// termination. +// SQLUV_ENDOFMEDIA - This indicates to DB2 that there was a +// normal end of storage on the media. The data that has been +// already written will be treated as committed to storage, and +// DB2 will end this vendor session by calling sqluvend with +// the SQLUV_COMMIT flag. See sqluvend for further info. +// SQLUV_END_OF_TAPE - Tells DB2 that there is not enough storage +// space to write this buffer out completely. This could be +// detected while a portion of the buffer has been written. +// DB2 will call sqluvend with SQLUV_TERMINATE flag. +// See sqluvend for further info. +// SQLUV_NO_DEV_AVAIL - Media Access error - DB2 will terminate +// or abort the session and fail the backup. +// SQLUV_DATA_RESEND will cause DB2 to re-send the same buffer +// from it's start on the next sqluvput call. This will only +// be done once, the second time SQLUV_DATA_RESEND is returned +// it will treated as an error. +// ---------------------------------------------------------------------------- +int sqluvput ( void * hdle, + struct Data *data, + struct Return_code *return_code) +{ + DataBlock dataBlk = {0}; + DB2XBSAHANDLE *handle = (DB2XBSAHANDLE *)hdle; + int rc = SQLUV_OK; + BSA_Int16 xbsaRC = BSA_RC_OK; + int byteswritten = 0; + int bytestowrite = 0; + char *workpointer = (char *)data->dataptr; + + if ( !(handle->status & BACKUP) ) + { + rc = SQLUV_INV_ACTION; + SET_ERR_REASON(return_code, 0 ); + goto exit; + } + + bytestowrite = data->buff_size; + + // split up the data to fit into the 16 bit interface + // (Limitation of the XBSA Draft 0.8 level API) + // ------------------------------------------------------------------------- + while (bytestowrite > 0) + { + if (bytestowrite >= USHRT_MAX) + dataBlk.bufferLen = USHRT_MAX - 16; + else + dataBlk.bufferLen = bytestowrite; + + dataBlk.bufferPtr = workpointer; + dataBlk.numBytes = dataBlk.bufferLen; + bytestowrite -= dataBlk.bufferLen; + + xbsaRC = BSASendData ( handle->xbsaHandle, &dataBlk); + if (xbsaRC != BSA_RC_SUCCESS) + { + SET_ERR_REASON(return_code, xbsaRC ); + rc = SQLUV_IO_ERROR; + goto exit; + } + else + { // End of tape check + if (dataBlk.numBytes == 0) + { + rc = SQLUV_END_OF_TAPE; + SET_ERR_REASON(return_code, rc ); + goto exit; + } + } + + byteswritten += dataBlk.numBytes; + workpointer += dataBlk.numBytes; + } + dataBlk.numBytes = byteswritten; + +exit: + + // actual number of bytes written. + // -------------------------------------------------------------------------- + data->actual_buff_size = byteswritten; + return(rc); +} + + +// ---------------------------------------------------------------------------- +// +// SQLUVEND +// +// This function cleans up all resources for a media session. It will be +// called for both successful and unsuccessful termination. +// 'action' indicates whether the data was compeletly processed by this +// session, or whether a problem occurred. +// 'hdle' handle or pointer to vendor control block for the session (input) +// 'in_out' pointer to structure 'Init_output' +// 'vendor_session' pointer to struct Vendor_info (input) +// 'pVendorCB' pointer to vendor control block (input) +// 'return_code' pointer to 'Return_code' structure (output) +// +// Release all memory allocated during initialization if completed +// successfully and call cleanup API's or functions. +// ---------------------------------------------------------------------------- +int sqluvend ( sqlint32 action, + void *hdle, + struct Init_output *in_out, + struct Return_code *return_code) +{ + int rc = SQLUV_OK; + BSA_Int16 xbsaRC = BSA_RC_OK; + Vote vote = BSAVote_COMMIT; + sqluint16 rc_reason = {0x00}; + DB2XBSAHANDLE *handle = (DB2XBSAHANDLE * ) hdle; + + if (handle==NULL) // init failed + goto exit; + + if (handle->status & INIT_DONE) + { + + xbsaRC = BSAEndData ( handle ->xbsaHandle ); + if ( xbsaRC != BSA_RC_SUCCESS) + { + rc = SQLUV_DEV_ERROR; + action = SQLUV_ABORT; + } + + if ((action == SQLUV_COMMIT) || + (action == SQLUV_TERMINATE)) + vote = BSAVote_COMMIT; + else + vote = BSAVote_ABORT; + + xbsaRC = BSAEndTxn ( handle->xbsaHandle, vote); + if ( xbsaRC != BSA_RC_SUCCESS) + { + rc = SQLUV_DEV_ERROR; + } + } + + BSATerminate (handle->xbsaHandle); + + // free allocated memory. + if (handle->ptr != NULL) + { + free(handle->ptr); + handle->ptr = NULL; + } + + if (handle->ObjectDescPtr != NULL) + { + free(handle->ObjectDescPtr); + handle->ObjectDescPtr = NULL; + } + + if (handle->QueryDescPtr != NULL) + { + free(handle->QueryDescPtr); + handle->QueryDescPtr = NULL; + } + + free(handle); + handle = NULL; + +exit: + + // SQLUV_TERMINATE indicates that we had to terminate to obtain the + // failing reasoncode, to not reset it. + // ------------------------------------------------------------------------- + if (action != SQLUV_TERMINATE) + SET_ERR_REASON(return_code, rc); + + return(rc); +} + + +// ---------------------------------------------------------------------------- +// +// SQLUVDEL +// +// This function will be invoked by DB2 when a backup fails after all +// sessions have ended. It is not a good idea to leave an incomplete +// backup image around. +// +// This function should create it's own session, and so, must initialize +// any resources to be used. See sqluvint for description of input/output +// parameters. +// ---------------------------------------------------------------------------- +int sqluvdel ( Init_input * in, + Init_output * vendorDevData, + Return_code * return_code) +{ + ApiVersion ApiVersion = {0x00}; + ObjectName objName = {0x00}; + int fileCount = 0; + BSA_UInt32 xbsaHandle = 0; + SecurityToken tokenPtr = {0x00}; + ObjectDescriptor *ObjectDescPtr = NULL; + QueryDescriptor *QueryDescPtr = NULL; + int rc = SQLUV_OK; + BSA_Int16 xbsaRC = BSA_RC_OK; + int ix = 0; + int currentMaxObjsAllocate = INIT_MAX_XBSA_OBJS; + + SQLUV_BMH *mediaHeader = (SQLUV_BMH *)vendorDevData->vendor_session->reserve; + + typedef struct objectIdent + { + ObjectName objName; + CopyType copyType; + CopyId copyID; + } OBJECT_IDENT; + OBJECT_IDENT *fileListPtr = NULL; + + + fileListPtr = (OBJECT_IDENT*)malloc(sizeof(OBJECT_IDENT)*currentMaxObjsAllocate); + if (fileListPtr == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, errno); + goto exit; + } + memset(fileListPtr, 0x00, (sizeof(OBJECT_IDENT)*currentMaxObjsAllocate)); + + + ObjectDescPtr = (ObjectDescriptor*)malloc(sizeof(ObjectDescriptor)); + if (ObjectDescPtr == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, errno); + goto exit; + } + memset(ObjectDescPtr, 0x00, sizeof(ObjectDescriptor)); + + QueryDescPtr = (QueryDescriptor*)malloc(sizeof(QueryDescriptor)); + if (QueryDescPtr == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, errno); + goto exit; + } + memset(QueryDescPtr, 0x00, sizeof(QueryDescriptor)); + + ObjectDescPtr->version = ObjectDescriptorVersion; + strcpy(ObjectDescPtr->Owner.bsaObjectOwner, "DB2"); + ObjectDescPtr->Owner.appObjectOwner[0] = '\0'; + ObjectDescPtr->copyType = BSACopyType_BACKUP; + ObjectDescPtr->size.left = 0; + ObjectDescPtr->size.right = 0; + strcpy(ObjectDescPtr->resourceType, "database"); + ObjectDescPtr->objectType = BSAObjectType_FILE; + ObjectDescPtr->encodingList = NULL; + strcpy(ObjectDescPtr->desc, "DB2 Backup"); + strcpy(QueryDescPtr->desc, "DB2 Backup"); + ObjectDescPtr->objectInfo[0] = '\0'; + QueryDescPtr->owner = ObjectDescPtr->Owner; + QueryDescPtr->objName = ObjectDescPtr->objName; + QueryDescPtr->copyType = ObjectDescPtr->copyType; + QueryDescPtr->objectType = ObjectDescPtr->objectType; + QueryDescPtr->status = ObjectDescPtr->status; + + BSAQueryApiVersion(&ApiVersion); + + // Initialize BSA session + // ------------------------------------------------------------------------- + xbsaRC = BSAInit(&xbsaHandle, /* Will contain session handle on retrun. */ + &tokenPtr, /* password */ + &ObjectDescPtr->Owner, /* Node name and Owner name */ + NULL); /* Environment variables */ + if (xbsaRC != BSA_RC_SUCCESS) + { + SET_ERR_REASON(return_code, xbsaRC); + goto exit; + } + + // Build image to be deleted into objName + // ------------------------------------------------------------------------- + sprintf(objName.objectSpaceName, "%s%s", + PATH_SEP_STR, mediaHeader->clientDBAlias); + + sprintf(&objName.objectSpaceName[strlen(objName.objectSpaceName)], "%sNODE%4.4d", + PATH_SEP_STR, in->DB2_session->nodeNum); + + sprintf(&objName.objectSpaceName[strlen(objName.objectSpaceName)], "%s%s.%s.*", + PATH_SEP_STR, "*" SQLUV_NAME_SUFFIX, mediaHeader->timestamp); + + QueryDescPtr->objName = objName; + QueryDescPtr->status = BSAObjectStatus_ANY; + + // Find all objects matching image name + // ------------------------------------------------------------------------- + xbsaRC = BSAQueryObject(xbsaHandle, QueryDescPtr, ObjectDescPtr); + if (( xbsaRC != BSA_RC_SUCCESS) && (xbsaRC != BSA_RC_NO_MORE_DATA)) + { + goto cleanup; + } + + // Save all matching image objects in list + // ------------------------------------------------------------------------- + while (( xbsaRC == BSA_RC_SUCCESS) || (xbsaRC == BSA_RC_NO_MORE_DATA) || (xbsaRC == BSA_RC_MORE_DATA)) + { + if (fileCount > currentMaxObjsAllocate) + { + // + // Double the size, reallocate and initialize + // ------------------------------------------------------------------- + currentMaxObjsAllocate += currentMaxObjsAllocate; + realloc(fileListPtr, sizeof(OBJECT_IDENT)*currentMaxObjsAllocate); + if (fileListPtr == NULL) + { + rc = SQLUV_INIT_FAILED; + SET_ERR_REASON(return_code, rc); + goto exit; + } + memset((void *)&fileListPtr[(currentMaxObjsAllocate/2)],0x00, + (sizeof(OBJECT_IDENT)*(currentMaxObjsAllocate/2))); + } + fileListPtr[fileCount].objName = ObjectDescPtr->objName; + fileListPtr[fileCount].copyType = ObjectDescPtr->copyType; + fileListPtr[fileCount].copyID = ObjectDescPtr->copyId; + fileCount++; + + if (xbsaRC == BSA_RC_NO_MORE_DATA) + break; + xbsaRC = BSAGetNextQueryObject(xbsaHandle, ObjectDescPtr); + if (xbsaRC == BSA_RC_NO_MATCH) + break; + } + +finished: + xbsaRC = BSABeginTxn( xbsaHandle ); + if ( xbsaRC != BSA_RC_SUCCESS) + { + goto cleanup; + } + + // + // Go through the list just created and do the deletes. + // ------------------------------------------------------------------------- + for(ix=0;ixobjName.objectSpaceName, "%c%s%s",PATH_SEP,extraSeparator, + db2_info->alias); + + // The objDesc->version parameter is assumed to be + // an input parameter. The current version number is defined in + // custom.h . + // ------------------------------------------------------------------------- + objDesc->version = ObjectDescriptorVersion; + objDesc->copyType = BSACopyType_BACKUP; + objDesc->objectType = BSAObjectType_FILE; + objDesc->size.left = 0; + objDesc->size.right = 0; + objDesc->encodingList = NULL; + objDesc->objectInfo[0] = '\0'; + + objDesc->Owner.appObjectOwner[0] = '\0'; + strcpy(objDesc->Owner.bsaObjectOwner, "DB2"); + strcpy(objDesc->resourceType, "database"); + strcpy(objDesc->desc, "DB2 Backup"); + strcpy(qryDesc->desc, "DB2 Backup"); + + // Init the query strcuture + // ------------------------------------------------------------------------- + qryDesc->status = BSAObjectStatus_ANY; + qryDesc->owner = objDesc->Owner; + qryDesc->objName = objDesc->objName; + qryDesc->copyType = objDesc->copyType; + qryDesc->objectType = objDesc->objectType; + qryDesc->status = objDesc->status; + + + return; +} + +// ---------------------------------------------------------------------------- +// To construct the XBSA file name +// ---------------------------------------------------------------------------- +int bldWriteObjDesc ( ObjectDescriptor *objDesc, + QueryDescriptor *qryDesc, + DB2_info *db2_info, + sqluint32 type, + sqluint32 incr) +{ + int rc = SQLUV_OK; + + // ------------------------------------------------------------------------- + sprintf(objDesc->objName.objectSpaceName, "/%s", db2_info->alias); + + sprintf(&objDesc->objName.objectSpaceName[strlen(objDesc->objName.objectSpaceName)], + "%sNODE%4.4d", PATH_SEP_STR, db2_info->nodeNum); + + if ((db2_info->filename == NULL) || (db2_info->filename[0] == '\0')) + { + // ObjectName = /ALIAS/NODExxxx/ + // /*_BACKUP.timestamp.seq_no + // + // For backup, timestamp is generated by the agent and is used + // by all the media IO. + // ---------------------------------------------------------------------- + sprintf(objDesc->objName.pathName, "%c%s.%s.%s", + PATH_SEP, + SQLUV_NAME_GENERATE(type, incr), + db2_info->timestamp, + db2_info->sequence ); + } + else + { + // if backup and filename is provided. + sprintf(objDesc->objName.pathName, "%c%s.%s.%s", + PATH_SEP, + db2_info->filename, + db2_info->timestamp, + db2_info->sequence ); + } + + return (rc); +} +// ---------------------------------------------------------------------------- +// To construct the XBSA file name +// ---------------------------------------------------------------------------- +int bldReadObjDesc ( ObjectDescriptor *objDesc, + QueryDescriptor *qryDesc, + DB2_info *db2_info) +{ + int rc = SQLUV_OK; + + // Legatto XBSA's implementation requires that double-backslashes ("\\\\") + // be passed on non-UNIX platforms because they interpert the '\' + // character in XBSA to mean escape. Therefore to use '\' as a regular + // character we must escape it twice. Once for the compiler and once + // again for Legatto. If your implemtation of XBSA does not assume + // this then the code following needs to be modified to reflect this. + // ------------------------------------------------------------------------- + +#ifndef WIN32 + const char * extraSeparator = ""; +#else + const char * extraSeparator = PATH_SEP_STR; +#endif + const char * filename = "*" SQLUV_NAME_SUFFIX; + char * timestamp = ""; + + sprintf(&qryDesc->objName.objectSpaceName[strlen(qryDesc->objName.objectSpaceName)], + "%s%sNODE%4.4d", PATH_SEP_STR, extraSeparator, db2_info->nodeNum); + + if (*db2_info->sequence == '0') + { + // this must be the first time in since all sequence + // numbers start at '1'. + // ---------------------------------------------------------------------- + *db2_info->sequence = '1'; + } + + // Restore does not currently supply a filename, but the + // recovery of a load copy might. + // ------------------------------------------------------------------------- + if ((db2_info->filename != NULL) && (db2_info->filename[0] != '\0')) + filename = db2_info->filename; + + if ((db2_info->timestamp != NULL) && (db2_info->timestamp[0] != '\0')) + timestamp = db2_info->timestamp; + + // filename not provided. + // fs = /ALIAS + // hl = /NODExxxx + // ll = /*_BACKUP.timestamp.seq_no + // ------------------------------------------------------------------------- + sprintf(qryDesc->objName.pathName, "%c%s%s.%s*.*", + PATH_SEP, extraSeparator, filename, timestamp); + + return (rc); +} + + +// ---------------------------------------------------------------------------- +// Select the latest backup image. +// The objName in QueryDesc is set to the search pattern. +// ---------------------------------------------------------------------------- +int getLatestCopy ( QueryDescriptor * QueryDescPtr, + ObjectDescriptor * objDataPtr, + sqluint32 * Handle, + sqluint16 nodeNum ) +{ + DataBlock dataBlk = {0x00}; + int rc = SQLUV_OK; + BSA_Int16 xbsaRC = BSA_RC_OK; + int CNamelen = 0; + char objSpaceName [BSA_MAX_OSNAME+1] = {0x00}; + char pathName [BSA_MAX_OSNAME+1] = {0x00}; + char *tptr = NULL; + int foundTSBackup = FALSE; + int foundDBBackup = FALSE; + int foundABackup = FALSE; + sqluint16 DBPartitionNum = 0; + + xbsaRC = BSAQueryObject( *Handle,QueryDescPtr, objDataPtr); + if ((xbsaRC != BSA_RC_SUCCESS) && (xbsaRC != BSA_RC_MORE_DATA) && (xbsaRC != BSA_RC_NO_MORE_DATA)) + goto exit; + + while ((xbsaRC == BSA_RC_MORE_DATA) || (xbsaRC == BSA_RC_NO_MORE_DATA) || ( xbsaRC == BSA_RC_SUCCESS)) + { + + // Ensure we are looking for data for this node only + // ---------------------------------------------------------------------- + tptr = strrchr(objDataPtr->objName.objectSpaceName, PATH_SEP); + if (tptr == NULL) + tptr = objDataPtr->objName.objectSpaceName; + else + tptr+=strlen("/NODE"); + + DBPartitionNum = (sqluint16)atoi(tptr); + if (nodeNum == DBPartitionNum) + { + // Make a note of the type of backup. If we find both a DB backup + // and a table space backup, that means that the type of backup + // to restore wasn't specified and we have both types on the + // stroage server. This is ambiguous. + // -------------------------------------------------------------------- + if ( !strncmp((objDataPtr->objName.pathName)+1, + SQLUV_NAME_DB_FULL, sizeof(SQLUV_NAME_DB_FULL)-1) + || !strncmp((objDataPtr->objName.pathName)+1, + SQLUV_NAME_DB, sizeof(SQLUV_NAME_DB)-1)) + { + foundDBBackup = TRUE; + } + else if (!strncmp((objDataPtr->objName.pathName)+1, + SQLUV_NAME_TSP, sizeof(SQLUV_NAME_TSP)-1)) + { + foundTSBackup = TRUE; + } + + // Initialize image info when we find first matching backup image. + if (! foundABackup) + { + strncpy(pathName, objDataPtr->objName.pathName,BSA_MAX_OSNAME ); + strncpy(objSpaceName, objDataPtr->objName.objectSpaceName,BSA_MAX_OSNAME); + tptr = strrchr (pathName, '.'); + + foundABackup = TRUE; + + *tptr = '\0'; // remove the sequence no. fr the fname. + CNamelen = strlen(pathName); + } + else + { + if ((strncmp( objDataPtr->objName.pathName, + pathName, CNamelen ) > 0)) // CNamelen upto timestamp. + { + // keep the latest copy. + tptr = strrchr (objDataPtr->objName.pathName, '.'); + if (tptr == NULL) + continue; + *tptr = '\0'; + strncpy(pathName, objDataPtr->objName.pathName,BSA_MAX_OSNAME ); + strncpy(objSpaceName, objDataPtr->objName.objectSpaceName,BSA_MAX_OSNAME); + } + } + } + if (xbsaRC == BSA_RC_NO_MORE_DATA) + break; + xbsaRC = BSAGetNextQueryObject ( *Handle, objDataPtr); + if (xbsaRC == BSA_RC_NO_MATCH) + break; + } + +exit: + + if (foundTSBackup && foundDBBackup) + { + rc = SQLUV_OBJS_FOUND; + } + else if (foundABackup) + { + strcpy( objDataPtr->objName.objectSpaceName, objSpaceName ); + strcpy( objDataPtr->objName.pathName, pathName ); + strcat( objDataPtr->objName.pathName, ".*"); // seq_no. + rc = SQLUV_OK; + } + else + { + rc = SQLUV_OBJ_NOT_FOUND; + } + + return (rc); +} + +#ifdef __cplusplus +} +#endif + + diff --git a/BARVendor/xbsa.h b/BARVendor/xbsa.h new file mode 100644 index 0000000..ecc94a4 --- /dev/null +++ b/BARVendor/xbsa.h @@ -0,0 +1,678 @@ +/* xbsa16.h + * + * This is a sample C header file describing the XBSA. + * + * This appendix is not a normative part of the + * specification and is provided for illustrative + * purposes only. + * + * Implementations must ensure that the sizes of integer + * datatypes match their names, not necessarily the typedefs + * presented in this example. + * + */ + +#ifndef _BSA_XBSA_H_ +#define _BSA_XBSA_H_ + +#include "custom.h" + +#if (SYS_V > 3) || defined(BERK4_2) || defined(SUN4) +#include +#else +#include +#endif + +/* Constants used + * + * Maximum string lengths (lower bound), including trailing null + */ +#define BSA_LIST_ELEMENT_DELIMITER null /* Element delimiter in list */ +#define BSA_MAX_ADMIN_NAME 64 /* Administrator name */ +#define BSA_MAX_APPOBJECT_OWNER 64 /* Max end-object owner length */ +#define BSA_MAX_BSAOBJECT_OWNER 64 /* Max BSA object owner length */ +#define BSA_MAX_CG_DEST 31 /* Copy group destination */ +#define BSA_MAX_CG_NAME 31 /* Max copy group name length */ +#define BSA_MAX_COPYGROUPS 16 /* Max number of copy groups */ + /* which can be specified in a */ + /* lifecycle group */ +#define BSA_MAX_DESCRIPTION 256 /* Description field */ +#define BSA_MAX_ENCODINGMETHOD 31 /* Max encoding method length */ +#define BSA_MAX_EVENTINFO 256 /* Max event info size */ +#define BSA_MAX_FILTERRULESET 8192 /* Max filter rule set size */ +#define BSA_MAX_OSNAME 1024 /* Max Objectspace name length */ +#define BSA_MAX_LG_NAME 31 /* Life cycle group name */ +#define BSA_MAX_LIFECYCLEGROUPS 64 /* Max number of life cycle */ + /* groups in a policy set */ +#define BSA_MAX_OBJINFO 512 /* Max object info size */ +#define BSA_MAX_PATHNAME 1024 /* Max path name length */ +#define BSA_MAX_POLICYDOMAINS 256 /* Max number of specific policy */ + /* domains an administrator may */ + /* be responsible for */ +#define BSA_MAX_POLICYDOMAIN_NAME 31 /* Policy domain name */ +#define BSA_MAX_POLICYSETS 16 /* Max number of policy sets */ + /* in a domain */ +#define BSA_MAX_POLICYSET_NAME 31 /* Policy set name */ +#define BSA_MAX_RESOURCETYPE 31 /* Max resource mgr name length */ +#define BSA_MAX_TOKEN_SIZE 64 /* Max size of a security token */ +#define BSA_PUBLIC "BSA_ANY" /* Default string */ + +/* Return Codes Used + * + * Return Code descriptions are given in Section 4.3. + */ +#define BSA_RC_ABORT_ACTIVE_NOT_FOUND 0x02 +#define BSA_RC_ABORT_SYSTEM_ERROR 0x03 +#define BSA_RC_AUTHENTICATION_FAILURE 0x04 +#define BSA_RC_BAD_CALL_SEQUENCE 0x05 +#define BSA_RC_BAD_HANDLE 0x06 +#define BSA_RC_BUFFER_TOO_SMALL 0x07 +#define BSA_RC_DESC_TOO_LONG 0x08 +#define BSA_RC_OBJECTSPACE_TOO_LONG 0x09 +#define BSA_RC_INVALID_TOKEN 0x0a +#define BSA_RC_INVALID_VOTE 0x0b +#define BSA_RC_INVALID_KEYWORD 0x0c +#define BSA_RC_MATCH_EXISTS 0x0d +#define BSA_RC_MORE_DATA 0x0e +#define BSA_RC_MORE_RULES 0x0f +#define BSA_RC_NEWTOKEN_REQD 0x10 +#define BSA_RC_NO_MATCH 0x11 +#define BSA_RC_NO_MORE_DATA 0x12 +#define BSA_RC_NO_RESOURCES 0x13 +#define BSA_RC_NULL_DATABLKPTR 0x14 +#define BSA_RC_NULL_OBJNAME 0x15 +#define BSA_RC_NULL_POINTER 0x16 +#define BSA_RC_NULL_RULEID 0x17 +#define BSA_RC_OBJECT_NAME_TOO_LONG 0x18 +#define BSA_RC_OBJECT_NOT_EMPTY 0x19 +#define BSA_RC_OBJECT_NOT_FOUND 0x1a +#define BSA_RC_OBJINFO_TOO_LONG 0x1b +#define BSA_RC_OBJNAME_TOO_LONG 0x1c +#define BSA_RC_OPERATION_NOT_AUTHORIZED 0x1d +#define BSA_RC_OLDTOKEN_REQD 0x1e +#define BSA_RC_TOKEN_EXPIRED 0x1f +#define BSA_RC_TXN_ABORTED 0x20 +#define BSA_RC_UNMATCHED_QUOTE 0x21 +#define BSA_RC_USER_OWNS_OBJECTS 0x22 + +/* AppObjectOwner + */ +typedef char AppObjectOwner[BSA_MAX_APPOBJECT_OWNER]; + +/* BSAObjectOwner + */ +typedef char BSAObjectOwner[BSA_MAX_BSAOBJECT_OWNER]; + +/* CopyGpDest + */ +typedef char CopyGpDest[BSA_MAX_CG_DEST]; + +/* CopyGpName + */ +typedef char CopyGpName[BSA_MAX_CG_NAME]; + +/* CopyMode + * + * Constant Value Explanation + * -------- ----- ----------- + * INCREMENTAL 1 Specifies that the Backup Services should make a + * copy only if the application object has been + * modified since the last time this copy group was + * used to create the object's copy. + * ABSOLUTE 2 Specifies that the Backup Services should make a + * copy even if the application object has not been + * modified since the last time this copy group was + * used to create the object's copy. + */ +typedef enum { + BSACopyMode_INCREMENTAL = 1, + BSACopyMode_ABSOLUTE = 2 +} CopyMode; + +/* CopySerialization + * + * Constant Value Explanation + * -------- ----- ----------- + * STATIC 1 Specifies that the Backup Services must create a + * consistent (unmodified during the operation) copy of + * the object. If the application is unable to create a + * consistent copy then it should skip the operation + * (creating backup or archive copy) for the object. + * SHAREDSTATIC 2 Specifies that the Backup Services must create a + * consistent copy of the object. It can retry the + * operation a number of times (application dependent). + * If the Backup Services is unable to create a + * consistent copy even after retries, then it should + * skip creating a backup or archive copy of the + * object. + * SHAREDDYNAMIC 3 Specifies that the Backup Services must create a + * copy of the object. It can retry the operation a + * number of times in an attempt to create a consistent + * copy; however, if it fails to make a consistent + * copy, a copy must still be made, ignoring the fact + * that the copy may have been modified during the + * operation. Such copies are useful for log file + * objects which are being continuously modified. + * DYNAMIC 4 Specifies that the Backup Services must create a + * copy of the obbject even if the source object is + * modified during the operation. No retries should be + * attempted to create a consistent copy. + */ +typedef enum { + BSACopySerialization_STATIC = 1, + BSACopySerialization_SHAREDSTATIC = 2, + BSACopySerialization_SHAREDDYNAMIC = 3, + BSACopySerialization_DYNAMIC = 4 +} CopySerialization; + +/* CopyType + * + * Constant Value Explanation + * -------- ----- ----------- + * ANY 1 Used for matching any copy type (e.g. "backup" or + * "archive" in the copy type field of structures for + * selecting query results). + * ARCHIVE 2 Specifies that the copy type should be "archive". + * When used in the copy type field of the CopyGroup, + * it identifies the copy data as of type + * ArchiveCopyData, which is used to create archive + * copies. + * BACKUP 3 Specifies that the copy type should be "backup". + * When used in the copy type field of the CopyGroup, + * it identifies the copy data as of type + * BackupCopyData, which is used to create backup + * copies. + */ +typedef enum { + BSACopyType_ANY = 1, + BSACopyType_ARCHIVE = 2, + BSACopyType_BACKUP = 3 +} CopyType; + +/* Description + */ +typedef char Description[BSA_MAX_DESCRIPTION]; + +/* DomainName + */ +typedef char * DomainName[BSA_MAX_POLICYDOMAIN_NAME]; + +/* EventInfo + */ +typedef char EventInfo[BSA_MAX_EVENTINFO]; + +/* LGName + */ +typedef char LGName[BSA_MAX_LG_NAME]; + +/* ObjectInfo + */ +typedef char ObjectInfo[BSA_MAX_OBJINFO]; + +/* ObjectName + */ +typedef struct { + char objectSpaceName[BSA_MAX_OSNAME]; /* Highest-level name qualifier */ + char pathName[BSA_MAX_PATHNAME]; /* Object name within */ + /* objectspace */ +} ObjectName; + +/* ObjectOwner + */ +typedef struct { + BSAObjectOwner bsaObjectOwner; /* BSA Owner name - this is the name */ + /* that Backup Services authenticates */ + AppObjectOwner appObjectOwner; /* End-owner name, this is the name */ + /* defined by the application */ +} ObjectOwner; + +/* ObjectSize + */ +typedef BSA_UInt64 ObjectSize; /* Unsigned 64-bit integer */ + +/* ObjectStatus + * + * Constant Value Explanation + * -------- ----- ----------- + * ANY 1 Provides a wild card function. Can only be used in + * queries. + * ACTIVE 2 Indicates that this is the most recent backup copy + * of an object. + * INACTIVE 3 Indicates that this is not the most recent backup + * copy, or that the object itself no longer exists. + */ +typedef enum { + BSAObjectStatus_ANY = 1, + BSAObjectStatus_ACTIVE = 2, + BSAObjectStatus_INACTIVE = 3 +} ObjectStatus; + +/* ObjectType + * + * Constant Value Explanation + * -------- ----- ----------- + * any 1 Used for matching any object type (e.g. "file" or + * "directory") value in the object type field of + * structures for selecting query results. + * file 2 Used by the application to indicate that the type of + * application object is a "file" or single object. + * directory 3 Used by the application to indicate that the type of + * application object is a "directory" or container of + * objects. + */ + typedef enum { + BSAObjectType_ANY = 1, + BSAObjectType_FILE = 2, + BSAObjectType_DIRECTORY = 3 +} ObjectType; + +/* Operation + * + * Constant Value Explanation + * -------- ----- ----------- + * archive 1 Used to indicate that a scheduled operation is of + * type "archive". + * backup 2 Used to indicate that a scheduled operation is of + * type "backup". + */ +typedef enum { + BSAOperation_ARCHIVE = 1, + BSAOperation_BACKUP = 2 +} Operation; + +/* Period + * + * Use of the Period structure in a Schedule for an event: + * 1. The Schedule structure specifies 3 timing elements: + * a. "firstStartTime" - a timestamp showing the "earliest" + * possible time the event could take place + * b. "day" - the day of the week the event should occur + * c. "frequency" - the period between successive events + * 2. To determine the day the event should occur (this does + * not change the time of the event in the day): + * a. Determine the requested day from "firstStartTime". + * b. If "day" does not equal XBSA_DAYOFWEEK_ANY + * i. Compare "day" to the day of the week corresponding + * to "firstStartTime" determined in 2a above. + * ii.If the days match, then use "firstStartTime" else + * use the first "day" *following* the day shown + * in "firstStartTime" as the day of the event. + * 3. If the PeriodWhich field in the Period structure is other + * than XBSA_PERIOD_UNDEFINED, then successive events are + * determined using the value of "periodData". + * a. For seconds and days, the appropriate seconds or days + * are added to the "firstStartTime" and step 2 to correct + * for the day of the week (if needed) is applied again. + * b. If a monthly period is specified, then the appropriate + * number of months are added by incrementing the month index is + * made (for example, a one month increment from February to + * March). If the monthly date is not valid (for example, January + * 30 --> February 30) then the last day of the desired month is + * used (example January 30 --> February 28). Then step 2 is + * followed to adjust for the requested day (which might move the + * event time into the following month). + */ +typedef enum { + BSAPeriod_SECONDS = 1, + BSAPeriod_DAYS = 2, + BSAPeriod_MONTHS = 3, + BSAPeriod_UNDEFINED = -9, + BSAPeriod_DAILY = 4, BSAPeriod_WEEKLY = 5, BSAPeriod_MONTHLY = 6, + BSAPeriod_QUARTERLY = 7, BSAPeriod_ANNUALLY = 8 +} PeriodWhich; + +typedef struct { + PeriodWhich which; + union { + time_t nSeconds; + BSA_Int16 nDays; + BSA_Int16 nMonths; + } periodData; +} Period; + +/* ResourceType + */ +typedef char ResourceType[BSA_MAX_RESOURCETYPE]; + +/* RuleId + */ +typedef BSA_UInt64 RuleId; + +/* Scheduleid + */ +typedef BSA_UInt64 ScheduleId; + +/* AccessRight + * + * Constant Value Explanation + * -------- ----- ----------- + * GET 1 Access right for getting an object from Backup + * Services, also includes access right for querying + * (getting attributes) an object from Backup Services. + * QUERY 2 Access right for querying (getting attributes) an + * object from Backup Services. + */ +typedef enum { + BSAAccessRight_GET = 1, + BSAAcessRight_QUERY = 2 +} AccessRight; + +/* AccessRule + */ +typedef struct { + RuleId ruleId; /* Provided by Backup Services */ + ObjectName objName; /* Object name to be given access */ + ObjectOwner objectOwner; /* BSA object owner and Applicaton object */ + /* owner to be given access */ + AccessRight rights; /* The access rights to be given */ +} AccessRule; + +/* ApiVersion + */ +typedef struct { + BSA_UInt16 version; /* Version of this API */ + BSA_UInt16 release; /* Release of this API */ + BSA_UInt16 level; /* Level of this API */ +} ApiVersion; + +/* ArchiveCopyData + */ +typedef struct { + CopyGpName cGName; /* Copy group name */ + BSA_UInt16 freq; /* Archive frequency */ + CopySerialization copySer; /* Copy serialization code */ + CopyMode copyMode; /* Copy mode */ + CopyGpDest destName; /* Copy destination name */ + BSA_UInt16 retVersion; /* Retention time for the version */ +} ArchiveCopyData; + +/* BackupCopyData + */ +typedef struct { + CopyGpName cGName; /* Copy group name */ + BSA_UInt16 freq; /* Backup frequency */ + CopySerialization copySer; /* Copy serialization code */ + CopyMode copyMode; /* Copy mode: 1=modified, 2=absolute */ + CopyGpDest destName; /* Copy destination name */ + BSA_UInt16 verDataEx; /* Versions (number of versions */ + /* retained) */ + BSA_UInt16 verDataDel; /* Versions (data deleted) */ + Period retXtraVer; /* Retain extra versions */ + Period retOnlyVer; /* Retain only versions */ +} BackupCopyData; + +/* CopyGroup + */ +typedef struct { + CopyType copyType; /* Type of copy group: archive, backup, etc */ + union { + ArchiveCopyData archive; + BackupCopyData backup; + } copyData; +} CopyGroup; + +/* CopyId + */ +typedef BSA_UInt64 CopyId; + +/* DataBlock + */ +typedef struct { + BSA_UInt16 bufferLen; + BSA_UInt16 numBytes; /* Actual number of bytes read from */ + /* or written to the buffer, or the */ + /* minimum number of bytes needed */ + char * bufferPtr; +} DataBlock; + +/* DayOfWeek + */ +typedef enum { + BSADayOfWeek_Monday = 1, BSADayOfWeek_Tuesday = 2, + BSADayOfWeek_Wednesday = 3, BSADayOfWeek_Thursday = 4, + BSADayOfWeek_Friday = 5, BSADayOfWeek_Saturday = 6, + BSADayOfWeek_Sunday = 7 +} DayOfWeek; + +/* Environment + */ +typedef struct { + char * envVariables; /* Identifies the Backup Services instance and other */ + /* implementation-dependent variables such as */ + /* communication ports, etc. Each variable is a */ + /* (keyword, value) pair separated by a space. */ + /* If a value contains spaces, it must be */ + /* enclosed in single or double quotes. */ +} BSAEnvironment; + +/* Event + */ +typedef struct { + BSA_UInt32 eventId; /* This is an internal (to Backup Services) id*/ + ObjectOwner objectOwner;/* Identifies the owner of the event */ + struct tm time; /* Identifies the time the action is to start */ + Operation action; /* Identifies the action (backup, archive) */ + ObjectName objName; /* Identifies objects to be acted on */ + ResourceType resourceType;/* Identifies the resource manager for the */ + /* event */ + EventInfo eventInfo; /* User- and resource-manager-specific info */ +} BSAEvent; + +/* MethodName + */ +typedef char EncodingMethod[BSA_MAX_ENCODINGMETHOD]; + +/* ObjectDescriptor + */ +#define ObjectDescriptorVersion 1 +typedef struct { + BSA_UInt32 version; /* Version number for this structure */ + ObjectOwner Owner; /* Owner of the object */ + ObjectName objName; /* Object name */ + struct tm createTime; /* Supplied by Backup Services */ + CopyType copyType; /* Copy type: archive or backup */ + CopyId copyId; /* Supplied by Backup Services */ + BSA_UInt64 restoreOrder; /* Supplied by Backup Services */ + LGName lGName; /* Associated Lifecycle Group name */ + CopyGpName cGName; /* Copy group within the lifecycle group */ + ObjectSize size; /* Object size may be up to 63 bits */ + ResourceType resourceType; /* e.g. UNIX file system */ + ObjectType objectType; /* e.g. file, directory, etc. */ + ObjectStatus status; /* Active/inactive, supplied by */ + /* Backup Services */ + EncodingMethod * encodingList; /* List of encoding Methods used, in */ + /* application-defined order, */ + /* terminated with a null entry */ + Description desc; /* Descriptive label for the object */ + ObjectInfo objectInfo; /* Application information */ +} ObjectDescriptor; + +/* QueryDescriptor + */ +typedef struct { + ObjectOwner owner; /* Owner of the object */ + ObjectName objName; /* Object name */ + struct tm createTimeLB; /* Lower bound on create time */ + struct tm createTimeUB; /* Upper bound on create time */ + struct tm expireTimeLB; /* Lower bound on expiration time */ + struct tm expireTimeUB; /* Upper bound on expiration time */ + CopyType copyType; /* Copy type: archive or backup */ + LGName lGName; /* Associated Lifecycle Group name */ + CopyGpName cGName; /* Copy group within the lifecycle group */ + ResourceType resourceType; /* e.g. UNIX file system */ + ObjectType objectType; /* e.g. file, directory, etc. */ + ObjectStatus status; /* Active/inactive, supplied by Backup */ + /* Services */ + Description desc; /* Descriptive label for the object */ +} QueryDescriptor; /* "*" is interpreted as a meta character */ + /* wild card. */ + /* Any undefined value is interpreted as */ + /* an error. */ + +/* Schedule + */ +typedef struct { + ScheduleId schedId; /* Provided by Backup Services */ + ObjectOwner objectOwner; /* Specifies the owner of the schedule */ + Operation operation; /* Specifies the action to be taken */ + struct tm firstStartTime; /* Specifies the first time the action */ + /* is to take place */ + DayOfWeek day; /* Specifies the day of week for the event*/ + Period frequency; /* Specifies the frequency, e.g. daily */ + ObjectName objectName; /* Identifies objects to be acted on */ + ResourceType resourceType; /* Identifies the resource manager for the*/ + /* schedule */ + EventInfo scheduleInfo; /* Resource manager specific information */ +} Schedule; + +/* Security Token + */ +typedef char SecurityToken[BSA_MAX_TOKEN_SIZE]; + +/* StreamHandle + */ +typedef int StreamHandle; + +/* UserDescriptor + */ +typedef struct t_UserDescriptor { + BSA_UInt16 version; /* Version num of this structure */ + BSAObjectOwner bsaObjectOwner; /* BSA Object owner name */ + DomainName domainName; /* Policy domain for the user */ + Description desc; /* User information */ +} UserDescriptor; + +/* Vote + */ +typedef enum { + BSAVote_COMMIT = 1, + BSAVote_ABORT = 2 +} Vote; + +/* Function Prototypes for Data Movement API Subset + * Note that int and long have been replaced with typedefs + * from custom.h. + */ + +extern BSA_Int16 +BSABeginTxn +( BSA_UInt32 bsaHandle +); + +extern BSA_Int16 +BSAChangeToken +( BSA_UInt32 bsaHandle, + SecurityToken *oldTokenPtr, + SecurityToken *newTokenPtr +); + +extern BSA_Int16 +BSACreateObject +( BSA_UInt32 bsaHandle, + ObjectDescriptor *objectDescriptorPtr, + DataBlock *dataBlockPtr +); + +extern BSA_Int16 +BSACreateObjectF +( BSA_UInt32 bsaHandle, + ObjectDescriptor *objectDescriptorPtr, + StreamHandle *streamPtr +); + +extern BSA_Int16 +BSADeleteObject +( BSA_UInt32 bsaHandle, + CopyType copyType, + ObjectName *objectName, + CopyId *copyId +); + +extern BSA_Int16 +BSAEndData +( BSA_UInt32 bsaHandle +); + +extern BSA_Int16 +BSAEndTxn +( BSA_UInt32 bsaHandle, + Vote vote +); + +extern BSA_Int16 +BSAGetData +( BSA_UInt32 bsaHandle, + DataBlock *dataBlockPtr +); + +extern BSA_Int16 +BSAGetEnvironment +( BSA_UInt32 bsaHandle, + ObjectOwner *objectOwnerPtr, + char **environmentPtr +); + +extern BSA_Int16 +BSAGetNextQueryObject +( BSA_UInt32 bsaHandle, + ObjectDescriptor *objectDescriptorPtr +); + +extern BSA_Int16 +BSAGetObject +( BSA_UInt32 bsaHandle, + ObjectDescriptor *objectDescriptorPtr, + DataBlock *dataBlockPtr +); + +extern BSA_Int16 +BSAGetObjectF +( BSA_UInt32 bsaHandle, + ObjectDescriptor *objectDescriptorPtr, + StreamHandle *streamPtr +); + +extern BSA_Int16 +BSAInit +( BSA_UInt32 *bsaHandleP, + SecurityToken *tokenPtr, + ObjectOwner *objectOwnerPtr, + char **environmentPtr +); + +extern BSA_Int16 +BSAMarkObjectInactive +( BSA_UInt32 bsaHandle, + ObjectName *objectNamePtr +); + +extern void +BSAQueryApiVersion +( ApiVersion *apiVersionPtr +); + +extern BSA_Int16 +BSAQueryObject +( BSA_UInt32 bsaHandle, + QueryDescriptor *queryDescriptorPtr, + ObjectDescriptor *objectDescriptorPtr +); + +extern BSA_Int16 +BSASendData +( BSA_UInt32 bsaHandle, + DataBlock *dataBlockPtr +); + +extern BSA_Int16 +BSASetEnvironment +( BSA_UInt32 bsaHandle, + char **environmentPtr +); + +extern BSA_Int16 +BSATerminate +( BSA_UInt32 bsaHandle +); + +#endif diff --git a/admin_scripts/README b/admin_scripts/README new file mode 100644 index 0000000..fd231e9 --- /dev/null +++ b/admin_scripts/README @@ -0,0 +1,175 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for ADMIN SCRIPT CLP Samples +* +* The /sqllib/samples/admin_scripts directory contains this +* README file where is the location of DB2 9.7 on your hard +* drive. +* The default location for is $HOME on Unix and +* C:\Program Files\IBM on Windows. +* +* This README describes how to run ADMIN SCRIPT CLP sample code for DB2 9.7. +* The DB2 9.7 sample code for CLP is located in the following directory: +* +* /sqllib/samples/admin_scripts +* +* Copy the sample files from this directory to a working directory prior to +* executing the sample programs. The sample program directories are typically +* read-only on most platforms and some samples produce output files that +* require write permissions on the directory. +* +* WARNING: Some of these samples may change your database or database manager +* configuration. Execute the samples against a test database +* only, such as the DB2 SAMPLE database. +* +****************************************************************************** +* +* Prepare your DB2 sample development environment +* +* 1) Copy the files in /sqllib/samples/admin_scripts/* to a +* working directory and ensure that directory has write permission. +* +* On windows platform, all samples should be run and built in a DB2 +* Command Window. The DB2 Command Window is needed to execute db2 +* specific commands. You can follow the step below to open +* DB2 Command window. +* From the Start Menu click Start --> Programs --> IBM DB2 --> +* --> Command Line Tools --> Command Window. +* +* 2) Start the Database Manager with the following command: +* db2start +* +* 3) Create the sample database with the following command: +* db2sampl +* +* 4) Connect to the database with the following command: +* db2 connect to sample +* +* 5) cd to the directory containing the files copied in Step 1. +* +****************************************************************************** +* +* *** Executing ADMIN SCRIPT CLP Samples *** +* +* Use following command to execute ADMIN SCRIPT CLP samples: +* db2 -vf -t +* -- Name of the ADMIN SCRIPT CLP file(including +* the extension). +* +* Note: Use following command to execute the sample "truncate.db2" +* db2 -td@ -vf truncate.db2 +* This sample has '@' as the delimiting character. If any character +* other than default character(;) is used to delimit the statements, +* use this command and replace '@' with the delimiting character. +* +****************************************************************************** +* +* Common file Descriptions +* +* The following are the common files for ADMIN SCRIPT CLP samples. For more +* information on these files, refer to the program source files. +* +****************************************************************************** +* +* Common files +* +* README - this file +* +****************************************************************************** +* +* ADMIN SCRIPT CLP Sample Descriptions +* +* The following are the ADMIN SCRIPT CLP sample files included with DB2. +* For more information on the sample programs, refer to the program source +* files. +* +****************************************************************************** +* +* ADMIN SCRIPT CLP Samples +* +* admincmd_tbload.db2 - How to load data in to table using ADMIN_CMD routine +* alterpartition.db2 - How to perform addition/deletion of partitions on a +* partitioned table +* audit.db2 - To demonstrate the new features in db2audit utility. +* autocfg.db2 - How to automatically configure DB and DBM cfg +* parameters based on the Performance Configuration +* Wizard's recommendations +* autodb.db2 - How to use DB2_ENABLE_AUTOCONFIG_DEFAULT registry +* variable to enable/disable Configuration Advisor at +* database creation. +* autonomous_ - Demonstrate the use of the AUTONOMOUS keyword +* transaction.db2 in the CREATE PROCEDURE statement. +* autorestore.db2 - How to restore a database with automatic storage. +* autostore.db2 - How to create, backup & restore databases enabled +* with automatic storage. +* cgtt.db2 - How to use Created Temporary table with Procedures, +* Functions, Triggers and Views. +* checkv9limits.db2 - To check if any of the v9 identifier length limits have +* been exceeded in the database +* contacts.db2 - How to add, update and drop contacts and +* contactgroups +* databaseroles.db2 - How to use database roles in DB2 LUW. +* fasterrollout.db2 - How to change the default MDC roll out behavior +* to a deferred index cleanup behavior +* gethealthconfig.db2 - How to get definition, alert configuration and +* default alert configurations +* getlogs.db2 - How to get the customer view of diagnostic log file +* entries +* globvarsupport.db2 - How to use global variables with DB2 +* healthmon.db2 - How to use table functions for Health Monitor +* Snapshot +* largerid.db2 - How to enable Large RIDs support on both new tables/ +* tablespaces and existing tables/tablespaces +* lbac.db2 - How to take advantage of DB2 LBAC (Label Based +* Access Control) feature +* monitor.db2 - How to use the table functions MON_GET_CONNECTION +* onlineload.db2 - How to do online loading using the ALLOW READ ACCESS +* option +* partitionindex.db2 - How to create indexes on a partitioned table +* public_alias.db2 - How to use public aliases for database objects such as +* tables and modules. +* redistribute_cmd.db2- How to redistribute the table data among database +* partitions in a partitioned database environment using +* REDISTRIBUTE DATABASE PARTITION GROUP command. +* rollindata.db2 - How to perform data-roll-in into a partitioned table +* rolloutdata.db2 - How to perform data-roll-out from a partitioned table +* security.db2 - How users can query details about the groups, +* authorities, privileges and ownerships +* setintegrity.db2 - How to perform online SET INTEGRITY on a table +* ssv_backup_db.db2 - How to perform database backup in am MPP environment. +* ssv_backup_tbsp.db2 - How to perform tablespace in am MPP environment. +* ssv_db_cfg.db2 - How to update db cfg parameters in an MPP environment. +* tablepartition.db2 - How to create a partitioned table +* tbeventmon.db2 - How to create and use event monitors written to +* a table +* tbonlineinx.db2 - How to create and reorg indexes on a table +* tbsreduce.db2 - How unused storage at the end of a table space can be +* - freed up and reused +* tbrowcompress.db2 - To demonstrate row compression and automatic dictionary +* creation on a table +* tbrunstats.db2 - How to perform runstats on a table +* wlmtiersdefault.db2 - To create a WLM tiered service class configuration +* wlmtierstimerons.db2 - To create a WLM tiered service class configuration +* using cost estimation on initial activity mapping +* wlmtiersdrop.db2 - To remove a WLM tiered service class configuration +* +****************************************************************************** diff --git a/admin_scripts/admincmd_tbload.db2 b/admin_scripts/admincmd_tbload.db2 new file mode 100644 index 0000000..f26d26d --- /dev/null +++ b/admin_scripts/admincmd_tbload.db2 @@ -0,0 +1,93 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: admincmd_tbload.db2 +-- +-- SAMPLE: How to load data in to table using ADMIN_CMD routine. +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- DROP TABLE +-- CALL +-- TERMINATE +-- +-- OUTPUT FILE: admincmd_tbload.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to 'sample' database +CONNECT TO SAMPLE; + +-- create a table to prepare LOAD data +CREATE TABLE temp (c1 INT, c2 VARCHAR(20)); + +-- insert the data into the table 'temp' +INSERT INTO temp VALUES (1, 'A'), (2, 'B'), (3, 'C'); + +-- export the table data to file 'load_file1.ixf'. +! db2 CONNECT TO SAMPLE; +! db2 "EXPORT TO $HOME/load_file1.ixf OF IXF SELECT * FROM temp"; + +-- delete the data from the table 'temp' +DELETE FROM temp; + +-- insert the data into the table 'temp'. +-- (This data will be used for LOAD with REPLACE) +INSERT INTO temp VALUES (11, 'AA'), (12, 'BB'), (13, 'CC'); + +-- export the table data to file 'load_file2.ixf'. +! db2 "EXPORT TO $HOME/load_file2.ixf OF IXF SELECT * FROM temp"; + +-- creating table to be laoded with data +CREATE TABLE temp_load LIKE temp; + +-- loading data from data file inserting data into the table temp_load. +! db2 "CALL ADMIN_CMD('LOAD FROM $HOME/load_file1.ixf of IXF INSERT INTO temp_load')"; + +-- display the contents of the table 'temp_load' +SELECT * FROM temp_load; + +-- loading data from data file replacing data loaded by the previous load. +! db2 "CALL ADMIN_CMD('LOAD FROM $HOME/load_file2.ixf of IXF REPLACE INTO temp_load')"; + +-- display the contents of the table 'temp_load' +SELECT * FROM temp_load; + +-- dropping the table +DROP TABLE temp_load; + +-- Drop the table 'temp' +DROP TABLE temp; + +-- disconnect from the database +CONNECT RESET; + +TERMINATE; + + diff --git a/admin_scripts/alterpartition.db2 b/admin_scripts/alterpartition.db2 new file mode 100644 index 0000000..224e134 --- /dev/null +++ b/admin_scripts/alterpartition.db2 @@ -0,0 +1,142 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: alterpartition.db2 +-- +-- SAMPLE: How to perform addition/deletion of partitions on a partitioned +-- table. +-- +-- This sample shows: +-- 1. How to add a new partition to a partitioned table. +-- 2. How to delete a partition from a partitioned table. +-- +-- SQL STATEMENTS USED: +-- ALTER TABLE +-- CREATE TABLE +-- CREATE TABLESPACE +-- DROP TABLE +-- INSERT +-- SET INTEGRITY +-- TERMINATE +-- +-- OUTPUT FILE: alterpartition.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to database. +CONNECT TO sample; + +-- Create DMS tablespaces. +CREATE TABLESPACE tbsp1 MANAGED BY DATABASE USING (FILE 'conta' 10000); +CREATE TABLESPACE tbsp2 MANAGED BY DATABASE USING (FILE 'contb' 10000); +CREATE TABLESPACE tbsp3 MANAGED BY DATABASE USING (FILE 'contc' 10000); + +-- Creating a partitioned table on a list of tablespaces. A table 'emp_table' +-- with three partitions will be created i.e. part0 is placed in tbsp1, part1 +-- is placed in tbsp2, and part2 is placed in tbsp3. +CREATE TABLE emp_table(emp_no INTEGER NOT NULL, + emp_name VARCHAR(10), + dept VARCHAR(5), + salary DOUBLE DEFAULT 3.14) + IN tbsp1, tbsp2, tbsp3 + PARTITION BY RANGE (emp_no) + (STARTING FROM (1) ENDING (25) EVERY (5), + STARTING FROM (26) ENDING (50) EVERY (10), + STARTING FROM (51) ENDING (75) EVERY (15)); + +-- Show data partitions defined for the base table 'emp_table'. +SELECT seqno, datapartitionid, substr(datapartitionname, 1, 15) + AS datapartitionname, substr(lowvalue, 1, 10) AS lowvalue, + substr(highvalue, 1, 10) AS highvalue FROM SYSCAT.DATAPARTITIONS + WHERE tabname = 'EMP_TABLE' AND tabschema = CURRENT SCHEMA; + +-- Insert data into the base table 'emp_table'. +INSERT INTO emp_table VALUES (1, 'John', 'E31', 4.34), + (26, 'James', 'E32', 3.35), + (51, 'Bill', 'E33', 4.00); + +-- Display the contents of the base table and which partition the rows are +-- in datapartitionnum returns the seqno of the partition. +-- WHERE predicate helps in partition elimination. +SELECT datapartitionnum(emp_no) AS dpnum, emp_no, emp_name, dept, salary + FROM emp_table WHERE emp_no > 1 ORDER BY emp_no; + +-- Detach a partition from the base table 'emp_table'. +ALTER TABLE emp_table DETACH PARTITION part0 INTO TABLE emp_part0; + +-- Display the contents of 'emp_part0'. This table contains DETACHed data. +SELECT * FROM emp_part0; + +-- Display the datapartitionnum of 'emp_table' after DETACH operation is +-- performed. +SELECT datapartitionnum(emp_no) AS dpnum, emp_no, emp_name, dept, salary + FROM emp_table ORDER BY emp_no; + +-- Create a temporary table 'tabletobeattached'. This table will be attached +-- to the base table 'emp_table'. +CREATE TABLE tabletobeattached (emp_no INTEGER NOT NULL, + emp_name VARCHAR(10), + dept VARCHAR(5), + salary DOUBLE DEFAULT 3.14)IN tbsp1; + +-- Insert data into the table 'tabletobeattached'. +INSERT INTO tabletobeattached VALUES (80, 'Sam', 'E36', 3.75); + +-- Display the datapartitionnum of 'tabletobeattached'. Since it is +-- non-partitioned table, datapartitionnum column should return 0. +SELECT datapartitionnum(emp_no) FROM tabletobeattached; + +-- Attach a new partition to the table 'emp_table'. ALTER TABLE statement +-- along with ATTACH clause is used to add a new partition to the base table. +ALTER TABLE emp_table ATTACH PARTITION attach_part + STARTING FROM (76) ENDING (100) INCLUSIVE FROM tabletobeattached; + +-- The previous ATTACH statement puts the table 'emp_table' into check +-- pending state. +-- Before performing SELECT operation on 'emp_table' it needs to be brought +-- out of check pending state. The following SET INTEGRITY statement brings +-- the table out of check pending state and makes the table availabe. +SET INTEGRITY FOR emp_table IMMEDIATE CHECKED; + +-- Display the contents of 'emp_table' after ATTACH is performed. +-- The newely added rows are also displayed. +SELECT * FROM emp_table; + +-- Drop the tables. +DROP TABLE emp_table; + +-- Drop the tablespaces. +DROP TABLESPACE tbsp1; +DROP TABLESPACE tbsp2; +DROP TABLESPACE tbsp3; + +-- Disconnect from database. +CONNECT RESET; + +TERMINATE; diff --git a/admin_scripts/audit.db2 b/admin_scripts/audit.db2 new file mode 100644 index 0000000..b44de4d --- /dev/null +++ b/admin_scripts/audit.db2 @@ -0,0 +1,778 @@ +-- /***************************************************************************/ +-- /* (c) Copyright IBM Corp. 2007 All rights reserved. +-- /* +-- /* The following sample of source code ("Sample") is owned by International +-- /* Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- /* copyrighted and licensed, not sold. You may use, copy, modify, and +-- /* distribute the Sample in any form without payment to IBM, for the purpose of +-- /* assisting you in the development of your applications. +-- /* +-- /* The Sample code is provided to you on an "AS IS" basis, without warranty of +-- /* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- /* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- /* not allow for the exclusion or limitation of implied warranties, so the above +-- /* limitations or exclusions may not apply to you. IBM shall not be liable for +-- /* any damages you suffer as a result of using, copying, modifying or +-- /* distributing the Sample, even if IBM has been advised of the possibility of +-- /* such damages. +-- /***************************************************************************/ +-- /* */ +-- /* SAMPLE FILE NAME: audit.db2 */ +-- /* */ +-- /* PURPOSE : To demonstrate the new features in db2audit utility. */ +-- /* */ +-- /* USAGE SCENARIO : The usage scenario is based on the Online Banking */ +-- /* Transaction Processing (OLTP). In an international bank database, */ +-- /* tables like TRANSACTION, ACCOUNT, PERSONALINFO contain extremely */ +-- /* sensitive information. To track access to these tables, bank can */ +-- /* create many new db2audit policies depending on the roles of people */ +-- /* who are accessing these tables. In future if bank decides to modify */ +-- /* these policies, DB2 provides the bank with the ALTER AUDIT POLICY */ +-- /* command. In a similar way bank can use DROP AUDIT POLICY to drop any */ +-- /* existing audit policies. DB2 facilitates the bank in taking the backup*/ +-- /* of audit data for future reference using db2audit archive command and */ +-- /* retrieving the data using extract command. DB2 provides one more */ +-- /* method to archive and extract the audit data using AUDIT_ARCHIVE */ +-- /* and AUDIT_DELIM_EXTRACT stored procedure respectively. */ +-- /* */ +-- /* PREREQUISITE : */ +-- /* 1. Two userid's present on the machine. */ +-- /* 2. One user with SYSADM authority. */ +-- /* 3. Second user name is joe, password is abcd1234 */ +-- /* */ +-- /* EXECUTION : db2 -tvf audit.db2 */ +-- /* */ +-- /* INPUTS : NONE */ +-- /* */ +-- /* OUTPUT : Audit data in the form of delimited files in side */ +-- /* the current working directory */ +-- /* */ +-- /* OUTPUT FILE : audit.out */ +-- /* (available in the online documentation) */ +-- /***************************************************************************/ +-- /*For more information about the command line processor (CLP) scripts, */ +-- /*see the README file. */ +-- /*For information on using SQL statements, see the SQL Reference. */ +-- /* */ +-- /*For the latest information on programming, building, and running DB2 */ +-- /*applications, visit the DB2 application development website: */ +-- /*http://www.software.ibm.com/data/db2/udb/ad */ +-- /***************************************************************************/ + +-- /***************************************************************************/ +-- /* SAMPLE DESCRIPTION */ +-- /***************************************************************************/ +-- /* 1. Setup the db2audit environment. */ +-- /* 2. Create, alter and drop audit policies. */ +-- /* 3. Apply AUDIT statement on different objects. */ +-- /* 4. Run transactions to generate audit data. */ +-- /* 5. Archive the audit data to different location. */ +-- /* 6. Extract the audit data when required. */ +-- /* 7. Loading the extracted del files to view the audit data. */ +-- /***************************************************************************/ + +-- /***************************************************************************/ +-- /* SETUP THE DB2AUDIT ENVIRONMENT */ +-- /***************************************************************************/ + +-- +-- Create a database BANKDB and connect to BANKDB. +-- +CREATE DATABASE BANKDB; + +CONNECT TO BANKDB; + +-- +-- Create an 8K bufferpool. +-- +CREATE BUFFERPOOL bpool8k SIZE 20000 PAGESIZE 8 K; + +-- +-- Create an 8K tablespace associating the bufferpool bpool8k. +-- +CREATE TABLESPACE tbsp_8k + PAGESIZE 8 K + BUFFERPOOL bpool8k; + +-- +-- Grant the SECADM privilege to execute the audit statements. +-- +GRANT SECADM ON DATABASE TO USER joe; + +-- +-- Grant the EXECUTE privilege to execute the audit routines. +-- +GRANT EXECUTE ON FUNCTION SYSPROC.AUDIT_ARCHIVE TO USER joe; +GRANT EXECUTE ON PROCEDURE SYSPROC.AUDIT_ARCHIVE TO USER joe; +GRANT EXECUTE ON PROCEDURE SYSPROC.AUDIT_DELIM_EXTRACT TO USER joe; +GRANT EXECUTE ON FUNCTION SYSPROC.AUDIT_LIST_LOGS TO USER joe; + +-- +-- Connect to BANKDB as SECADM. +-- +CONNECT TO BANKDB USER joe USING abcd1234; + +-- +-- Execute the db2audit DDL to create audit tables. +-- AUDIT CATEGORY +-- +CREATE TABLE DB2AUDIT.AUDIT ( TIMESTAMP CHAR(32 OCTETS), + CATEGORY CHAR(32 OCTETS), + EVENT VARCHAR(32 OCTETS), + CORRELATOR INTEGER, + STATUS INTEGER, + USERID VARCHAR(1024 OCTETS), + AUTHID VARCHAR(128 OCTETS), + DATABASE CHAR(8 OCTETS), + NODENUM SMALLINT, + COORDNUM SMALLINT, + APPID VARCHAR(255 OCTETS), + APPNAME VARCHAR(1024 OCTETS), + PKGSCHEMA VARCHAR(128 OCTETS), + PKGNAME VARCHAR(128 OCTETS), + PKGSECNUM SMALLINT, + PKGVER VARCHAR(64 OCTETS), + LCLTRANSID VARCHAR(16 OCTETS) FOR BIT DATA, + GLBLTRANSID VARCHAR(32 OCTETS) FOR BIT DATA, + CLNTUSERID VARCHAR(255 OCTETS), + CLNTWRKSTNAME VARCHAR(255 OCTETS), + CLNTAPPNAME VARCHAR(255 OCTETS), + CLNTACCSTRING VARCHAR(255 OCTETS), + TRSTCTXNAME VARCHAR(255 OCTETS), + CONTRSTTYPE CHAR(1 OCTETS), + ROLEINHERITED VARCHAR(128 OCTETS), + POLNAME VARCHAR(128 OCTETS), + POLASSOCOBJTYPE CHAR(10 OCTETS), + POLASSOCSUBOBJTYPE CHAR(10 OCTETS), + POLASSOCNAME VARCHAR(128 OCTETS), + OBJSCHEMA VARCHAR(128 OCTETS), + AUDITSTATUS CHAR(1 OCTETS), + CHECKINGSTATUS CHAR(1 OCTETS), + CONTEXTSTATUS CHAR(1 OCTETS), + EXECUTESTATUS CHAR(1 OCTETS), + EXECUTEDATA CHAR(1 OCTETS), + OBJMAINTSTATUS CHAR(1 OCTETS), + SECMAINTSTATUS CHAR(1 OCTETS), + SYSADMINSTATUS CHAR(1 OCTETS), + VALIDATESTATUS CHAR(1 OCTETS), + ERRORTYPE CHAR(8 OCTETS), + DATAPATH VARCHAR(1024 OCTETS), + ARCHIVEPATH VARCHAR(1024 OCTETS), + ORIGUSERID VARCHAR(1024 OCTETS), + INSTNAME VARCHAR(128 OCTETS), + HOSTNAME VARCHAR(255 OCTETS)); + +-- +-- CHECKING CATEGORY +-- + +CREATE TABLE DB2AUDIT.CHECKING ( TIMESTAMP CHAR(32 OCTETS), + CATEGORY CHAR(32 OCTETS), + EVENT VARCHAR(32 OCTETS), + CORRELATOR INTEGER, + STATUS INTEGER, + DATABASE CHAR(8 OCTETS), + USERID VARCHAR(1024 OCTETS), + AUTHID VARCHAR(128 OCTETS), + NODENUM SMALLINT, + COORDNUM SMALLINT, + APPID VARCHAR(255 OCTETS), + APPNAME VARCHAR(1024 OCTETS), + PKGSCHEMA VARCHAR(128 OCTETS), + PKGNAME VARCHAR(128 OCTETS), + PKGSECNUM SMALLINT, + OBJSCHEMA VARCHAR(128 OCTETS), + OBJNAME VARCHAR(128 OCTETS), + OBJTYPE VARCHAR(32 OCTETS), + ACCESSAPP CHAR(34 OCTETS), + ACCESSATT CHAR(34 OCTETS), + PKGVER VARCHAR(64 OCTETS), + CHKAUTHID VARCHAR(128 OCTETS), + LCLTRANSID VARCHAR(16 OCTETS) FOR BIT DATA, + GLBLTRANSID VARCHAR(32 OCTETS) FOR BIT DATA, + CLNTUSERID VARCHAR(255 OCTETS), + CLNTWRKSTNAME VARCHAR(255 OCTETS), + CLNTAPPNAME VARCHAR(255 OCTETS), + CLNTACCSTRING VARCHAR(255 OCTETS), + TRSTCTXNAME VARCHAR(255 OCTETS), + CONTRSTTYPE CHAR(1 OCTETS), + ROLEINHERITED VARCHAR(128 OCTETS), + ORIGUSERID VARCHAR(1024 OCTETS), + INSTNAME VARCHAR(128 OCTETS), + HOSTNAME VARCHAR(255 OCTETS)); + +-- +-- OBJMAINT CATEGORY +-- + +CREATE TABLE DB2AUDIT.OBJMAINT ( TIMESTAMP CHAR(32 OCTETS), + CATEGORY CHAR(32 OCTETS), + EVENT VARCHAR(32 OCTETS), + CORRELATOR INTEGER, + STATUS INTEGER, + DATABASE CHAR(8 OCTETS), + USERID VARCHAR(1024 OCTETS), + AUTHID VARCHAR(128 OCTETS), + NODENUM SMALLINT, + COORDNUM SMALLINT, + APPID VARCHAR(255 OCTETS), + APPNAME VARCHAR(1024 OCTETS), + PKGSCHEMA VARCHAR(128 OCTETS), + PKGNAME VARCHAR(128 OCTETS), + PKGSECNUM SMALLINT, + OBJSCHEMA VARCHAR(128 OCTETS), + OBJNAME VARCHAR(128 OCTETS), + OBJTYPE VARCHAR(32 OCTETS), + PACKVER VARCHAR(64 OCTETS), + SECPOLNAME VARCHAR(128 OCTETS), + ALTERACTION VARCHAR(32 OCTETS), + PROTCOLNAME VARCHAR(128 OCTETS), + COLSECLABEL VARCHAR(128 OCTETS), + SECCOLNAME VARCHAR(128 OCTETS), + LCLTRANSID VARCHAR(16 OCTETS) FOR BIT DATA, + GLBLTRANSID VARCHAR(32 OCTETS) FOR BIT DATA, + CLNTUSERID VARCHAR(255 OCTETS), + CLNTWRKSTNAME VARCHAR(255 OCTETS), + CLNTAPPNAME VARCHAR(255 OCTETS), + CLNTACCSTRING VARCHAR(255 OCTETS), + TRSTCTXNAME VARCHAR(255 OCTETS), + CONTRSTTYPE CHAR(1 OCTETS), + ROLEINHERITED VARCHAR(128 OCTETS), + MODULENAME VARCHAR(128 OCTETS), + ASSOCOBJNAME VARCHAR(128 OCTETS), + ASSOCOBJSCHEMA VARCHAR(128 OCTETS), + ASSOCOBJTYPE VARCHAR(32 OCTETS), + ASSOCSUBOBJNAME VARCHAR(128 OCTETS), + ASSOCSUBOBJTYPE VARCHAR(32 OCTETS), + SECURED VARCHAR(32 OCTETS), + STATE VARCHAR(32 OCTETS), + ACCESSCONTROL VARCHAR(32 OCTETS), + ORIGUSERID VARCHAR(1024 OCTETS), + INSTNAME VARCHAR(128 OCTETS), + HOSTNAME VARCHAR(255 OCTETS)); + + +-- +-- SECMAINT CATEGORY +-- + +CREATE TABLE DB2AUDIT.SECMAINT ( TIMESTAMP CHAR(32 OCTETS), + CATEGORY CHAR(32 OCTETS), + EVENT VARCHAR(32 OCTETS), + CORRELATOR INTEGER, + STATUS INTEGER, + DATABASE CHAR(8 OCTETS), + USERID VARCHAR(1024 OCTETS), + AUTHID VARCHAR(128 OCTETS), + NODENUM SMALLINT, + COORDNUM SMALLINT, + APPID VARCHAR(255 OCTETS), + APPNAME VARCHAR(1024 OCTETS), + PKGSCHEMA VARCHAR(128 OCTETS), + PKGNAME VARCHAR(128 OCTETS), + PKGSECNUM SMALLINT, + OBJSCHEMA VARCHAR(128 OCTETS), + OBJNAME VARCHAR(128 OCTETS), + OBJTYPE VARCHAR(32 OCTETS), + GRANTOR VARCHAR(128 OCTETS), + GRANTEE VARCHAR(128 OCTETS), + GRANTEETYPE VARCHAR(32 OCTETS), + PRIVAUTH CHAR(34 OCTETS), + PKGVER VARCHAR(64 OCTETS), + ACCESSTYPE VARCHAR(32 OCTETS), + ASSUMEAUTHID VARCHAR(128 OCTETS), + LCLTRANSID VARCHAR(16 OCTETS) FOR BIT DATA, + GLBLTRANSID VARCHAR(32 OCTETS) FOR BIT DATA, + GRANTORTYPE VARCHAR(32 OCTETS), + CLNTUSERID VARCHAR(255 OCTETS), + CLNTWRKSTNAME VARCHAR(255 OCTETS), + CLNTAPPNAME VARCHAR(255 OCTETS), + CLNTACCSTRING VARCHAR(255 OCTETS), + TRSTCTXUSER VARCHAR(128 OCTETS), + TRSTCTXUSERAUTH INTEGER, + TRSTCTXNAME VARCHAR(255 OCTETS), + CONTRSTTYPE CHAR(1 OCTETS), + ROLEINHERITED VARCHAR(128 OCTETS), + ALTERACTION VARCHAR(32 OCTETS), + ASSOCOBJNAME VARCHAR(128 OCTETS), + ASSOCOBJSCHEMA VARCHAR(128 OCTETS), + ASSOCOBJTYPE VARCHAR(32 OCTETS), + ASSOCSUBOBJNAME VARCHAR(128 OCTETS), + ASSOCSUBOBJTYPE VARCHAR(32 OCTETS), + SECURED VARCHAR(32 OCTETS), + STATE VARCHAR(32 OCTETS), + ACCESSCONTROL VARCHAR(32 OCTETS), + ORIGUSERID VARCHAR(1024 OCTETS), + INSTNAME VARCHAR(128 OCTETS), + HOSTNAME VARCHAR(255 OCTETS)); + + +-- +-- SYSADMIN CATEGORY +-- + +CREATE TABLE DB2AUDIT.SYSADMIN ( TIMESTAMP CHAR(32 OCTETS), + CATEGORY CHAR(32 OCTETS), + EVENT VARCHAR(32 OCTETS), + CORRELATOR INTEGER, + STATUS INTEGER, + DATABASE CHAR(8 OCTETS), + USERID VARCHAR(1024 OCTETS), + AUTHID VARCHAR(128 OCTETS), + NODENUM SMALLINT, + COORDNUM SMALLINT, + APPID VARCHAR(255 OCTETS), + APPNAME VARCHAR(1024 OCTETS), + PKGSCHEMA VARCHAR(128 OCTETS), + PKGNAME VARCHAR(128 OCTETS), + PKGSECNUM SMALLINT, + PKGVER VARCHAR(64 OCTETS), + LCLTRANSID VARCHAR(16 OCTETS) FOR BIT DATA, + GLBLTRANSID VARCHAR(32 OCTETS) FOR BIT DATA, + CLNTUSERID VARCHAR(255 OCTETS), + CLNTWRKSTNAME VARCHAR(255 OCTETS), + CLNTAPPNAME VARCHAR(255 OCTETS), + CLNTACCSTRING VARCHAR(255 OCTETS), + TRSTCTXNAME VARCHAR(255 OCTETS), + CONTRSTTYPE CHAR(1 OCTETS), + ROLEINHERITED VARCHAR(128 OCTETS), + ORIGUSERID VARCHAR(1024 OCTETS), + EVENTDETAILS VARCHAR(2048 OCTETS), + INSTNAME VARCHAR(128 OCTETS), + HOSTNAME VARCHAR(255 OCTETS)); + +-- +-- VALIDATE CATEGORY +-- + +CREATE TABLE DB2AUDIT.VALIDATE ( TIMESTAMP CHAR(32 OCTETS), + CATEGORY CHAR(32 OCTETS), + EVENT VARCHAR(32 OCTETS), + CORRELATOR INTEGER, + STATUS INTEGER, + DATABASE CHAR(8 OCTETS), + USERID VARCHAR(1024 OCTETS), + AUTHID VARCHAR(128 OCTETS), + EXECID VARCHAR(1024 OCTETS), + NODENUM SMALLINT, + COORDNUM SMALLINT, + APPID VARCHAR(255 OCTETS), + APPNAME VARCHAR(1024 OCTETS), + AUTHTYPE VARCHAR(32 OCTETS), + PKGSCHEMA VARCHAR(128 OCTETS), + PKGNAME VARCHAR(128 OCTETS), + PKGSECNUM SMALLINT, + PKGVER VARCHAR(64 OCTETS), + LCLTRANSID VARCHAR(16 OCTETS) FOR BIT DATA, + GLBLTRANSID VARCHAR(32 OCTETS) FOR BIT DATA, + PLUGINNAME VARCHAR(32 OCTETS), + CLNTUSERID VARCHAR(255 OCTETS), + CLNTWRKSTNAME VARCHAR(255 OCTETS), + CLNTAPPNAME VARCHAR(255 OCTETS), + CLNTACCSTRING VARCHAR(255 OCTETS), + TRSTCTXNAME VARCHAR(255 OCTETS), + CONTRSTTYPE CHAR(1 OCTETS), + ROLEINHERITED VARCHAR(128 OCTETS), + ORIGUSERID VARCHAR(1024 OCTETS), + INSTNAME VARCHAR(128 OCTETS), + HOSTNAME VARCHAR(255 OCTETS)); + +-- +-- CONTEXT CATEGORY +-- + +CREATE TABLE DB2AUDIT.CONTEXT ( TIMESTAMP CHAR(32 OCTETS), + CATEGORY CHAR(32 OCTETS), + EVENT VARCHAR(32 OCTETS), + CORRELATOR INTEGER, + DATABASE CHAR(8 OCTETS), + USERID VARCHAR(1024 OCTETS), + AUTHID VARCHAR(128 OCTETS), + NODENUM SMALLINT, + COORDNUM SMALLINT, + APPID VARCHAR(255 OCTETS), + APPNAME VARCHAR(1024 OCTETS), + PKGSCHEMA VARCHAR(128 OCTETS), + PKGNAME VARCHAR(128 OCTETS), + PKGSECNUM SMALLINT, + STMTTEXT CLOB(2M OCTETS), + PKGVER VARCHAR(64 OCTETS), + LCLTRANSID VARCHAR(16 OCTETS) FOR BIT DATA, + GLBLTRANSID VARCHAR(64 OCTETS) FOR BIT DATA, + CLNTUSERID VARCHAR(255 OCTETS), + CLNTWRKSTNAME VARCHAR(255 OCTETS), + CLNTAPPNAME VARCHAR(255 OCTETS), + CLNTACCSTRING VARCHAR(255 OCTETS), + TRSTCTXNAME VARCHAR(255 OCTETS), + CONTRSTTYPE CHAR(1 OCTETS), + ROLEINHERITED VARCHAR(255 OCTETS), + ORIGUSERID VARCHAR(1024 OCTETS), + INSTNAME VARCHAR(128 OCTETS), + HOSTNAME VARCHAR(255 OCTETS)); + +-- +-- EXECUTE CATEGORY +-- + +CREATE TABLE DB2AUDIT.EXECUTE ( TIMESTAMP CHAR(32 OCTETS), + CATEGORY CHAR(32 OCTETS), + EVENT VARCHAR(32 OCTETS), + CORRELATOR INTEGER, + STATUS INTEGER, + DATABASE CHAR(8 OCTETS), + USERID VARCHAR(1024 OCTETS), + AUTHID VARCHAR(128 OCTETS), + SESSNAUTHID VARCHAR(128 OCTETS), + NODENUM SMALLINT, + COORDNUM SMALLINT, + APPID VARCHAR(255 OCTETS), + APPNAME VARCHAR(1024 OCTETS), + CLNTUSERID VARCHAR(255 OCTETS), + CLNTWRKSTNAME VARCHAR(255 OCTETS), + CLNTAPPNAME VARCHAR(255 OCTETS), + CLNTACCSTRING VARCHAR(255 OCTETS), + TRSTCTXNAME VARCHAR(255 OCTETS), + CONTRSTTYPE CHAR(1 OCTETS), + ROLEINHERITED VARCHAR(128 OCTETS), + PKGSCHEMA VARCHAR(128 OCTETS), + PKGNAME VARCHAR(128 OCTETS), + PKGSECNUM SMALLINT, + PKGVER VARCHAR(64 OCTETS), + LCLTRANSID VARCHAR(10 OCTETS) FOR BIT DATA, + GLBLTRANSID VARCHAR(30 OCTETS) FOR BIT DATA, + UOWID BIGINT, + ACTIVITYID BIGINT, + STMTINVOCID BIGINT, + STMTNESTLVL BIGINT, + STMTTYPE VARCHAR(128 OCTETS), + STMTISOLATIONLVL CHAR(128 OCTETS), + ROWSREAD CHAR(128 OCTETS), + ROWSMODIFIED CHAR(32 OCTETS), + ROWSRETURNED CHAR(16 OCTETS), + STMTTEXT CLOB(2M OCTETS), + COMPENVDESC BLOB(8K), + STMTVALINDEX INTEGER, + STMTVALTYPE CHAR(16 OCTETS), + STMTVALDATA CLOB(32K OCTETS), + LOCAL_START_TIME CHAR(32 OCTETS), + ORIGUSERID VARCHAR(1024 OCTETS), + INSTNAME VARCHAR(128 OCTETS), + HOSTNAME VARCHAR(255 OCTETS)); + +-- +-- Configure the datapath and archivepath for audit purpose. +-- +! db2audit CONFIGURE datapath "$HOME" + archivepath "$HOME"; + +-- /***************************************************************************/ +-- /* CREATE THE REQUIRED BANK TABLES */ +-- /***************************************************************************/ + +-- +-- Create TRANSACTION, ACCOUNT and PERSONALINFO tables. +-- +CREATE TABLE TRANSACTION ( AccNo INT NOT NULL, + TrDate DATE, + TrType VARCHAR(10), + Amount DECIMAL(7,2), + Remarks VARCHAR(50) ); + +CREATE TABLE ACCOUNT ( CName VARCHAR(30), + AccType VARCHAR(10) NOT NULL, + AccNo INT NOT NULL PRIMARY KEY, + CType VARCHAR(10), + TrDate DATE, + Balance DECIMAL(9,2), + Remarks VARCHAR(50) ); + +CREATE TABLE PERSONALINFO ( CName VARCHAR(30), + CType VARCHAR(10), + CPhone VARCHAR(15), + CAddress VARCHAR(100), + LoanInfo VARCHAR(50), + Remarks VARCHAR(50) ); + +-- /***************************************************************************/ +-- /* CREATE AUDIT POLYCIES */ +-- /***************************************************************************/ + +-- +-- Create TRANSACTIONPOLICY to generate the audit records to show the +-- execution of SQL statements. +-- +CREATE AUDIT POLICY TRANSACTIONPOLICY + CATEGORIES EXECUTE STATUS BOTH + ERROR TYPE AUDIT; + +-- +-- Create ACCOUNTPOLICY to generate the audit records for any thing happening +-- on the table. +-- +CREATE AUDIT POLICY ACCOUNTPOLICY + CATEGORIES ALL STATUS BOTH + ERROR TYPE AUDIT; + +-- +-- Create PERSONALADMINPOLICY to generate the audit records when +-- creating or dropping data objects, +-- granting or revoking object privileges, +-- granting or revoking database privileges, +-- granting or revoking DBADM authority, +-- authenticating users or retrieving system +-- security information related to a user. +-- +CREATE AUDIT POLICY PERSONALADMINPOLICY + CATEGORIES OBJMAINT STATUS BOTH, + SECMAINT STATUS BOTH, + SYSADMIN STATUS BOTH, + VALIDATE STATUS FAILURE + ERROR TYPE AUDIT; + +COMMIT; + +-- /***************************************************************************/ +-- /* ALTER AUDIT POLYCY */ +-- /***************************************************************************/ + +-- +-- Alter the current policy TRANSACTIONPOLICY to audit all the information. +-- +ALTER AUDIT POLICY TRANSACTIONPOLICY + CATEGORIES ALL STATUS BOTH + ERROR TYPE AUDIT; + +COMMIT; + +-- /***************************************************************************/ +-- /* DROP AUDIT POLYCY */ +-- /***************************************************************************/ + +-- +-- Drop the the current policy TRANSACTIONPOLICY +-- +-- DROP AUDIT POLICY TRANSACTIONPOLICY; +-- COMMIT; + +-- /***************************************************************************/ +-- /* APPLY AUDIT STATEMENTS ON DIFFERENT OBJECTS */ +-- /***************************************************************************/ + +-- +-- Audit the database using the TRANSACTIONPOLICY policy. +-- +AUDIT DATABASE USING POLICY TRANSACTIONPOLICY; + +-- +-- Audit the table ACCOUNT using ACCOUNTPOLICY policy. +-- +AUDIT TABLE ACCOUNT USING POLICY ACCOUNTPOLICY; + +-- +-- Audit the SYSADM, SYSMAINT, SECADM, DBADM activities using +-- PERSONALADMINPOLICY policy. +-- +AUDIT SYSADM, SYSMAINT, SECADM, DBADM USING POLICY PERSONALADMINPOLICY; + +-- /***************************************************************************/ +-- /* RUN TRANSACTIONS */ +-- /***************************************************************************/ + +-- +-- Run transactions on table TRANSACTION +-- Insert records into the table TRANSACTION +-- +INSERT INTO TRANSACTION VALUES ( 1000, '2007-01-20', 'CREDIT', 2000.00, '2000$ + got credited from AccNo 01232 Citi Bank'); +INSERT INTO TRANSACTION VALUES ( 1000, '2007-01-20', 'CREDIT', 1050.00, '1050$ + got credited from AccNo 98211 AMEX Bank'); +INSERT INTO TRANSACTION VALUES ( 1000, '2007-01-20', 'DEBIT', 100.00, '100$ got + debited and credited to American Express'); +INSERT INTO TRANSACTION VALUES ( 1000, '2007-01-21', 'CREDIT', 200.00, '200$ + got credited from AccNo 87342 HSBC Bank'); +INSERT INTO TRANSACTION VALUES ( 1000, '2007-01-23', 'CREDIT', 400.00, '400$ + got credited from AccNo 81234 HSBC Bank'); +INSERT INTO TRANSACTION VALUES ( 1000, '2007-01-26', 'DEBIT', 600.00, '600$ + got debited and credited to AMEX Loan'); +INSERT INTO TRANSACTION VALUES ( 1000, '2007-01-30', 'CREDIT', 4000.00, '4000$ + got credited BI-MONTHLY Salary for JAN 2007'); +COMMIT; + +-- +-- Select the records from TRANSACTION +-- +SELECT TrDate, TrType, Amount, Remarks FROM TRANSACTION; + +-- +-- Run transactions on table ACCOUNT +-- Insert records into the table ACCOUNT +-- +INSERT INTO ACCOUNT VALUES ( 'MOHAN SARASWATIPURA', 'SALARY', 1000, 'GOLD', + '2007-01-30', 20000.00, 'Balance amount + is 20000$'); +INSERT INTO ACCOUNT VALUES ( 'PRAVEEN SOGALAD', 'SALARY', 1010, 'GOLD', + '2007-01-30', 20200.00, 'Balance amount is 20200$'); +INSERT INTO ACCOUNT VALUES ( 'SANJAY KUMAR', 'SALARY', 1020, 'GOLD','2007-02-13', + 30010.00, 'Balance amount is 30010$'); +INSERT INTO ACCOUNT VALUES ( 'GAURAV SHUKLA', 'SALARY', 2001, 'GOLD','2007-01-30', + 15001.00, 'Balance amount is 15001$'); +INSERT INTO ACCOUNT VALUES ( 'ITI RAWAT', 'SALARY', 1030, 'GOLD','2007-01-30', + 30000.00, 'Balance amount is 30000$'); +INSERT INTO ACCOUNT VALUES ( 'MARK TAYLOR', 'SAVING', 4030, 'GOLD','2007-01-30', + 52000.00, 'Balance amount is 52000$'); +COMMIT; + +-- +-- Select the records from ACCOUNT +-- +SELECT CName, AccType, AccNo, TrDate, Balance FROM ACCOUNT; + +-- +-- Run transactions on table PERSONALINFO +-- Insert records into the table PERSONALINFO +-- +INSERT INTO PERSONALINFO VALUES ( 'MOHAN SARASWATIPURA', 'GOLD', '9880012396', + 'VIJAYNAGAR, BANGALORE', 'PERSONAL LOAN PLoanNo: + 1233812', 'GOLD CUSTOMER'); +INSERT INTO PERSONALINFO VALUES ( 'PRAVEEN SOGALAD', 'GOLD', '9881212391', + 'VIJAYNAGAR, BANGALORE', 'HOME LOAN HLoanNo: + 0129111', 'GOLD CUSTOMER'); +INSERT INTO PERSONALINFO VALUES ( 'SANJAY KUMAR', 'GOLD', '9900012345', + 'INDIRANAGAR, BANGALORE', 'HOME LOAN HLoanNo: + 1112911', 'GOLD CUSTOMER'); +INSERT INTO PERSONALINFO VALUES ( 'GAURAV SHUKLA', 'GOLD', '9900054321', + 'RAJAJINAGAR, BANGALORE', 'No Information', + 'GOLD CUSTOMER'); +INSERT INTO PERSONALINFO VALUES ( 'ITI RAWAT', 'GOLD', '9990012345', + 'INDIRANAGAR, BANGALORE', 'HOME LOAN HLoanNo: + 2112911', 'GOLD CUSTOMER'); +INSERT INTO PERSONALINFO VALUES ( 'MARK TAYLOR', 'GOLD', '602-712121', + 'ARIZONA, USA', 'No Information', 'GOLD CUSTOMER'); + +-- /***************************************************************************/ +-- /* ARCHIVE THE AUDIT LOGS */ +-- /***************************************************************************/ + +-- +-- Archive the audit data to different location. +-- METHOD: 1 +-- Archival using normal db2audit command. +-- +-- ! db2audit ARCHIVE DATABASE BANKDB TO "$HOME"; + +-- METHOD: 2 +-- Archival can also be enabled using the stored procedure. +-- +! db2 "CONNECT TO BANKDB USER joe USING abcd1234"; +CALL SYSPROC.AUDIT_ARCHIVE(NULL,0); +-- +-- Parameter NULL specifies '$HOME' as the default archive location. +-- -2 instead of 0 enables the archive on all the nodes in case of MPP setup. +-- + +-- /***************************************************************************/ +-- /* EXTRACT THE AUDIT LOGS */ +-- /***************************************************************************/ + +-- +-- Extract the audit data from the archive logs to AUDIT directory. +-- + +! db2 "CONNECT TO BANKDB USER joe USING abcd1234"; +CALL SYSPROC.AUDIT_DELIM_EXTRACT (';',NULL,NULL, + 'db2audit.db.BANKDB.log.%.20%',' '); + +-- +-- Parameter ';' specifies the delimiter in extracted log files. +-- Parameter NULL specifies '$HOME' as the default audit logs extract location. +-- Parameter NULL specifies '$HOME' as the archive logs location. +-- Parameter 'db2audit.db.BANKDB.log.%.20%' specifies the log name. +-- Parameter ' ' directs stored procedure to extract all the activities. +-- One can specify 'execute status failure' to extract only the execute +-- failures. +-- + +-- /***************************************************************************/ +-- /* IMPORT DELIMITED FILES TO AUDIT TABLES */ +-- /***************************************************************************/ + +-- +-- Import the extracted del files to audit tables for auditing purpose. +-- Uncomment the comments to load the data into audit tables +-- DB2AUDIT.AUDIT +-- DB2AUDIT.CHECKING +-- DB2AUDIT.OBJMAINT +-- DB2AUDIT.SECMAINT +-- DB2AUDIT.SYSADMIN +-- DB2AUDIT.VALIDATE +-- DB2AUDIT.CONTEXT +-- DB2AUDIT.EXECUTE +-- + + +! db2stop force; +! db2start; + +-- ! db2 "CONNECT TO BANKDB USER joe USING abcd1234"; +-- ! db2 "SET SCHEMA DB2AUDIT"; +-- ! db2 "IMPORT FROM $HOME/audit.del OF DEL REPLACE INTO AUDIT"; +-- ! db2 "IMPORT FROM $HOME/checking.del OF DEL REPLACE INTO CHECKING"; +-- ! db2 "IMPORT FROM $HOME/objmaint.del OF DEL REPLACE INTO OBJMAINT"; +-- ! db2 "IMPORT FROM $HOME/secmaint.del OF DEL REPLACE INTO SECMAINT"; +-- ! db2 "IMPORT FROM $HOME/sysadmin.del OF DEL REPLACE INTO SYSADMIN"; +-- ! db2 "IMPORT FROM $HOME/validate.del OF DEL REPLACE INTO VALIDATE"; +-- ! db2 "IMPORT FROM $HOME/context.del OF DEL REPLACE INTO CONTEXT"; +-- ! db2 "IMPORT FROM $HOME/execute.del OF DEL REPLACE INTO EXECUTE"; + +-- /***************************************************************************/ +-- /* VIEW THE AUDIT DATA */ +-- /***************************************************************************/ +-- +-- Connect to database BANKDB; +-- Execute select statement on the tables +-- DB2AUDIT.AUDIT +-- DB2AUDIT.CHECKING +-- DB2AUDIT.OBJMAINT +-- DB2AUDIT.SECMAINT +-- DB2AUDIT.SYSADMIN +-- DB2AUDIT.VALIDATE +-- DB2AUDIT.CONTEXT +-- DB2AUDIT.EXECUTE +-- Uncomment the comments to view the records + +-- ! db2 "CONNECT TO BANKDB USER joe USING abcd1234"; +-- ! db2 "SET SCHEMA DB2AUDIT"; +-- ! db2 "SELECT * FROM AUDIT"; +-- ! db2 "SELECT * FROM CHECKING"; +-- ! db2 "SELECT * FROM OBJMAINT"; +-- ! db2 "SELECT * FROM SECMAINT"; +-- ! db2 "SELECT * FROM SYSADMIN"; +-- ! db2 "SELECT * FROM VALIDATE"; +-- ! db2 "SELECT * FROM CONTEXT"; +-- ! db2 "SELECT * FROM EXECUTE"; + +-- /***************************************************************************/ +-- /* CLEAN UP */ +-- /***************************************************************************/ + +! db2stop force; +! db2start; +DROP DB BANKDB; + +! rm $HOME/audit.del; +! rm $HOME/checking.del; +! rm $HOME/context.del; +! rm $HOME/execute.del; +! rm $HOME/objmaint.del; +! rm $HOME/secmaint.del; +! rm $HOME/sysadmin.del; +! rm $HOME/validate.del; +! rm -rf $HOME/db2audit.db.BANKDB.*; +! rm $HOME/auditlobs; + +TERMINATE; + +-- /***************************************************************************/ +-- /* END OF SAMPLE */ +-- /***************************************************************************/ diff --git a/admin_scripts/autocfg.db2 b/admin_scripts/autocfg.db2 new file mode 100644 index 0000000..28684ff --- /dev/null +++ b/admin_scripts/autocfg.db2 @@ -0,0 +1,100 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: autocfg.db2 +-- +-- SAMPLE: How to automatically configure DB and DBM cfg parameters based on +-- the Performance Configuration Wizard's recommendations. +-- +-- SQL STATEMENT USED: +-- CREATE +-- AUTOCONFIGURE +-- CONNECT +-- GET DB CFG +-- DROP +-- +-- OUTPUT FILE: autocfg.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Disconnect from any existing database connection +CONNECT RESET; + +-- Create a database EXAMPLE using AUTOCONFIGURE parameter +-- Use 'APPLY DB ONLY' to display and apply the recommended changes to +-- DB cfg, buffer pool settings + +CREATE DATABASE EXAMPLE + AUTOCONFIGURE USING MEM_PERCENT 80 NUM_STMTS 20 + APPLY DB ONLY; + +-- Restarting the instance to make these changes effective +DB2STOP FORCE; +DB2START; + +-- Use 'APPLY DB AND DBM' to display and apply the recommended changes to +-- DB cfg and DBM cfg, buffer pool settings +-- NOTE: Un-commenting and running this will change the DBM cfg parameters + + -- DROP DB EXAMPLE; + -- CREATE DATABASE EXAMPLE + -- AUTOCONFIGURE USING MEM_PERCENT 70 NUM_LOCAL_APPS 20 NUM_STMTS 20 + -- APPLY DB AND DBM; + + -- Restarting the instance to make these changes effective + -- DB2STOP FORCE; + -- DB2START; + +-- Use 'APPLY NONE' to display recommended changes without applying them +DROP DB EXAMPLE; +CREATE DATABASE EXAMPLE + AUTOCONFIGURE USING MEM_PERCENT 70 NUM_LOCAL_APPS 20 NUM_STMTS 20 + APPLY NONE; + +-- Restarting the instance to make these changes effective +DB2STOP FORCE; +DB2START; + +-- To autoconfigure an existing EXAMPLE database +CONNECT TO EXAMPLE; +AUTOCONFIGURE USING MEM_PERCENT 90 APPLY DB ONLY; +CONNECT RESET; + +-- Restarting the instance to make these changes effective +DB2STOP FORCE; +DB2START; + +-- To obtain DB cfg parameters values set by AUTOCONFIGURE +CONNECT TO EXAMPLE; +GET DB CFG FOR EXAMPLE SHOW DETAIL; +CONNECT RESET; + +-- Drop EXAMPLE database +DROP DB EXAMPLE; +TERMINATE; diff --git a/admin_scripts/autodb.db2 b/admin_scripts/autodb.db2 new file mode 100644 index 0000000..74434fd --- /dev/null +++ b/admin_scripts/autodb.db2 @@ -0,0 +1,177 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: autodb.db2 +-- +-- SAMPLE: How to use DB2_ENABLE_AUTOCONFIG_DEFAULT registry variable to +-- enable/disable the Configuration Advisor at database creation. +-- +-- SQL STATEMENT USED: +-- AUTOCONFIGURE +-- CREATE DB +-- DROP DB +-- GET DB CFG +-- +-- OUTPUT FILE: autodb.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Disconnect from any existing database connection. +CONNECT RESET; + +-- The registry variable DB2_ENABLE_AUTOCONFIG_DEFAULT controls the auto +-- enablement of the Configuration Advisor at database creation time. +-- Valid values for this registry variable are: +-- YES : Enable Configuration Advisor at database creation. +-- : (default) same as "YES". +-- Enable Configuration Advisor at database creation +-- NO : Do not run the Configuration Advisor at database creation. + +-- DB2_ENABLE_AUTOCONFIG_DEFAULT is a dynamic variable and hence instance +-- restart is not required when it is set. +-- Registry variable can be set using +-- db2set DB2_ENABLE_AUTOCONFIG_DEFAULT=YES + +-- If DB2_ENABLE_AUTOCONFIG_DEFAULT is either set to "YES" or , the +-- Configuration Advisor is enabled at database creation time and the database +-- configuration parameters will be tuned. + +-- If DB2_ENABLE_AUTOCONFIG_DEFAULT is set to "NO", the Configuration +-- Advisor is disabled at database creation time and the database +-- configuration parameters will not be tuned. However, if AUTOCONFIGURE +-- or CREATE DB AUTOCONFIGURE commands are executed, then this overrides the +-- DB2_ENABLE_AUTOCONFIG_DEFAULT setting, and the Configuration Advisor will +-- always be executed against the database since an explicit +-- statement (AUTOCONFIGURE) has been made. + +-- NOTE: The below example results are applicable to non-DPF systems + +-- EXAMPLES: +------------ + +-- Example 1: Setting DB2_ENABLE_AUTOCONFIG_DEFAULT = + +! db2set DB2_ENABLE_AUTOCONFIG_DEFAULT= ; +CREATE DB test; + +GET DB CFG FOR test; + +-- Expected Result: +------------------- + +-- The DB CFG parameters should be tuned by the Configuration Advisor. +-- In addition, the following STMM (Self Tuning Memory Management) +-- and Auto Runstats parameters should be ON or AUTOMATIC: + +-- Sort heap threshold (4KB) (SHEAPTHRES) = 0 +-- Self tuning memory (SELF_TUNING_MEM) = ON +-- Package cache size (4KB) (PCKCACHESZ) = AUTOMATIC +-- Sort list heap (4KB) (SORTHEAP) = AUTOMATIC +-- Sort heap thres for shared sorts (4KB) (SHEAPTHRES_SHR) = AUTOMATIC +-- Max storage for lock list (4KB) (LOCKLIST) = AUTOMATIC +-- Percent. of lock lists per application (MAXLOCKS) = AUTOMATIC +-- Size of database shared memory (4KB) (DATABASE_MEMORY) = AUTOMATIC +-- Automatic maintenance (AUTO_MAINT) = ON +-- Automatic table maintenance (AUTO_TBL_MAINT) = ON +-- Automatic runstats (AUTO_RUNSTATS) = ON + +-- If you wish to disable STMM or Auto Runstats on the database, this can be +-- done by updating the SELF_TUNING_MEM or AUTO_RUNSTATS database +-- configuration parameters, respectively, using the UPDATE DB CFG command. + +-- Note: When DB2_ENABLE_AUTOCONFIG_DEFAULT=YES, you should get the same +-- behaviour as when DB2_ENABLE_AUTOCONFIG_DEFAULT= + +DROP DB test; +----------------------------------------------------------------------------- +-- Example 2: Setting DB2_ENABLE_AUTOCONFIG_DEFAULT=NO + +! db2set DB2_ENABLE_AUTOCONFIG_DEFAULT=NO ; +CREATE DB test; + +GET DB CFG FOR test; + +-- Expected Result: +---------------- +-- The DB CFG parameters should NOT be tuned by the Configuration Advisor +-- In addition, the following STMM and Auto Runstats parameters should be ON +-- or AUTOMATIC: + +-- Sort heap threshold (4KB) (SHEAPTHRES) = 0 +-- Self tuning memory (SELF_TUNING_MEM) = ON +-- Package cache size (4KB) (PCKCACHESZ) = AUTOMATIC +-- Sort list heap (4KB) (SORTHEAP) = AUTOMATIC +-- Sort heap thres for shared sorts (4KB) (SHEAPTHRES_SHR) = AUTOMATIC +-- Max storage for lock list (4KB) (LOCKLIST) = AUTOMATIC +-- Percent. of lock lists per application (MAXLOCKS) = AUTOMATIC +-- Size of database shared memory (4KB) (DATABASE_MEMORY) = AUTOMATIC +-- Automatic maintenance (AUTO_MAINT) = ON +-- Automatic table maintenance (AUTO_TBL_MAINT) = ON +-- Automatic runstats (AUTO_RUNSTATS) = ON + +-- If you wish to disable STMM or Auto Runstats on the database, this can be +-- done by updating the SELF_TUNING_MEM or AUTO_RUNSTATS database +-- configuration parameters, respectively, using the UPDATE DB CFG command. + +DROP DB test; +----------------------------------------------------------------------------- + +-- Example 3: AUTOCONFIGURE keyword overrides DB2_ENABLE_AUTOCONFIG_DEFAULT +-- value setting + +! db2set DB2_ENABLE_AUTOCONFIG_DEFAULT=NO; +CREATE DB test AUTOCONFIGURE APPLY DB ONLY; + +GET DB CFG FOR test; + +-- Expected Result: +------------------- +-- The DB CFG parameters should be tuned by the Configuration Advisor +-- In addition, the following STMM and Auto Runstats parameters should +-- be ON or AUTOMATIC: + +-- Sort heap threshold (4KB) (SHEAPTHRES) = 0 +-- Self tuning memory (SELF_TUNING_MEM) = ON +-- Package cache size (4KB) (PCKCACHESZ) = AUTOMATIC +-- Sort list heap (4KB) (SORTHEAP) = AUTOMATIC +-- Sort heap thres for shared sorts (4KB) (SHEAPTHRES_SHR) = AUTOMATIC +-- Max storage for lock list (4KB) (LOCKLIST) = AUTOMATIC +-- Percent. of lock lists per application (MAXLOCKS) = AUTOMATIC +-- Size of database shared memory (4KB) (DATABASE_MEMORY) = AUTOMATIC +-- Automatic maintenance (AUTO_MAINT) = ON +-- Automatic table maintenance (AUTO_TBL_MAINT) = ON +-- Automatic runstats (AUTO_RUNSTATS) = ON + +-- In this case, the explicit call to AUTOCONFIGURE in the CREATE DB statement +-- has taken precedence over the DB2_ENABLE_AUTOCONFIG_DEFAULT=NO value, i.e., +-- the Configuration Advisor has been executed against the database. +-- Using the AUTOCONFIGURE command against an existing database will have the +-- same effect. + +DROP DB test; diff --git a/admin_scripts/autonomous_transaction.db2 b/admin_scripts/autonomous_transaction.db2 new file mode 100644 index 0000000..f44fcb7 --- /dev/null +++ b/admin_scripts/autonomous_transaction.db2 @@ -0,0 +1,630 @@ +--/**************************************************************************** +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ****************************************************************************** +-- +-- SAMPLE FILE NAME: autonomous_transaction.db2 +-- +-- PURPOSE : The purpose of this sample is to demonstrate the use of +-- the AUTONOMOUS keyword in the CREATE PROCEDURE statement. +-- +-- USAGE SCENARIO : In an enterprise, each employee has some privileges on +-- certain tables and procedures. The employees use stored +-- procedures to perform operations on the table. The employees +-- cannot access those tables on which they do not have access +-- privileges. If any employee tries to access any restricted +-- data, an autonomous procedure will log the complete event and +-- store the details in a log table. At the end of day, the +-- administrator can check all the events. +-- +-- PREREQUISITE : The following users should exist in the operating system. +-- +-- john with password "john12345" in SYSADM group +-- bob with password "bob12345" +-- pat with password "pat12345" +-- +-- EXECUTION : db2 -td@ -vf autonomous_transaction.db2 +-- +-- INPUTS : NONE +-- +-- OUTPUT : Successful execution of autonomous procedure. +-- +-- OUTPUT FILE : autonomous_transaction.out (available in the online documentation) +-- +-- DEPENDENCIES : NONE +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- CREATE PROCEDURE +-- DROP TABLE +-- DROP PROCEDURE +-- INSERT +-- SELECT +-- UPDATE TABLE +-- +-- ************************************************************************* +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- +-- http://www.ibm.com/software/data/db2/ad/ +-- +-- ************************************************************************* +-- +-- SAMPLE DESCRIPTION +-- +-- 1. The data is stored in the following tables: + +-- a) TEMP_EMPLOYEE : Contains employee details. +-- b) TEMP_PAYROLL : Contains the employees' salary details. +-- c) EVENT_LOG : Contains the details of all the events performed +-- by the user. + +-- 2. The application is processed using the following procedures: +-- +-- a) UPDATE_SALARY : Procedure to update the salary. The user passes the +-- employee's experience, work department, and new salary +-- as the parameters. +-- +-- b) REPORT_GENERATE : Procedure to generate the employee's salary report. +-- +-- c) EVENT_LOG : An autonomous procedure to store the events performed +-- by the user. +-- +-- SAMPLE DETAILS +-- +-- (1) The user JOHN is the administrator with SYSADM authority. JOHN +-- creates two stored procedures; UPDATE_SALARY, REPORT_GENERATE, +-- and an autonomous procedure EVENT_LOG. A table EVENT_LOG is +-- also created by JOHN to store all the events. +-- +-- (2) BOB and PAT are non-administrator users. BOB is from the Payroll +-- department and has access to the TEMP_PAYROLL table and TEMP_EMPLOYEE table. +-- BOB can also update the employees' salary with the help of a stored +-- procedure UPDATE_SALARY. +-- +-- (3) The user PAT is also from the Payroll department and his job is to generate the +-- reports. This is done with the help of a stored procedure REPORT_GENERATE. +-- +-- (4) BOB invokes the procedure UPDATE_SALARY to update the salary and PAT +-- invokes the procedure REPORT_GENERATE to generate the report. +-- +-- (5) When PAT tries to invoke the procedure UPDATE_SALARY to access the +-- TEMP_PAYROLL and TEMP_EMPLOYEE tables, an autonomous procedure EVENT_LOG is +-- automatically invoked as PAT does not have sufficient privileges to +-- perform this operation. Hence, the transaction is rolled back and the event +-- is logged in the EVENT_TABLE. +-- +-- (6) Later, the administrator (JOHN) will invoke the table EVENT_LOG to track +-- all the events in the EVENT_LOG table. +-- +-- ************************************************************************* + +-- *************************************************************************/ +-- SET UP */ +-- *************************************************************************/ + +-- /******************************************************/ +-- /* User JOHN creates the tables */ +-- /******************************************************/ + +-- Connect to sample database +CONNECT TO sample USER john USING john12345@ + +echo@ +echo **************************@ +echo CREATE TABLES @ +echo **************************@ +echo@ + +-- Create table temp_employee under 'JOHN' schema + +CREATE TABLE temp_employee( +empno CHAR(6), +empname VARCHAR(10), +lastname VARCHAR(10), +workdept CHAR(3), +bonus DECIMAL(9,2), +hiredate DATE)@ + +-- Create table temp_payroll under 'JOHN' schema + +CREATE TABLE temp_payroll( +empno CHAR(6), +salary DECIMAL(9,2))@ + +-- Create table event_log under 'JOHN' schema. +-- The event_log table stores the session user, the event performed by the user, +-- the event time, and the event date. + +CREATE TABLE event_log( +user_name VARCHAR(10), +event VARCHAR(65), +event_time TIME, +event_date DATE)@ + + +echo@ +echo **************************@ +echo INSERT DATA INTO TABLES @ +echo **************************@ +echo@ + +-- Insert data into temp_employee table from employee table +INSERT INTO temp_employee VALUES +('000010', 'CHRISTINE', 'HAAS', 'A00', 1000.00, '01/01/1995')@ +INSERT INTO temp_employee VALUES +('000020', 'MICHAEL', 'THOMPSON', 'B01', 800.00, '10/10/2003')@ +INSERT INTO temp_employee VALUES +('000030', 'SALLY', 'KWAN', 'C01', 800.00, '04/05/2005')@ +INSERT INTO temp_employee VALUES +('000050', 'JACK', 'GEYER', 'E01', 800.00, '08/17/1979')@ +INSERT INTO temp_employee VALUES +('000060', 'IRVING', 'STERN', 'D11', 500.00, '09/14/2003')@ +INSERT INTO temp_employee VALUES +('000070', 'EVA', 'PULASKI', 'D21', 700.00, '09/30/2005')@ +INSERT INTO temp_employee VALUES +('000090', 'EILEEN', 'HENDERSON', 'E11', 600.00, '08/15/2000')@ +INSERT INTO temp_employee VALUES +('000100', 'THEODORE', 'SPENSER', 'E21', 500.00, '06/19/2000')@ +INSERT INTO temp_employee VALUES +('000110', 'VINCENZO', 'LUCCHESSI', 'A00', 900.00, '05/16/1988')@ + + +-- Insert data into temp_payroll table +INSERT INTO temp_payroll VALUES +('000010', 10000.500)@ +INSERT INTO temp_payroll VALUES +('000020', 12000.430)@ +INSERT INTO temp_payroll VALUES +('000030', 11600.600)@ +INSERT INTO temp_payroll VALUES +('000050', 10560.450)@ +INSERT INTO temp_payroll VALUES +('000060', 13000.500)@ +INSERT INTO temp_payroll VALUES +('000070', 11640.600)@ +INSERT INTO temp_payroll VALUES +('000090', 12560.450)@ +INSERT INTO temp_payroll VALUES +('000100', 13894.556)@ + + +echo@ +echo **************************@ +echo FETCH DATA FROM TABLES @ +echo **************************@ +echo@ + +-- Fetch data from temp_employee +SELECT * FROM temp_employee@ + +-- Fetch data from temp_payroll +SELECT * FROM temp_payroll@ + + +echo@ +echo@ +echo **************************@ +echo CREATE PROCEDURE event_log@ +echo **************************@ +echo@ +echo@ + +-- Create autonomous procedure "event_log" to log the event. Each procedure +-- will call this procedure before any operation. While calling +-- event_log procedure, each procedure will pass the event name as an argument. +-- "event_log" procedure inserts the event in "event_log" table. + +CREATE PROCEDURE event_log(IN event CHAR(1)) + AUTONOMOUS + LANGUAGE SQL + BEGIN + CASE event + WHEN 'U' + THEN INSERT INTO event_log + VALUES(SESSION_USER, + 'CALLING salary_update PROCEDURE TO UPDATE THE SALARY', + CURRENT TIME, + CURRENT DATE); + + WHEN 'S' + THEN INSERT INTO event_log + VALUES(SESSION_USER, + 'CALLING report_generate PROCEDURE TO VIEW EMPLOYEES SALARY', + CURRENT TIME, + CURRENT DATE); + + END CASE; + END@ + + +echo@ +echo@ +echo *******************************@ +echo CREATE PROCEDURE update_salary @ +echo *******************************@ +echo@ +echo@ + +-- Create procedure "update_salary" to perform the salary update. +-- Caller user passes the employees' total experience, +-- work department, and new salary as arguments. The "update_salary" +-- procedure will update the salary of employees' whose work department +-- and total experience is equal to the passed arguments. Only the user +-- BOB can update the salary. + +CREATE PROCEDURE update_salary + (IN exp INTEGER, + IN workdpt CHAR(3), + IN new_salary INTEGER) + LANGUAGE SQL + BEGIN + CALL event_log('U'); + UPDATE temp_payroll + SET salary = salary + new_salary + WHERE empno = + (SELECT empno FROM temp_employee WHERE workdept = workdpt + AND (CURRENT DATE - hiredate) > exp); + + IF (USER <> 'BOB') + THEN + ROLLBACK; + END IF; + END@ + + +echo@ +echo@ +echo *********************************@ +echo CREATE PROCEDURE report_generate @ +echo *********************************@ +echo@ +echo@ + +-- Create procedure "report_generate". This procedure +-- will generate the report of employee salary details. Only the user +-- PAT can generate the report. + +CREATE PROCEDURE report_generate() + LANGUAGE SQL + BEGIN + DECLARE v_empfn CHAR(10); + DECLARE v_empln CHAR(10); + DECLARE v_empsal DECIMAL(9,2); + DECLARE c_report_gen CURSOR; + SET c_report_gen= CURSOR FOR SELECT empname, lastname, salary + FROM temp_employee t1, temp_payroll t2 + WHERE t1.empno = t2.empno; + CALL event_log('S'); + IF (USER <> 'PAT') + THEN + ROLLBACK; + ELSE + OPEN c_report_gen; + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('---------------'); + CALL DBMS_OUTPUT.PUT_LINE('EMPLOYEE REPORT'); + CALL DBMS_OUTPUT.PUT_LINE('---------------'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE(''); + CALL DBMS_OUTPUT.PUT + ('EMP NAME '||' '||'LASTNAME '||' '||'SALARY'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT + ('-----------'||' '||'-----------'||' '||'-----------'); + CALL DBMS_OUTPUT.NEW_LINE; + + fetch_loop: + LOOP + FETCH FROM c_report_gen INTO v_empfn, v_empln, v_empsal; + + IF c_report_gen IS NOT FOUND + THEN LEAVE fetch_loop; + END IF; + + CALL DBMS_OUTPUT.PUT(v_empfn); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_empln); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_empsal); + CALL DBMS_OUTPUT.NEW_LINE; + + END LOOP fetch_loop; + CLOSE c_report_gen; + END IF; + END@ + + +-- /*************************************************** +-- /* GRANT EXECUTE privileges to users +-- /*************************************************** + +echo@ +echo@ +echo ************************************************@ +echo GRANT EXECUTE PRIVILEGES ON PROCEDURES TO USERS @ +echo ************************************************@ +echo@ +echo@ + +-- Grant execute privilege to user BOB on procedure update_salary +GRANT EXECUTE ON PROCEDURE update_salary TO USER bob@ + +-- Grant execute privilege to user BOB on procedure report_generate +GRANT EXECUTE ON PROCEDURE report_generate TO USER bob@ + +-- Grant execute privilege to user PAT on procedure report_generate +GRANT EXECUTE ON PROCEDURE report_generate TO USER pat@ + +-- Grant execute privilege to user PAT on procedure update_salary +GRANT EXECUTE ON PROCEDURE update_salary TO USER pat@ + +-- RESET CONNECTION +CONNECT RESET@ + +-- CALL PROCEDURES TO PERFORM DIFFERENT OPERATIONS@ + +echo@ +echo@ +echo ***************************************@ +echo FETCH SALARY OF EMPLOYEES BEFORE @ +echo CALLING update_salary STORED PROECDURE @ +echo ***************************************@ +echo@ +echo@ + + +-- Fetch salary of employees before calling update_salary procedure +-- by user BOB. + +-- Connect to database +CONNECT TO sample USER john USING john12345@ + +SELECT salary FROM temp_payroll + WHERE empno = (SELECT empno FROM temp_employee + WHERE workdept = 'D11' + AND (CURRENT DATE - hiredate) > 5)@ + + +-- CALL Procedure update_salary to update the salary + +echo@ +echo User BOB calls procedure update_salary @ +echo TO UPDATE THE SALARY@ +echo@ + +-- RESET CONNECTION +CONNECT RESET@ + +-- Connect to database +CONNECT TO sample user bob using bob12345@ + +CALL JOHN.update_salary(5, 'D11', 2000)@ + + +echo@ +echo@ +echo ***************************************@ +echo FETCH SALARY OF EMPLOYEES AFTER @ +echo CALLING update_salary STORED PROECDURE @ +echo ***************************************@ +echo@ +echo@ + +-- Fetch salary of employees after calling update_salary procedure +-- by user BOB. + +-- RESET CONNECTION +CONNECT RESET@ + +-- Connect to database +CONNECT TO sample user john using john12345@ + +SELECT salary FROM temp_payroll + WHERE empno = (SELECT empno FROM temp_employee + WHERE workdept = 'D11' + AND (CURRENT DATE - hiredate) > 5)@ + + +echo@ +echo@ +echo ****************************************@ +echo USER PAT CALLS PROCEDURE report_generate@ +echo TO GENERATE THE REPORTS @ +echo ****************************************@ +echo@ +echo@ + + +-- RESET CONNECTION +CONNECT RESET@ + +-- Connect to sample database +CONNECT TO sample user pat using pat12345@ + +-- CALL procedure to generate the report +SET SERVEROUTPUT ON@ +CALL JOHN.report_generate()@ + + +-- The only user who has the appropriate privilege to execute the procedure +-- "update_salary" is BOB. So when the user PAT invokes the procedure +-- "update_salary", the procedure will check if the user is BOB. If the user +-- is not BOB, all the transactions will be rolled back but the event will be +-- logged as the event is passed as argument to the autonomous procedure. + +echo@ +echo@ +echo **************************************@ +echo FETCH SALARY OF EMPLOYEES BEFORE @ +echo CALLING update_salary STORED PROECDURE@ +echo **************************************@ +echo@ +echo@ + +-- RESET CONNECTION +CONNECT RESET@ + +-- Select salary of employees before calling update_salary procedure +-- by user PAT. + +-- Connect to database +CONNECT TO sample user john using john12345@ + +SELECT salary FROM temp_payroll + WHERE empno = (SELECT empno FROM temp_employee + WHERE workdept = 'D11' + AND (CURRENT DATE - hiredate) > 5)@ + + +echo@ +echo@ +echo ***************************************@ +echo USER PAT CALLS PROCEDURE update_salary @ +echo TO UPDATE THE SALARY @ +echo ***************************************@ +echo@ +echo@ + +-- RESET CONNECTION +CONNECT RESET@ + +-- Connect to database +CONNECT TO sample user pat using pat12345@ + +CALL JOHN.update_salary(5, 'D11', 2000)@ + +echo@ +echo@ +echo ***************************************@ +echo FETCH SALARY OF EMPLOYEES AFTER @ +echo CALLING update_salary STORED PROECDURE @ +echo ***************************************@ +echo@ +echo@ + +-- Select salary of employees after calling update_salary procedure +-- by user PAT. + +-- RESET CONNECTION +CONNECT RESET@ + +-- Connect to database +CONNECT TO sample user john using john12345@ + +SELECT salary FROM temp_payroll + WHERE empno = (SELECT empno FROM temp_employee + WHERE workdept = 'D11' + AND (CURRENT DATE - hiredate) > 5)@ + +echo@ +echo The above output is expected as the session user is not BOB.@ +echo So all the transactions will be rolled back and salary will @ +echo remain same but the event will be logged in event_log table.@ +echo@ + + +-- RESET CONNECTION +CONNECT RESET@ + +-- Connect to database +CONNECT TO sample user bob using bob12345@ + +echo@ +echo@ +echo ****************************************@ +echo USER bob CALLS PROCEDURE report_generate@ +echo TO GENERATE THE REPORT @ +echo ****************************************@ +echo@ +echo@ + +CALL JOHN.report_generate()@ +SET SERVEROUTPUT ON@ + +echo@ +echo The above output is expected as session user is not PAT. @ +echo So report will not generate but the event will be logged in@ +echo event_log table. @ +echo@ + +-- RESET CONNECTION +CONNECT RESET@ + +-- Track all the events. +CONNECT TO sample USER john USING john12345@ + +echo@ +echo@ +echo ********************************@ +echo FETCH DATA FROM event_log TABLE @ +echo ********************************@ +echo@ +echo@ + +SELECT * FROM event_log@ + + +-- Disconnect from sample database +CONNECT RESET@ + + +-- ************************************************* +-- CLEAN UP +-- ************************************************* + +echo@ +echo@ +echo *******************************@ +echo DROP ALL TABLES AND PROCEDURES @ +echo *******************************@ +echo@ +echo@ + +-- Drop tables and procedures +CONNECT TO sample USER john USING john12345@ + +-- Drop table temp_employee +DROP TABLE temp_employee@ + +-- Drop table temp_payroll +DROP TABLE temp_payroll@ + +-- Drop table event_log +DROP TABLE event_log@ + +-- Drop procedure update_salary +DROP PROCEDURE update_salary@ + +-- Drop procedure report_generate +DROP PROCEDURE report_generate@ + +-- Drop procedure event_log +DROP PROCEDURE event_log@ + +-- Connect reset +CONNECT RESET@ + + diff --git a/admin_scripts/autorestore.db2 b/admin_scripts/autorestore.db2 new file mode 100644 index 0000000..ad03880 --- /dev/null +++ b/admin_scripts/autorestore.db2 @@ -0,0 +1,126 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: autorestore.db2 +-- +-- SAMPLE: How to restore a database with automatic storage. +-- +-- SQL STATEMENT USED: +-- CREATE DATABASE +-- DROP DATABASE +-- RESTORE DATABASE +-- BACKUP DATABASE +-- TERMINATE +-- +-- Note: This sample requires an MPP environment with 3 nodes. +-- +-- OUTPUT FILE: autorestore.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Following directories will be used for restoring the database on new +-- storage paths. +!mkdir $HOME/storpath1; +!mkdir $HOME/storpath2; +!mkdir $HOME/dbpath; +!mkdir $HOME/storpath3; +!mkdir $HOME/storpath4; +!mkdir $HOME/storpath5; +!mkdir $HOME/storpath6; + +-- Create a database enabled for automatic storage with two storage paths and +-- on a specified database path. +-- The storage paths used are: $HOME/storpath1, $HOME/storpath2 +-- The database path use is : $HOME/dbpath + +! db2 CREATE DATABASE TESTDB AUTOMATIC STORAGE YES ON + $HOME/storpath1, $HOME/storpath2 DBPATH ON $HOME/dbpath; + +-- Backup the database 'TESTDB' on all partitions. +! db2_all "db2 BACKUP DATABASE TESTDB"; + +-- The sample demonstrates three scenarios of database restore. +-- CASE 1: Database with automatic storage enabled pre-exists. User wants +-- to restore all db partitions, using old storage paths. +-- User can issue restore on each db partition in any order, or in parallel. + +-- Use 'db2_all' utility to execute restore on all partitions. +-- A warning is expected for all restore commands as the database is +-- identical to the backup. +-- Following command will be executed on all db partitions. +! db2_all "db2 RESTORE DATABASE TESTDB WITHOUT PROMPTING"; + +-- CASE 2: Database with automatic storage enabled pre-exists.User wants to +-- restore from the catalog partition, using a new set of storage paths. + +-- Use 'db2_all' utility to execute restore command on individual partitions. +-- Following command will be executed on partition 0(catalog partition). +! db2_all "<<+0 500000 AND payable_tax <= 1000000 THEN + SET payable_tax = payable_tax * 0.20; + ELSEIF payable_tax > 1000000 THEN + SET payable_tax = payable_tax * 0.30; + END IF; + + SET payable_tax = payable_tax + (awarded_pay * 0.30); + RETURN payable_tax; +END@ + + +-- Create procedure 'tax_pay' to calculate the tax payable by the employees. +-- For a finnancial year a tax exemption of +-- 100,000 is given to all the employees. +-- This procedure calls the function 'tax_compute' to calculate +-- tax. + +CREATE PROCEDURE initial_tax_compute() +SPECIFIC initialTax +LANGUAGE SQL +BEGIN + DECLARE id CHARACTER(6); + DECLARE at_end SMALLINT DEFAULT 0; + DECLARE salary DECFLOAT; + DECLARE payable_tax DECFLOAT; + DECLARE not_found CONDITION for SQLSTATE '02000'; + + DECLARE IterateOverEmpRecord CURSOR WITH HOLD FOR SELECT empid,salaryPA FROM payroll; + DECLARE CONTINUE HANDLER for not_found SET at_end = 1; + + OPEN IterateOverEmpRecord; + + ins_loop: LOOP + FETCH IterateOverEmpRecord INTO id,salary; + + IF at_end = 1 THEN + LEAVE ins_loop; + ELSE + + UPDATE payroll SET tax_payable = tax_compute(salary,100000,0) WHERE empid = id; + COMMIT; + ITERATE ins_loop; + END IF; + END LOOP; + + CLOSE IterateOverEmpRecord; +END@ + +-- Create procedure 'update' to update the CGTT 'cgtt.tax_cal' with the tax +-- payable by an employee, calculated by the procedure 'final_tax_compute'. + +CREATE PROCEDURE update() +SPECIFIC updater +LANGUAGE SQL +BEGIN + DECLARE at_end SMALLINT DEFAULT 0; + DECLARE id CHARACTER(6); + DECLARE tax_left DECFLOAT; + DECLARE tax_p DECFLOAT; + DECLARE not_found CONDITION FOR SQLSTATE '02000'; + + DECLARE UpdateCGTT CURSOR WITH HOLD FOR + SELECT empno,tax_to_be_paid,tax_payable + FROM cgtt.tax_cal; + DECLARE UpdatePayroll CURSOR WITH HOLD FOR + SELECT empno,tax_to_be_paid,tax_payable + FROM cgtt.tax_cal; + DECLARE CONTINUE HANDLER for not_found SET at_end = 1; + + OPEN UpdateCGTT; + + up_loop: LOOP + FETCH UpdateCGTT INTO id,tax_left,tax_p; + + IF at_end = 1 THEN + LEAVE up_loop; + ELSE + UPDATE cgtt.tax_cal SET tax_payable = tax_left, + tax_to_be_paid = tax_left - tax_p + WHERE empno = id; + ITERATE up_loop; + END IF; + END LOOP; + + CLOSE UpdateCGTT; + + SET at_end = 0; + OPEN UpdatePayroll; + + update_payroll: LOOP + FETCH UpdatePayroll INTO id,tax_left,tax_p; + + IF at_end = 1 THEN + LEAVE update_payroll; + ELSE + UPDATE payroll SET tax_payable = tax_p, + tax_to_be_paid = tax_left + WHERE empid = id; + ITERATE update_payroll; + END IF; + END LOOP; + + CLOSE UpdatePayroll; + + +END@ + +-- Create procedure 'final_tax_compute' to select employee records from the +-- created temporary table 'cgtt.tax_cal' and call the function 'tax_compute' +-- to calculate the tax. + +CREATE PROCEDURE final_tax_compute() +SPECIFIC finalTax +LANGUAGE SQL +BEGIN + DECLARE id CHARACTER(6); + DECLARE at_end SMALLINT DEFAULT 0; + DECLARE salary DECFLOAT; + DECLARE exempted DECFLOAT; + DECLARE proof DECFLOAT; + DECLARE awarded_pay DECFLOAT; + DECLARE bonus DECFLOAT; + DECLARE comm DECFLOAT; + DECLARE not_found CONDITION for SQLSTATE '02000'; + + DECLARE IterateOverEmpRecord CURSOR WITH HOLD FOR + SELECT empno,bonus,comm,salaryPA,tax_exempted,tax_proof FROM cgtt.tax_cal; + DECLARE CONTINUE HANDLER for not_found SET at_end = 1; + + OPEN IterateOverEmpRecord; + + ins_loop: LOOP + FETCH IterateOverEmpRecord INTO id, bonus, comm, salary, exempted, proof; + + IF at_end = 1 THEN + LEAVE ins_loop; + ELSE + IF exempted > proof THEN + SET exempted = proof; + END IF; + SET awarded_pay = bonus + comm; + + UPDATE cgtt.tax_cal SET tax_to_be_paid = tax_compute(salary,exempted,awarded_pay) WHERE empno = id; + ITERATE ins_loop; + END IF; + END LOOP; + + CLOSE IterateOverEmpRecord; + +END@ + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- Step4: Create a function 'printITSheet' to print IT sheet for the -- +-- employees, using data in the created temporary table -- +-- 'cgtt.tax_cal' through the view 'ViewOnCgtt'. -- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +CREATE FUNCTION printITSheet() +SPECIFIC ITSheet +RETURNS TABLE (empno CHARACTER(6), + firstnme VARCHAR(12), + lastname VARCHAR(15), + birthdate DATE, + bonus DECFLOAT, + comm DECFLOAT, + salarypa DECFLOAT, + tax_to_be_paid DECFLOAT) +LANGUAGE SQL +NO EXTERNAL ACTION +READS SQL DATA +RETURN + SELECT empno, firstnme, lastname, birthdate, bonus, comm, salarypa, tax_to_be_paid + FROM cgtt.ViewOnCgtt@ + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-- Step 5: Create Trigger 'tax_update' on 'Payroll' table to start the tax -- +-- calculation process. -- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- The trigger is invoked on update of calculate_tax column of payroll table. -- +-- The trigger populates the created temporary table 'tax_cal' and calls the -- +-- procedure 'final_tax_compute' to start tax computation process. -- +-------------------------------------------------------------------------------- + +CREATE TRIGGER tax_update AFTER UPDATE OF calculate_tax ON payroll +REFERENCING NEW TABLE AS new +FOR EACH STATEMENT +BEGIN ATOMIC + + INSERT INTO cgtt.tax_cal + (empno, firstnme, lastname, birthdate, bonus, comm, salarypa, tax_payable, + tax_exempted, tax_to_be_paid, tax_proof, deptno) + (SELECT e.empno, e.firstnme, e.lastname, e.birthdate, e.bonus, e.comm, + p.salarypa, p.tax_payable, p.tax_exempted, p.tax_to_be_paid, + p.tax_proof, p.deptno + FROM employee AS e, payroll AS p + WHERE e.empno = p.empid AND p.tax_exempted > 0 AND p.deptno = + (SELECT DISTINCT deptno FROM payroll WHERE calculate_tax = 1)); + + CALL final_tax_compute(); +END@ + + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- Step6: Start the tax computation process. -- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +-- Call the procedure 'tax_pay' to calculate the tax_payable +-- by an employee depending on his income and update the +-- 'payroll' table +CALL initial_tax_compute()@ + +-- Update the 'payroll' table with the tax proof submitted by the employees. +-- For ease of demonstration, set tax exemption for each employee as 100,000 +-- and proof submitted by the employee as 50,000. +-- After all the employees of a department submit their tax proofs, update +-- the calculate_tax column of payroll table to 1. +-- This update invokes the trigger 'tax_update'. + +UPDATE payroll SET tax_proof = 50000 WHERE deptno = 'D11'@ +UPDATE payroll SET calculate_tax = 1 WHERE deptno = 'D11'@ + +-- Execute RUNSTATS command to update the created temporary table 'cgtt.tax_cal' +-- to update statistics +RUNSTATS ON TABLE cgtt.tax_cal FOR indexes cgtt.IndexOnId@ + +CALL update()@ + +-- CALL the table function to print the IT sheet for the employees. +SELECT * FROM TABLE(printITSheet()) as ITSheet@ + + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- Step7: Run the Clean up scripts. -- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +-- Remove contents from the created temporary table. +TRUNCATE TABLE cgtt.tax_cal IMMEDIATE@ + +-- DROP the trigger, procedure, and function created by the sample. . +DROP TRIGGER tax_update@ +DROP FUNCTION tax_compute@ +DROP SPECIFIC PROCEDURE updater@ +DROP SPECIFIC PROCEDURE initialTax@ +DROP SPECIFIC PROCEDURE finalTax@ +DROP FUNCTION printITSheet@ + +-- DROP all the tables, indexes, and views created by the sample. +DROP INDEX cgtt.IndexOnId@ +DROP TABLE cgtt.tax_cal@ +DROP TABLE payroll@ +DROP VIEW cgtt.ViewOnCgtt@ + +-- DROP tablespaces created by the sample +DROP TABLESPACE TbspaceCgtt@ +DROP TABLESPACE TbspacePayroll@ +DROP BUFFERPOOL BufForSample@ +-------------------------------------------------------------------------------- + + + + + + + + + + + + + + diff --git a/admin_scripts/checkv9limits.db2 b/admin_scripts/checkv9limits.db2 new file mode 100644 index 0000000..22be181 --- /dev/null +++ b/admin_scripts/checkv9limits.db2 @@ -0,0 +1,157 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: checkv9limits.db2 +-- +-- SAMPLE: Check if any of the v9 identifier length limits have been +-- exceeded in this database. +-- +-- SQL STATEMENTS USED: +-- SELECT +-- TERMINATE +-- +-- Note: Use following command to execute the sample: +-- db2 -td@ -vf checkv9limits.db2 +-- +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to 'sample' database +CONNECT TO SAMPLE @ + +-- This is a collection of queries that returns result sets similar to the +-- following format: +-- OBJECT_SCHEMA VARCHAR(128) +-- OBJECT_NAME VARCHAR(128) +-- LENGTH INTEGER +-- OLD_LIMIT INTEGER +-- +-- The result sets contain lists of the identifiers in the database +-- which have exceeded the old V9 identifier length limits. The purpose +-- of this is for administrators to determine if any users or developers +-- have created large identifier names. This allows administrators to +-- ensure that the database and applications can handle longer identifier +-- names. +-- For more information on identifier length limits, please refer to the +-- InfoCenter topic "SQL and XQuery Limits" + +ECHO Checking for ATTRIBUTE NAME identifiers larger than 18 @ +SELECT TYPESCHEMA, ATTR_NAME, LENGTH(ATTR_NAME) AS LENGTH, INTEGER(18) AS OLDLIMIT + FROM SYSCAT.ATTRIBUTES + WHERE LENGTH(ATTR_NAME) > 18 @ + +ECHO Checking for AUTHID identifiers larger than 30 @ +SELECT AUTHID, LENGTH(AUTHID) AS LENGTH, INTEGER(30) AS OLDLIMIT + FROM SYSIBMADM.AUTHORIZATIONIDS + WHERE AUTHIDTYPE = 'U' AND LENGTH(AUTHID) > 30 @ + +ECHO Checking for COLUMN NAME identifiers larger than 30 @ +SELECT TABSCHEMA, COLNAME, LENGTH(COLNAME) AS LENGTH, INTEGER(30) AS OLDLIMIT + FROM SYSCAT.COLUMNS + WHERE LENGTH(COLNAME) > 30 @ + +ECHO Checking for CONSTRAINT NAME identifiers larger than 18 @ +SELECT TABSCHEMA, CONSTNAME, LENGTH(CONSTNAME) AS LENGTH, INTEGER(18) AS OLDLIMIT + FROM SYSCAT.CONSTDEP + WHERE LENGTH(CONSTNAME) > 18 + UNION + SELECT TABSCHEMA, CONSTNAME, LENGTH(CONSTNAME) AS LENGTH, INTEGER(18) AS OLDLIMIT + FROM SYSCAT.KEYCOLUSE + WHERE LENGTH(CONSTNAME) > 18 + UNION + SELECT TABSCHEMA, CONSTNAME, LENGTH(CONSTNAME) AS LENGTH, INTEGER(18) AS OLDLIMIT + FROM SYSCAT.CHECKS + WHERE LENGTH(CONSTNAME) > 18 @ + +ECHO Checking for EVENT MONITOR NAME identifiers larger than 18 @ +SELECT EVMONNAME, LENGTH(EVMONNAME) AS LENGTH, INTEGER(18) AS OLDLIMIT + FROM SYSCAT.EVENTMONITORS + WHERE LENGTH(EVMONNAME) > 18 @ + +ECHO Checking for GROUP identifiers larger than 30 @ +SELECT AUTHID, LENGTH(AUTHID) AS LENGTH, INTEGER(30) AS OLDLIMIT + FROM SYSIBMADM.AUTHORIZATIONIDS + WHERE AUTHIDTYPE = 'G' AND LENGTH(AUTHID) > 30 @ + +ECHO Checking for DBPARTITIONGROUP NAME identifiers larger than 18 @ +SELECT DBPGNAME, LENGTH(DBPGNAME) AS LENGTH, INTEGER(18) AS OLDLIMIT + FROM SYSCAT.DBPARTITIONGROUPS + WHERE LENGTH(DBPGNAME) > 18 @ + +ECHO Checking for PACKAGE NAME identifiers larger than 12 @ +SELECT PKGSCHEMA, PKGNAME, LENGTH(PKGNAME) AS LENGTH, INTEGER(8) AS OLDLIMIT + FROM SYSCAT.PACKAGES + WHERE LENGTH(PKGNAME) > 12 @ + +ECHO Checking for SCHEMA NAME identifiers larger than 30 @ +SELECT SCHEMANAME, LENGTH(SCHEMANAME) AS LENGTH, INTEGER(30) AS OLDLIMIT + FROM SYSCAT.SCHEMATA + WHERE LENGTH(SCHEMANAME) > 30 @ + +ECHO Checking for SPECIFIC NAME identifiers larger than 18 @ +SELECT ROUTINESCHEMA, SPECIFICNAME, LENGTH(SPECIFICNAME) AS LENGTH, INTEGER(18) AS OLDLIMIT + FROM SYSCAT.ROUTINES + WHERE LENGTH(SPECIFICNAME) > 18 @ + +ECHO Checking for FUNCPATH identifiers larger than 254 @ +SELECT VARCHAR(FUNC_PATH) AS FUNCPATH, LENGTH(FUNC_PATH) AS LENGTH, INTEGER(254) AS OLDLIMIT + FROM SYSCAT.VIEWS + WHERE LENGTH(FUNC_PATH) > 254 + UNION + SELECT VARCHAR(FUNC_PATH) AS FUNCPATH, LENGTH(FUNC_PATH) AS LENGTH, INTEGER(254) AS OLDLIMIT + FROM SYSCAT.CHECKS + WHERE LENGTH(FUNC_PATH) > 254 + UNION + SELECT VARCHAR(FUNC_PATH) AS FUNCPATH, LENGTH(FUNC_PATH) AS LENGTH, INTEGER(254) AS OLDLIMIT + FROM SYSCAT.TRIGGERS + WHERE LENGTH(FUNC_PATH) > 254 + UNION + SELECT VARCHAR(FUNC_PATH) AS FUNCPATH, LENGTH(FUNC_PATH) AS LENGTH, INTEGER(254) AS OLDLIMIT + FROM SYSCAT.PACKAGES + WHERE LENGTH(FUNC_PATH) > 254 + UNION + SELECT VARCHAR(FUNC_PATH) AS FUNCPATH, LENGTH(FUNC_PATH) AS LENGTH, INTEGER(254) AS OLDLIMIT + FROM SYSCAT.ROUTINES + WHERE LENGTH(FUNC_PATH) > 254 @ + +ECHO Checking for TRIGGER NAME identifiers larger than 18 @ +SELECT TRIGSCHEMA, TRIGNAME, LENGTH(TRIGNAME) AS LENGTH, INTEGER(18) AS OLDLIMIT + FROM SYSCAT.TRIGGERS + WHERE LENGTH(TRIGNAME) > 18 @ + +ECHO Checking for UDT NAME identifiers larger than 18 @ +SELECT TYPESCHEMA, TYPENAME, LENGTH(TYPENAME) AS LENGTH, INTEGER(18) AS OLDLIMIT + FROM SYSCAT.DATATYPES + WHERE LENGTH(TYPENAME) > 18 @ + + +-- Disconnect from the sample database +CONNECT RESET @ + +TERMINATE @ diff --git a/admin_scripts/contacts.db2 b/admin_scripts/contacts.db2 new file mode 100644 index 0000000..6d72eca --- /dev/null +++ b/admin_scripts/contacts.db2 @@ -0,0 +1,92 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: contacts.db2 +-- +-- SAMPLE: How to add, update and drop contacts and contactgroups +-- +-- This sample shows: +-- 1. How to add a contact for a user with e-mail address. +-- 2. How to create a contactgroup with contact names. +-- 3. How to update the address for the sample user. +-- 4. How to update the contactgroup by adding a contact. +-- 5. How to read a contact list. +-- 6. How to read a contact group list +-- 7. How to drop a contact from the list of contacts. +-- 8. How to drop a contactgroup from the list of groups +-- +-- Note: The Database Administration Server(DAS) should be running. +-- +-- SQL STATEMENTS USED: +-- ADD +-- CONNECT +-- DROP +-- GET +-- UPDATE +-- TERMINATE +-- +-- OUTPUT FILE: contacts.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to sample database +CONNECT TO sample; + +-- Add contacts for a user with e-mail address +ADD CONTACT testuser1 TYPE EMAIL ADDRESS testuser1@test.com; + +ADD CONTACT testuser2 TYPE EMAIL ADDRESS testuser2@test.com; + +-- Create a contactgroup with a contact name +ADD CONTACTGROUP gname1 CONTACT testuser1; + +-- Update the address for the user testuser1 +UPDATE CONTACT testuser1 USING ADDRESS address@test.com; + +-- Update the contactgroup by adding a contact +UPDATE CONTACTGROUP gname1 ADD CONTACT testuser2; + +-- Get the list of contactgroups +GET CONTACTGROUPS; + +-- Get the list of contacts +GET CONTACTS; + +-- Drop a contactgroup from the list of groups +DROP CONTACTGROUP gname1; + +-- Drop contacts from the list of contacts +DROP CONTACT testuser1; + +DROP CONTACT testuser2; + +-- Disconnect from the database +CONNECT RESET; + +TERMINATE; diff --git a/admin_scripts/databaseroles.db2 b/admin_scripts/databaseroles.db2 new file mode 100644 index 0000000..58dd6e3 --- /dev/null +++ b/admin_scripts/databaseroles.db2 @@ -0,0 +1,726 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: databaseroles.db2 +-- +-- PURPOSE : To demonstrate how database roles can be used in DB2 LUW. +-- +-- USAGE SCENARIO : In an enterprise, each employee has certain privileges +-- based on his/her role in each department. When an +-- employee joins, leaves or moves to or from a different +-- department, permissions need to be +-- granted, revoked, or transferred on department specific +-- database objects individually. This sample demonstrates +-- how all these can easily be done in single statement using +-- roles. +-- +-- The sample uses a scenario of an enterprise with three +-- departments DEVELOPMENT, TESTING, and SALES and three new +-- employees JOE, BOB, and PAT, joining the three departments +-- respectively. Employees for each department should have +-- access to only department specific information (tables) +-- and in case an employee gets transferred to another +-- department or leaves the enterprise, the permissions need +-- to be modified accordingly. The sample demonstrates how +-- the enterprise DBA's task of modifying permission on +-- different database objects for different users can be +-- simplified by the creation of database roles. +-- +-- PREREQUISITE : The following users should exist in the operating system. +-- +-- newton with password "Way2discoveR" in SYSADM group. +-- john with password "john123456" +-- joe with password "joe123456" +-- bob with password "bob123456" +-- pat with password "pat123456" +-- +-- +-- EXECUTION : db2 -tvf databaseroles.db2 +-- +-- INPUTS : NONE +-- +-- OUTPUTS : Roles will be created and dropped in the database. +-- +-- OUTPUT FILE : databaseroles.out (available in the online documentation) +-- +-- DEPENDENCIES : NONE +-- +-- SQL STATEMENTS USED: +-- CREATE ROLE +-- CREATE TABLE +-- CRETE VIEW +-- CONNECT +-- DROP +-- GRANT +-- INSERT +-- REVOKE +-- SELECT +-- TRANSFER +-- **************************************************************************** +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- **************************************************************************** +-- SAMPLE DESCRIPTION +-- **************************************************************************** +-- 1: How to GRANT select privilege to users through ROLES. +-- 2. How to replace GROUPS with ROLES. +-- 3: How to transfer ownership of database objects. +-- 4: How to REVOKE privileges from roles. +-- 5: How to build a role hierarchy. +-- 6: GRANT-ing and REVOKE-ing WITH ADMIN OPTIONS to and from an +-- authorization ID. +-- **************************************************************************** + +-- **************************************************************************** +-- SETUP +-- **************************************************************************** + +CONNECT TO sample; + +-- Create tables TEMP_EMPLOYEE and TEMP_DEPARTMENT under 'newton' schema. +CREATE TABLE newton.TEMP_EMPLOYEE LIKE EMPLOYEE; +CREATE TABLE newton.TEMP_DEPARTMENT LIKE DEPARTMENT; + +-- Populate the above created tables with the data from EMPLOYEE & DEPARTMENT tables. + +-- export the table data to file 'load_employee.ixf'. +EXPORT TO load_employee.ixf OF IXF SELECT * FROM EMPLOYEE; + +-- loading data from data file inserting data into the table TEMP_EMPLOYEE. +LOAD FROM load_employee.ixf of IXF INSERT INTO newton.TEMP_EMPLOYEE; + +-- export the table data to file 'load_department.ixf'. +EXPORT TO load_department.ixf OF IXF SELECT * FROM DEPARTMENT; + +-- loading data from data file inserting data into the table TEMP_DEPARTMENT. +LOAD FROM load_department.ixf of IXF INSERT INTO newton.TEMP_DEPARTMENT; + +-- ---------------------------------------------------------------------------- +-- 1: How to GRANT select privilege to users through ROLES. +-- ---------------------------------------------------------------------------- +-- Usage scenario : +-- The code below shows how to GRANT/REVOKE select privilege to users JOE and +-- BOB through role DEVELOPMENT_ROLE. User JOHN, who is a +-- security administrator(SECADM), creates a role DEVELOPMENT_ROLE and grants +-- employees JOE and BOB, working in department DEVELOPMENT, SELECT privilege +-- on tables DEV_TABLE1 and DEV_TABLE2 via DEVELOPMENT_ROLE. +-- The sample also shows how REVOKING of the DEVELOPMENT_ROLE from employees +-- JOE and BOB causes employees JOE and BOB to lose SELECT privilege on +-- tables DEV_TABLE1 and DEV_TABLE2. At this point, if employees JOE and +-- BOB try to perform a select operation on tables DEV_TABLE1 and DEV_TABLE2, +-- the select statement will fail. The sample also shows when a new +-- employee PAT joins department DEVELOPMENT, she is granted SELECT privilege +-- on the two development tables via DEVELOPMENT_ROLE. +-- ---------------------------------------------------------------------------- + +-- Connect to sample database using user NEWTON. +CONNECT TO sample user newton using Way2discoveR; + +-- Grant SECADM authority to a user JOHN. +GRANT SECADM ON DATABASE TO USER john; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO sample USER john USING john123456; + +-- Create role DEVELOPMENT_ROLE. Only a user with SECADM authority can create +-- the role. In this sample user JOHN is assigned SECADM authority and has +-- the privilege to create the roles. +CREATE ROLE development_role; + +-- Create tables DEV_TABLE1 and DEV_TABLE2. Any user can create these tables. +-- In the sample these tables are created by user JOHN. +CREATE TABLE dev_table1 (project VARCHAR(25), dept_no INT); +INSERT INTO dev_table1 VALUES ('DB0', 1); + +CREATE TABLE dev_table2 (defect_no INT, scheme_repository VARCHAR(25)); +INSERT INTO dev_table2 VALUES (100, 'wsdbu'); + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user NEWTON(SYSADM). +-- User NEWTON is system administrator(SYSADM). +CONNECT TO sample user newton using Way2discoveR; + +-- Grant SELECT privilege on tables DEV_TABLE1 and DEV_TABLE2 to role +-- DEVELOPMENT_ROLE. +GRANT SELECT ON TABLE john.dev_table1 + TO ROLE development_role; +GRANT SELECT ON TABLE john.dev_table2 + TO ROLE development_role; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO sample user john using john123456; + +-- Grant role DEVELOPMENT_ROLE to users JOE and BOB. +GRANT ROLE development_role TO USER joe, USER bob; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOE. +CONNECT TO sample USER joe USING joe123456; + +-- User JOE is granted DEVELOPMENT_ROLE role and hence gains select privilege +-- on the tables DEV_TABLE1 and DEV_TABLE2 through membership of this role. +-- SELECT from tables DEV_TABLE1 and DEV_TABLE2 to verify user JOHN has +-- select privileges. +SELECT * FROM john.dev_table1; +SELECT * FROM john.dev_table2; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user BOB +CONNECT TO sample USER bob USING bob123456; + +-- User BOB is granted DEVELOPMENT_ROLE role and hence gains select privilege +-- on the tables DEV_TABLE1 and DEV_TABLE2 through membership of this role. +-- SELECT from tables DEV_TABLE1 and DEV_TABLE2 to verify user BOB has select +-- privileges. + +SELECT * FROM john.dev_table1; +SELECT * FROM john.dev_table2; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO sample user john using john123456; + +-- REVOKE the role DEVELOPMENT_ROLE from users JOE and BOB. +REVOKE ROLE development_role FROM USER joe, USER bob; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOE. +CONNECT TO sample USER joe USING joe123456; + +-- The following two SELECT statements will fail. Users JOE cannot perform +-- SELECT on the tables DEV_TABLE1 and DEV_TABLE2 now. JOE has lost SELECT +-- privilege on these tables as role DEVELOPMENT_ROLE was revoked from him. + +-- Error displayed for the following SELECT statement will be : +-- SQL0551N "JOE" does not have the privilege to perform operation "SELECT" +-- on object "JOHN.DEV_TABLE1". SQLSTATE=42501 +SELECT * FROM john.dev_table1; +!echo "Above error is expected !"; + +-- Error displayed for the following SELECT statement will be : +-- SQL0551N "JOE" does not have the privilege to perform operation "SELECT" +-- on object "JOHN.DEV_TABLE2". SQLSTATE=42501 +SELECT * FROM john.dev_table2; +!echo "Above error is expected !"; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user BOB +CONNECT TO sample USER bob USING bob123456; + +-- The following two SELECT statements will fail as user BOB has lost SELECT +-- privilege on these tables as the role DEVELOPMENT_ROLE was revoked +-- from him. + +-- Error displayed for the following SELECT statement will be : +-- SQL0551N "BOB" does not have the privilege to perform operation "SELECT" +-- on object "JOHN.DEV_TABLE1". SQLSTATE=42501 +SELECT * FROM john.dev_table1; +!echo "Above error is expected !"; + +-- Error displayed for the following SELECT statement will be : +-- SQL0551N "BOB" does not have the privilege to perform operation "SELECT" +-- on object "JOHN.DEV_TABLE2". SQLSTATE=42501 +SELECT * FROM john.dev_table2; +!echo "Above error is expected !"; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN. +CONNECT TO sample USER john USING john123456; + +-- Grant role DEVELOPMENT_ROLE to new employee PAT. +-- Once this is done, PAT can SELECT from tables DEV_TABLE1 +-- and DEV_TABLE2. +GRANT ROLE development_role TO USER pat; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user PAT. +CONNECT TO sample USER pat USING pat123456; + +-- The following two SELECT statements will be successful. +SELECT * FROM john.dev_table1; +SELECT * FROM john.dev_table2; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO sample USER john USING john123456; + +-- Drop the tables. +DROP TABLE dev_table1; +DROP TABLE dev_table2; + +-- Drop the role. Only a user having SECADM authority can drop the role. +DROP ROLE development_role; + +-- Disconnect from sample database. +CONNECT RESET; + +-- ---------------------------------------------------------------------------- +-- 2. How to replace GROUPS with ROLES. +-- ---------------------------------------------------------------------------- +-- Usage scenario: +-- Assume there are three groups DEVELOPER_G, TESTER_G, and SALES_G and three +-- users (BOB, JOE and PAT) defined in the operating system. +-- BOB belongs to group DEVELOPER_G and SALES_G, JOE +-- belongs to group TESTER_G and SALES_G and PAT belongs to group TESTER_G. +-- Roles DEVELOPER, TESTER and SALES will be created and used instead of groups +-- DEVELOPER_G, TESTER_G, and SALES_G respectively . In this scenario, all the +-- privileges held by GROUPS will be granted to appropriate ROLES and revoked +-- from the GROUPS. This leaves the users with the same privileges but now +-- held through ROLES instead of GROUPS. +-- ---------------------------------------------------------------------------- + +-- Connect to sample database using user JOHN. +CONNECT TO sample USER john USING john123456; + +-- Create roles DEVELOPER, TESTER and SALES. +CREATE ROLE developer; +CREATE ROLE tester; +CREATE ROLE sales; + +-- Grant role DEVELOPER to user BOB. +GRANT ROLE developer TO USER bob; + +-- Grant role TESTER to users JOE and PAT. +GRANT ROLE tester TO USER joe, USER pat; + +-- Grant role SALES to users JOE and BOB. +GRANT ROLE sales TO USER joe, USER bob; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user BOB. +CONNECT TO SAMPLE USER bob USING bob123456; + +-- Create table TEMP1. +CREATE TABLE temp1 (a int); + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user Newton(SYSADM)so that he can grant +-- ALTER privilege to role DEVELOPER. (DBADM can also grant ALTER privilege). +CONNECT TO SAMPLE USER newton USING Way2discoveR; + +-- Grant ALTER privilege on table TEMP1 to role DEVELOPER. NEWTON(SYSADM) +-- (also DBADM) can grant the ALTER privilege on tables. +-- Once ALTER privilege is granted to role DEVELOPER, any user who +-- is part of role DEVELOPER can ALTER this table. So in this sample, +-- user BOB can perform an alter operation on table TEMP1. Users belonging to +-- other roles cannot perform alter operation on TEMP1 unless they have +-- privilege granted. +GRANT ALTER ON bob.temp1 TO ROLE developer; +CONNECT RESET; + +-- The following statements show that a trigger TRG1 will be created +-- when user BOB holds the privilege through role DEVELOPER. But this is +-- not possible if user BOB is part of group DEVELOPER_G. + +-- Connect to sample database using user BOB. +CONNECT TO SAMPLE USER bob using bob123456; + +-- Create trigger TRG1. The following statements show that trigger TRG1 can +-- only be created by user BOB, as he holds the privilege through role +-- DEVELOPER. But this is not possible if user BOB holds the necessary +-- privileges through a group. +CREATE TRIGGER trg1 AFTER DELETE ON bob.temp1 + FOR EACH STATEMENT MODE DB2SQL INSERT INTO bob.temp1 VALUES (1); + +-- Drop the table TEMP1. +DROP TABLE bob.temp1; + +-- Drop the trigger TRG1. +DROP trigger trg1; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO SAMPLE USER john using john123456; + +-- Drop the roles. Only a user with SECADM authority can drop the roles. +-- In this sample, user JOHN(SECADM) can only drop the roles. +DROP ROLE developer; +DROP ROLE tester; +DROP ROLE sales; + +-- Disconnect from sample database. +CONNECT RESET; + +-- ---------------------------------------------------------------------------- +-- 3: How to transfer ownership of database objects. +-- ---------------------------------------------------------------------------- +-- Usage scenario: +-- Consider the tables TEMP_EMPLOYEE and TEMP_DEPARTMENT in the sample database. User BOB +-- creates a view EMP_DEPT on tables TEMP_EMPLOYEE and TEMP_DEPARTMENT. +-- The user JOHN(SECADM) creates a role EMP_DEPT_ROLE which is granted SELECT +-- privilege on table TEMP_EMPLOYEE and TEMP_DEPARTMENT. The sample shows how to transfer +-- ownership of view BOB.EMP_DEPT, which depends on tables TEMP_EMPLOYEE and +-- TEMP_DEPARTMENT, to new user JOE. For the TRANSFER to work, new user JOE must +-- hold SELECT privilege on the above two table. +-- ---------------------------------------------------------------------------- + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO SAMPLE USER john USING john123456; + +-- Create role EMP_DEPT_ROLE. +CREATE ROLE emp_dept_role; + +-- Disconnect from sample database. +CONNECT RESET; + +-- User NEWTON(SYSADM) grants SELECT privilege on tables TEMP_EMPLOYEE and TEMP_DEPARTMENT +-- to role EMP_DEPT_ROLE. + +-- Connect to sample database using user NEWTON. +CONNECT TO sample user newton using Way2discoveR; + +GRANT SELECT ON TABLE newton.temp_employee + TO ROLE emp_dept_role; +GRANT SELECT ON TABLE newton.temp_department + TO ROLE emp_dept_role; + +-- Disconnect from sample database. +CONNECT RESET; + + +-- To transfer ownership of view EMP_DEPT(created below), BOB must hold SELECT +-- privilege on table TEMP_EMPLOYEE and table TEMP_DEPARTMENT. +-- Since role EMP_DEPT_ROLE has these privileges, role EMP_DEPT_ROLE +-- is granted to user BOB using the statement, below. +-- For the TRANSFER to work, new user JOE must also hold SELECT privilege on +-- the above two tables. Hence user JOHN(SECADM) grants SELECT privilege +-- to user JOE also. +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO SAMPLE USER john USING john123456; + +GRANT ROLE emp_dept_role TO USER bob, USER joe; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user BOB. +CONNECT TO SAMPLE USER bob USING bob123456; + +-- User BOB creates a view EMP_DEPT which depends upon tables +-- TEMP_EMPLOYEE and TEMP_DEPARTMENT. +-- Create view EMP_DEPT using tables TEMP_EMPLOYEE and TEMP_DEPARTMENT. +CREATE VIEW emp_dept AS SELECT * FROM newton.temp_employee, newton.temp_department; + +-- Transfer view EMP_DEPT to user JOE from user BOB. +TRANSFER OWNERSHIP OF VIEW bob.emp_dept TO USER joe PRESERVE PRIVILEGES; + +-- Connect to sample database using user JOE. +CONNECT TO SAMPLE USER joe using joe123456; + +-- After the TANSFER is done,user BOB cannot drop the view. Only new user JOE, +-- who is current owner of the view, can drop it. +DROP VIEW bob.emp_dept; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO SAMPLE USER john using john123456; + +-- User JOHN(SECADM) drops the role. +DROP ROLE emp_dept_role; + +-- Disconnect from sample database. +CONNECT RESET; + +-- ---------------------------------------------------------------------------- +-- 4: How to REVOKE privileges from roles. +-- ---------------------------------------------------------------------------- +-- Usage scenario: +-- To show the effect on a user~Rs access privilege to a database object, if +-- some privileges are revoked from an authorization ID and privileges are +-- held only through a role. User JOE creates a table TEMP_TABLE. +-- User JOHN(SECADM) creates a role DEVELOPER and is grants it to user BOB. +-- User NEWTON(SYSADM) grants SELECT and INSERT privileges on table JOE.TEMP_TABLE to +-- PUBLIC and to role DEVELOPER. User BOB creates a view VIEW_TEMP which is +-- dependent on table JOE.TEMP_TABLE. The sample shows what happens to +-- user BOB's access privilege when SELECT privilege is revoked from PUBLIC +-- and from role developer. +-- ---------------------------------------------------------------------------- + +-- Connect to sample database using user JOE. +CONNECT TO SAMPLE USER joe USING joe123456; + +-- Create table TEMP_TABLE. +CREATE TABLE temp_table (x int); + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO SAMPLE USER john USING john123456; + +-- Create role DEVELOPER. +CREATE ROLE developer; + +-- Grant role DEVELOPER to user BOB +GRANT ROLE developer TO USER bob; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user NEWTON(SYSADM). +CONNECT TO SAMPLE USER newton using Way2discoveR; + +-- Grant SELECT and INSERT privileges on table TEMP_TABLE to PUBLIC and +-- to role DEVELOPER. Only a user with SYSADM or DBADM authority can grant +-- the privileges on the table. +-- In this sample, the user NEWTON(SYSADM)can grant the SELECT and the INSERT +-- privileges on the table TEMP_TABLE to PUBLIC and to role DEVELOPER. +GRANT SELECT ON TABLE joe. temp_table TO PUBLIC; +GRANT INSERT ON TABLE joe. temp_table TO PUBLIC; +GRANT SELECT ON TABLE joe. temp_table + TO ROLE developer; +GRANT INSERT ON TABLE joe. temp_table + TO developer; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database uing user BOB. +CONNECT TO SAMPLE USER bob USING bob123456; + +-- Create a view VIEW_TEMP on the table TEMP_TABLE. +CREATE VIEW view_temp + AS SELECT * FROM joe.temp_table; + +-- Disconnect form sample database. +CONNECT RESET; + +-- Connect to sample database using user NEWTON(SYSADM). +CONNECT TO SAMPLE USER newton using Way2discoveR; + +-- If SELECT privilege on table JOE.TEMP_TABLE is revoked from PUBLIC, +-- the view, BOB.VIEW_TEMP will still be accessible by users who are +-- part of the role DEVELOPER. +REVOKE SELECT ON joe. temp_table FROM PUBLIC; + +-- Disconnect from sample database. +CONNECT RESET; + + +-- Connect to sample database using user NEWTON(SYSADM). +CONNECT TO sample USER newton USING Way2discoveR; + +-- If SELECT privilege on table JOE.TEMP_TABLE is revoked from the role +-- DEVELOPER, user BOB will lose SELECT privilege on the table JOE.TEMP_TABLE +-- because required privileges are not held through either role DEVELOPER +-- or any other means. +REVOKE SELECT ON TABLE joe. temp_table FROM ROLE developer; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user BOB. +CONNECT TO sample USER bob USING bob123456; + +-- Drop a view VIEW_TEMP. +DROP VIEW bob.view_temp; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOE. +CONNECT TO SAMPLE USER joe USING joe123456; + +-- Drop a table TEMP_TABLE. +DROP TABLE joe.temp_table; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO SAMPLE USER john USING john123456; + +-- Drop a role DEVELOPER. +DROP ROLE developer; + +-- Disconnect from sample database. +CONNECT RESET; + +-- ---------------------------------------------------------------------------- +-- 5: How to build a role hierarchy. +-- ---------------------------------------------------------------------------- +-- Usage scenario: +-- The following sample demonstrates how to represent hierarchy levels +-- in an enterprise by building a role hierarchy. +-- Consider an enterprise having the following roles: MANAGER, TECH_LEAD and +-- DEVELOPER. A role hierarchy is built by granting a role to another role, but +-- without creating cycles. Role DEVELOPER will be granted to role TECH_LEAD, +-- and role TECH_LEAD will be granted to role MANAGER. Granting role MANAGER to +-- role DEVELOPER will create a cycle and it is not allowed. +-- By building a hierarchy, role MANAGER will have all the privileges of roles +-- DEVELOPER and TECH_LEAD along with the privileges granted to it directly. +-- Role TECH_LEAD will have privileges of role DEVELOPER and the privileges +-- granted to it directly. Role DEVELOPER will just have the privileges granted +-- to it. Later, depending upon the enterprise needs, each role can be granted +-- to specific employees to form the hierarchy. +-- ---------------------------------------------------------------------------- + + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO SAMPLE USER john USING john123456; + +-- Create roles MANAGER, TECH_LEAD and DEVELOPER. +CREATE ROLE manager; +CREATE ROLE tech_lead; +CREATE ROLE developer; + +-- These two statements create a role hierarchy. +GRANT ROLE developer TO ROLE tech_lead; +GRANT ROLE tech_lead TO ROLE manager; + +-- Drop roles MANAGER, TECH_LEAD and DEVELOPER. +DROP ROLE manager; +DROP ROLE tech_lead; +DROP ROLE developer; + +-- Disconnect from sample database. +CONNECT RESET; + +-- ---------------------------------------------------------------------------- +-- 6: GRANT-ing and REVOKE-ing WITH ADMIN OPTIONS to and from an +-- authorization ID. +-- ---------------------------------------------------------------------------- +-- Usage scenario: +-- A security administrator will create role DEVELOPER and grant it to user JOE +-- using WITH ADMIN OPTION. Once the ADMIN OPTION is granted to user JOE, he can +-- GRANT or REVOKE role DEVELOPER to or from another user BOB who is a member of +-- this role. But JOE will not get the authority to drop role DEVELOPER or to +-- grant ADMIN OPTION to another user. User JOE is not allowed to REVOKE the +-- ADMIN OPTION from role DEVELOPER because he does not have SECADM authority. +-- A security administrator can revoke the ADMIN OPTION from role DEVELOPER, +-- and user JOE will still have role DEVELOPER granted. +-- If a SECADM revokes the role DEVELOPER from the user JOE, the user JOE will +-- lose all the privileges he has received by being a member of role DEVELOPER +-- and the ADMIN OPTION on role DEVELOPER if this was held. +-- ---------------------------------------------------------------------------- + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO SAMPLE USER john USING john123456; + +-- Create role DEVELOPER. +CREATE ROLE developer; + +-- Grant role DEVELOPER to user JOE and give the WITH ADMIN privilege. +GRANT ROLE developer TO USER joe WITH ADMIN OPTION; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOE. +CONNECT TO SAMPLE USER joe USING joe123456; + +-- The following statements will be successful because user JOE has the +-- WITH ADMIN privileges on role DEVELOPER. +-- User JOE can GRANT and REVOKE ROLE to/from the other users. +GRANT ROLE developer TO USER bob; + +REVOKE ROLE developer FROM USER bob; + +-- The following statement will fail since user JOE doesn't have the privilege +-- to drop the role DEVELOPER. Only user JOHN(SECADM) is allowed to drop the +-- role. +-- Error displayed will be: +-- SQL0552N "JOE" does not have the privilege to perform operation +-- "DROP ROLE". SQLSTATE=42502 +DROP ROLE developer; +!echo "Above error is expected!"; + +-- The following statement will fail because user JOE cannot GRANT/REVOKE +-- the role DEVELOPER to another user by using the WITH ADMIN OPTION clause. +-- Only a SECADM can grant/revoke the WITH ADMIN OPTION. +-- Error displayed will be: +-- SQL0551N .JOE" does not have the privilege to perform operation +-- "GRANT/REVOKE" on object "DEVELOPER". SQLSTATE=42501 +GRANT ROLE DEVELOPER TO USER bob WITH ADMIN OPTION; +!echo "Above error is expected!"; + +REVOKE ADMIN OPTION FOR ROLE developer FROM USER bob; +!echo "Above error is expected!"; + +-- Disconnect from sample database. +CONNECT RESET; + +-- Connect to sample database using user JOHN(SECADM). +CONNECT TO SAMPLE USER john USING john123456; + +-- The following statement will be successful because user JOHN(SECADM) +-- is executing it. +-- With the command below, only ADMIN OPTION is revoked, role DEVELOPER is +-- still granted to user JOE. +REVOKE ADMIN OPTION FOR ROLE developer FROM USER joe; + +-- Revoke role DEVELOPER from user JOE. +REVOKE ROLE developer FROM USER joe; + +-- Drop a role. +DROP ROLE developer; + +-- Disconnect from sample database. +CONNECT RESET; + +-- **************************************************************************** +-- CLEAN UP +-- **************************************************************************** + +-- Drop the temporary tables created. +CONNECT TO SAMPLE; + +DROP TABLE newton.TEMP_EMPLOYEE; +DROP TABLE newton.TEMP_DEPARTMENT; + +TERMINATE; + diff --git a/admin_scripts/fasterrollout.db2 b/admin_scripts/fasterrollout.db2 new file mode 100644 index 0000000..b1cb257 --- /dev/null +++ b/admin_scripts/fasterrollout.db2 @@ -0,0 +1,152 @@ +-- ************************************************************************ +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************ +-- +-- SAMPLE FILE NAME: fasterrollout.db2 +-- +-- PURPOSE : To demonstrate how to change the default MDC roll out +-- behavior to a deferred index cleanup behavior. +-- +-- USAGE SCENARIO : This sample demonstrates different ways to cleanup +-- indexes using DELETE statement. +-- +-- PREREQUISITE : NONE +-- +-- EXECUTION : db2 -tvf fasterrollout.db2 +-- +-- INPUTS : NONE +-- +-- OUTPUTS : Successful change of MDC roll out behaviour from +-- IMMEDIATE index cleanup to DEFERRED index cleanup. +-- +-- OUTPUT FILE : fasterrollout.out (available in the online documentation) +-- +-- DEPENDENCIES : NONE +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- CREATE INDEX +-- DELETE +-- DROP TABLE +-- INSERT +-- SET CURRENT ROLLOUT MODE +-- +-- ************************************************************************* +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- ************************************************************************* +-- SAMPLE DESCRIPTION +-- ************************************************************************* +-- 1. How to perform delete that uses IMMEDIATE INDEX CLEANUP roll out type. +-- 2. How to perform delete that uses DEFERRED INDEX CLEANUP roll out type. +-- ************************************************************************* +-- +-- ************************************************************************* +-- SETUP +-- ************************************************************************* +-- Connect to the database. +CONNECT TO sample; + +-- ************************************************************************* +-- Following shows how to perform delete that uses IMMEDIATE INDEX +-- CLEANUP roll out type. +-- ************************************************************************* + +-- Create MDC table 'MDC_temp'. + +CREATE TABLE MDC_emp (emp_no INT NOT NULL, emp_sal DOUBLE, + emp_location CHAR (25)) + ORGANIZE BY DIMENSIONS (emp_no, emp_location); + +-- Populate table 'MDC_emp' with data. + +INSERT INTO MDC_emp values (100, 1.25, 'BANGALORE'); +INSERT INTO MDC_emp values (200, 2.00, 'BANGALORE'); +INSERT INTO MDC_emp values (300, 2.00, 'CHENNAI'); +INSERT INTO MDC_emp values (400, 3.00, 'CHENNAI'); +INSERT INTO MDC_emp values (500, 2.00, 'PUNE'); +INSERT INTO MDC_emp values (600, 2.00, 'BANGALORE'); + +-- Create index on columns 'emp_no' and 'emp_location'. + +CREATE INDEX indx1 ON MDC_emp (emp_no, emp_location); + +-- The below DELETE statement uses 'IMMEDIATE INDEX CLEANUP ROLLOUT' as default. +-- Indexes are cleaned up at delete time and rolled out blocks will be +-- available for immediate use. + +DELETE FROM MDC_emp WHERE emp_sal = 2.00 AND emp_location = 'BANGALORE'; + +-- Drop the table. + +DROP TABLE MDC_emp; + +-- ************************************************************************* +-- Following shows how to perform DELETE that uses DEFERRED INDEX CLEANUP +-- roll out type. This type of index cleanup is very efficient in case of +-- large tables. This even shows how to change the DEFAULT mode to +-- DEFERRED mode. +-- ************************************************************************* + +-- Create MDC table 'MDC_temp'. + +CREATE TABLE MDC_emp (emp_no INT NOT NULL, emp_sal DOUBLE, + emp_location CHAR (25)) + ORGANIZE BY DIMENSIONS (emp_no, emp_location); + +-- Populate table 'MDC_emp' with data. + +INSERT INTO MDC_emp values (100, 1.25, 'BANGALORE'); +INSERT INTO MDC_emp values (200, 2.00, 'BANGALORE'); +INSERT INTO MDC_emp values (300, 2.00, 'CHENNAI'); +INSERT INTO MDC_emp values (400, 3.00, 'CHENNAI'); +INSERT INTO MDC_emp values (500, 2.00, 'PUNE'); +INSERT INTO MDC_emp values (600, 2.00, 'BANGALORE'); + +-- Create index on columns 'emp_no' and 'emp_location'. + +CREATE INDEX indx1 ON MDC_emp (emp_no, emp_location); + +-- Change the roll out type to 'DEFERRED'. + +SET CURRENT MDC ROLLOUT MODE = DEFERRED; + +-- The above statement changes the roll out type from 'IMMEDIATE' to 'DEFERRED'. +-- Once the delete statement is committed, DB2 begins to cleanup +-- RID indexes asynchronously. Users cannot use the rolled out blocks immediately +-- after DELETE. These blocks will be available for reuse only after index cleanup +-- is completed by DB2. + +DELETE FROM MDC_emp WHERE emp_sal = 2.00 OR emp_location = 'BANGALORE'; + +-- Drop table. + +DROP TABLE MDC_emp; + +-- Disconnect form database. + +CONNECT RESET; + +TERMINATE; + diff --git a/admin_scripts/gethealthconfig.db2 b/admin_scripts/gethealthconfig.db2 new file mode 100644 index 0000000..c63ea8c --- /dev/null +++ b/admin_scripts/gethealthconfig.db2 @@ -0,0 +1,76 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: gethealthconfig.db2 +-- +-- SAMPLE: How to get definition, alert configuration and default alert +-- configurations +-- +-- SQL STATEMENTS USED: +-- SELECT +-- TERMINATE +-- +-- OUTPUT FILE: gethealthconfig.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to sample database +CONNECT TO SAMPLE; + +-- Get the definition for health indicator db2.mon_heap_util +SELECT D.ID, + SUBSTR(D.SHORT_DESCRIPTION, 1, 25) AS SHORT_DESCRIPTION, + SUBSTR(D.FORMULA, 1, 55) AS FORMULA + FROM TABLE(SYSPROC.HEALTH_GET_IND_DEFINITION('')) AS D + WHERE NAME = 'db2.mon_heap_util'; + +-- Get alert configuration for health indicator db.log_util on database SAMPLE +SELECT SUBSTR(D.NAME, 1, 15) AS NAME, + C.EVALUATE, + C.ACTION_ENABLED, + C.WARNING_THRESHOLD, + C.ALARM_THRESHOLD + FROM TABLE(SYSPROC.HEALTH_GET_IND_DEFINITION('')) AS D, + TABLE(SYSPROC.HEALTH_GET_ALERT_CFG('DB', 'O', 'SAMPLE', '')) AS C + WHERE D.ID = C.ID AND D.NAME = 'db.log_util'; + +-- Get Global default alert configuration settings for tablespaces on health indicator ts.ts_util +SELECT SUBSTR(D.NAME, 1, 15) AS NAME, + C.EVALUATE, + C.ACTION_ENABLED, + C.WARNING_THRESHOLD, + C.ALARM_THRESHOLD + FROM TABLE(SYSPROC.HEALTH_GET_IND_DEFINITION('')) AS D, + TABLE(SYSPROC.HEALTH_GET_ALERT_CFG('TS', 'G', '', '')) AS C + WHERE D.ID = C.ID AND D.NAME = 'ts.ts_util'; + +-- disconnect from the database +CONNECT RESET; + +TERMINATE; \ No newline at end of file diff --git a/admin_scripts/getlogs.db2 b/admin_scripts/getlogs.db2 new file mode 100644 index 0000000..8625a2a --- /dev/null +++ b/admin_scripts/getlogs.db2 @@ -0,0 +1,83 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: getlogs.db2 +-- +-- SAMPLE: How to get the customer view of diagnostic log file entries +-- +-- This sample shows: +-- 1. How to retrieve messages from the notification log starting +-- at a specified point in time. +-- 2. How to retrieve messages from the notification log written +-- over the last week or over the last 24 hours. +-- +-- SQL STATEMENTS USED: +-- CONNECT +-- SELECT +-- TERMINATE +-- +-- OUTPUT FILE: getlogs.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to sample database. +CONNECT TO sample; + +-- Retrieve all notification messages written after the specified +-- timestamp (for example '2006-02-22', '06.44.44') +-- If NULL is specified as the input timestamp to PD_GET_LOG_MSGS UDF, +-- then all the log entries will be returned. +SELECT dbname, + msgseverity + FROM TABLE (PD_GET_LOG_MSGS(TIMESTAMP('2006-02-22','06.44.44'))) AS t + ORDER BY TIMESTAMP; + +-- Retrieve all notification messages written in the last week from +-- all partitions in chronological order. +SELECT instancename, + dbpartitionnum, + dbname, + msgtype + FROM TABLE(PD_GET_LOG_MSGS(current_timestamp - 7 days)) AS t + ORDER BY TIMESTAMP; + +-- Get all critical log messages logged over the last 24 hours, order +-- by most recent +SELECT timestamp, + instancename, + dbname, + appl_id, + msg + FROM SYSIBMADM.PDLOGMSGS_LAST24HOURS WHERE msgseverity = 'C' + ORDER BY TIMESTAMP DESC; + +-- Disconnect from database. +CONNECT RESET; + +TERMINATE; diff --git a/admin_scripts/globvarsupport.db2 b/admin_scripts/globvarsupport.db2 new file mode 100644 index 0000000..b82a028 --- /dev/null +++ b/admin_scripts/globvarsupport.db2 @@ -0,0 +1,343 @@ +-- **************************************************************************** +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- **************************************************************************** +-- +-- SAMPLE FILE NAME: globvarsupport.db2 +-- +-- PURPOSE : To demonstrate how to use global variables with DB2. +-- +-- USAGE SCENARIO : This sample demonstrates how to exploit session global +-- variables in DB2. +-- +-- PREREQUISITE : NONE +-- +-- EXECUTION : db2 -tvf globvarsupport.db2 +-- +-- INPUTS : NONE +-- +-- OUTPUTS : +-- +-- OUTPUT FILE : globvarsupport.out (available in the online documentation) +-- +-- DEPENDENCIES : NONE +-- +-- SQL STATEMENTS USED: +-- COMMENT ON +-- CREATE PROCEDURE +-- CREATE TABLE +-- CREATE TRIGGER +-- CREATE VARIABLE +-- CREATE VIEW +-- DROP +-- GRANT +-- INSERT +-- REVOKE +-- SELECT +-- SET +-- VALUES +-- +-- **************************************************************************** +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- **************************************************************************** +-- SAMPLE DESCRIPTION +-- **************************************************************************** +-- The sample showcases the following: +-- 1. Simple operations with global variables, such as: +-- * creating and dropping of session global variable. +-- * granting/revoking the permissions to/from users. +-- * setting value to a global variable using SET statement. +-- * adding comment to a global variable. +-- * counting the number of global variables from catalog tables. +-- * transferring the ownership of a variable. +-- +-- 2. Use of global variable in a trigger which can be used to control the +-- operation on the trigger like switching off the trigger for maintenance. +-- +-- 3. Use of global variable in a stored procedure. +-- +-- 4. Use of a global variable in a view to show how global variables can help +-- to improve security and performance and to reduce complexity. +-- **************************************************************************** +-- +-- **************************************************************************** +-- SETUP +-- **************************************************************************** +-- Connect to sample database. +CONNECT TO sample; + +-- **************************************************************************** +-- 1. Simple operations with global variables. +-- **************************************************************************** +-- The code below shows how users can perform different operations on +-- global variables. +-- **************************************************************************** +-- Create a session global variable. +CREATE VARIABLE myjob_current varchar (10) DEFAULT ('soft-engg'); + +-- Obtain information of the global variable created. +SELECT substr (varschema, 1, 10) as varschema, + substr (varname, 1, 10) AS varname, + varid, substr(owner,1,10) AS owner, + ownertype, create_time, + substr(typeschema,1,10) AS typeschema, + substr(typename,1,10) AS typename, length + FROM syscat.variables + WHERE varname = 'MYJOB_CURRENT'; + +-- Give read and write permissions to users 'praveen' and 'sanjay'. +GRANT READ, WRITE ON VARIABLE myjob_current TO USER praveen, USER sanjay; + +-- Check the privileges for users 'praveen' and 'sanjay'. +SELECT substr (varschema, 1, 10) AS schema, + substr (varname, 1, 10) AS name, + substr(grantor,1,10) AS grantor, grantortype AS Rtype, + substr(grantee,1,10) AS grantee, granteetype AS Etype, + readauth, writeauth + FROM syscat.variableauth + WHERE varname ='MYJOB_CURRENT'; + +-- Revoke write permission from user 'sanjay' +REVOKE WRITE ON VARIABLE myjob_current FROM USER sanjay; + +-- Check the privilege for user 'sanjay' to verify write +-- permission was revoked. +SELECT substr (varschema, 1, 10) AS schema, + substr (varname, 1, 10) AS name, + substr(grantor,1,10) AS grantor, grantortype AS Rtype, + substr(grantee,1,10) AS grantee, granteetype AS Etype, + readauth, writeauth + FROM syscat.variableauth + WHERE varname ='MYJOB_CURRENT' AND grantee = 'SANJAY'; + +-- Assign value 'MGR' to global variable 'myjob_current'. +SET myjob_current = 'MGR'; + +-- Query the value of global variable 'myjob_current'. +VALUES myjob_current; + +-- Add a comment to the global variable 'myjob_current'. +COMMENT ON VARIABLE myjob_current IS 'Manager'; + +-- Check comment added to the global variable 'myjob_current'. +SELECT substr (varschema, 1, 10) AS varschema, + substr (varname, 1, 10) AS varname, + substr (remarks, 1, 50) AS comment + FROM syscat.variables + WHERE varname = 'MYJOB_CURRENT'; + +-- Count the number of global variables created in the catalog +-- The count should be one. +SELECT count (*) FROM syscat.variables; + +-- Drop the global variable. +DROP VARIABLE myjob_current; + +-- **************************************************************************** +-- The code below shows users how ownership of a global variable +-- can be transferred to another user. +-- **************************************************************************** + +-- Create a session global variable. +CREATE VARIABLE myvar_transfer int; + +-- Obtain information of the global variable created. +SELECT substr (varschema, 1, 10) AS varschema, + substr (varname, 1, 10) AS varname, + substr (owner, 1, 10) AS owner, ownertype, create_time + FROM syscat.variables + WHERE varname = 'MYVAR_TRANSFER'; + +SELECT substr (varschema, 1, 10) AS varschema, + substr (varname, 1, 10) AS varname, + substr (grantor, 1, 10) AS grantor, grantortype, + substr (grantee, 1, 10) AS grantee, granteetype, + readauth, writeauth + FROM syscat.variableauth + WHERE varname = 'MYVAR_TRANSFER'; + +-- Transfer ownership of the global variable to another user. +TRANSFER OWNERSHIP OF VARIABLE myvar_transfer + TO USER mohan PRESERVE PRIVILEGES; + +-- Obtain information of the global variable after TRANSFER. +SELECT substr (varschema, 1, 10) AS varschema, + substr (varname, 1, 10) AS varname, + substr (owner, 1, 10) AS owner, ownertype, create_time + FROM syscat.variables + WHERE varname = 'MYVAR_TRANSFER'; + +SELECT substr (varschema, 1, 10) AS varschema, + substr (varname, 1, 10) AS varname, + substr (grantor, 1, 10) AS grantor, grantortype, + substr (grantee, 1, 10) AS grantee, granteetype, + readauth, writeauth + FROM syscat.variableauth + WHERE varname = 'MYVAR_TRANSFER'; + +-- Drop the global variable. +DROP VARIABLE myvar_transfer; + +-- **************************************************************************** +-- 2. Use of global variable in a trigger which can be used to control the +-- operation on the trigger like switching off the trigger for maintenance. +-- **************************************************************************** +-- The code below shows how users can use global variables within a trigger +-- to control the operation of the trigger. +-- **************************************************************************** + +-- Create a global variable whose default value is set to 'N'. We will use +-- this global variable to enable or disable the firing of the trigger. Its +-- default will be 'N' since we want the trigger to be active by default. +CREATE VARIABLE disable_trigger char (1) DEFAULT ('N'); + +-- Grant write privilege only to the DBA User ID. We only want the DBA user to +-- be able to change the value of the global variable. This is because we want +-- to prevent regular users from being able to disable the trigger. +GRANT WRITE ON VARIABLE disable_trigger TO dba_user; + +-- Create a trigger that depends on the global variable. The trigger will only fire +-- if the 'disable_trigger' global variable is set to 'N'. +CREATE TRIGGER validate_t BEFORE INSERT ON EMPLOYEE + REFERENCING NEW AS n FOR EACH ROW + WHEN (disable_trigger = 'N' AND n.empno > '10000') + SIGNAL SQLSTATE '38000' + SET message_text = 'EMPLOYEE NUMBER TOO BIG and INVALID'; + +-- To diable the trigger the DBA will set the global variable to 'Y'. +SET disable_trigger = 'Y'; + +-- The DBA can perform table maintenance operations like for example importing older +-- records since the trigger will not fire. After completing the table operations, +-- the DBA can set the global variable again to 'N'. +SET disable_trigger = 'N'; + +-- Drop the trigger. +DROP TRIGGER validate_t; + +-- Drop the variable. +DROP VARIABLE disable_trigger; + +-- **************************************************************************** +-- 3. Use of global variable in a stored procedure. +-- **************************************************************************** +-- The code below shows how to use global variables in a stored procedure. +-- It returns the authorization level of the user invoking the stored +-- procedure. The authorization level returned will be different depending on +-- the user executing the stored procedure. +-- +-- The idea of this example is that the users will only have permissions to +-- execute the stored procedure and not to modify the global variable. Since +-- the default value of the global variable is "SESSION_USER" it will get the +-- correct value when called even if it was not set before. Each time the user +-- logs in and calls this stored procedure he will receive the correct +-- authorization level. +-- **************************************************************************** + +-- Create the table 'security.users'. +CREATE TABLE security.users (userid varchar (10) NOT NULL PRIMARY KEY, + firstname varchar(10), lastname varchar(10), + authlevel int); + +-- Populate table with the following data. +INSERT INTO security.users VALUES ('praveen', 'sanjay', 'mohan', 1); +INSERT INTO security.users VALUES ('PRAVEEN', 'SANJAY', 'MOHAN', 1); +INSERT INTO security.users VALUES ('padma', 'gaurav', 'PADMA', 3); + +-- Create a global variable. +CREATE VARIABLE security.gv_user VARCHAR (10) DEFAULT (SESSION_USER); + +-- Create procedure 'get_authorization' that is dependent on the +-- global variable 'security.gv_user'. +CREATE PROCEDURE get_authorization (OUT authorization INT) +RESULT SETS 1 +LANGUAGE SQL + SELECT authlevel INTO authorization + FROM security.users + WHERE userid = security.gv_user; + +-- Assign 'praveen' to variable 'security.gv_user'. +SET security.gv_user = 'praveen'; + +-- Call stored procedure 'get_authorization'. +-- The authorization level returned will be 1 +call get_authorization(?); + +-- Assign 'padma' to variable 'security.gv_user'. +SET security.gv_user = 'padma'; + +-- Call stored procedure 'get_authorization'. +-- The authorization level returned will be 3 +call get_authorization(?); + +-- Drop a procedure. +DROP PROCEDURE get_authorization; + +-- Drop a variable. +DROP VARIABLE security.gv_user; + +-- Drop a table. +DROP TABLE security.users; + +-- **************************************************************************** +-- 4. Use of a global variable in a view to show how global variables can help +-- to improve security and performance and to reduce complexity. +-- **************************************************************************** +-- The code below shows how global variables along with views can be used to +-- improve security, reduce complexity and improve performance. +-- **************************************************************************** + +-- A variable can be set by invoking a function that supplies the value +-- of the SESSION_USER special register to fetch the department number +-- for the current user. A view can use the value of this global variable +-- in a predicate to select only those rows that contains the user's +-- department. Since the value of the variable is set the +-- first time it is invoked, then we only execute the query once instead of +-- doing it for each row if the query was embedded in the view definition. +-- This will improve the performance. + +-- Create the global variable using a SELECT statement in the defination. +CREATE VARIABLE schema1.gv_workdept CHAR + DEFAULT ((SELECT workdept FROM employee + WHERE firstnme = SESSION_USER)); + +-- Create the view which depends on the global variable +CREATE VIEW schema1.emp_filtered AS + SELECT * FROM employee + WHERE workdept = schema1.gv_workdept; + +-- Adjust permissions so that other users can only select from the view. +-- Any user using this view will only be able to see his department rows. +GRANT SELECT on schema1.emp_filtered TO PUBLIC; + +-- Drop a view. +DROP VIEW schema1.emp_filtered; + +-- Drop a variable. +DROP VARIABLE schema1.gv_workdept; + +-- Disconnect from the database. +CONNECT RESET; + +TERMINATE; diff --git a/admin_scripts/healthmon.db2 b/admin_scripts/healthmon.db2 new file mode 100644 index 0000000..5927aa9 --- /dev/null +++ b/admin_scripts/healthmon.db2 @@ -0,0 +1,268 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: healthmon.db2 +-- +-- SAMPLE: How to use table functions for Health Monitor Snapshot +-- +-- SQL STATEMENTS USED: +-- SELECT +-- TERMINATE +-- UPDATE +-- +-- OUTPUT FILE: healthmon.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- HEALTH_MON parameter allows you to specify whether you want to monitor an +-- instance, its associated databases, and database objects according to +-- various health indicators. This parameter has to be set to ON. + +UPDATE DBM CFG USING HEALTH_MON ON IMMEDIATE; + +-- For each logical group (namely DBM, DB2, Tablespace and Container), there +-- are three types of UDFs: INFO, HI (Health Indicator) and HI_HIS (Health +-- Indicator HIStory) + +-- CREATE FUNCTION statement is used to register a UDF or function template +-- with application server. It has been included here to depict the prototype +-- of the UDFs and the table each of them return. + +-- Usage of UDFs: +-- select *|[,] +-- from table( ( [,] )) as +-- where partition has the following values +-- 0..n, with n>0 partition number +-- -1 means currently connected partition +-- -2 means all partitions + +-- Snapshot monitor UDF for HMon Snapshot DBM header table + +CREATE FUNCTION HEALTH_DBM_INFO ( INTEGER ) +RETURNS TABLE ( + SNAPSHOT_TIMESTAMP TIMESTAMP, + SERVER_INSTANCE_NAME VARCHAR(8), + ROLLED_UP_ALERT_STATE BIGINT, + ROLLED_UP_ALERT_STATE_DETAIL VARCHAR(20), + DB2START_TIME TIMESTAMP, + LAST_RESET TIMESTAMP, + NUM_NODES_IN_DB2_INSTANCE INT +) +SPECIFIC HEALTH_DBM_INFO +EXTERNAL NAME 'db2dbappext!health_dbm_info' +LANGUAGE C +PARAMETER STYLE db2sql +DETERMINISTIC +FENCED +CALLED ON NULL INPUT +NO SQL +EXTERNAL ACTION +SCRATCHPAD +FINAL CALL +DISALLOW PARALLEL; + +SELECT SERVER_INSTANCE_NAME, + DB2START_TIME +FROM TABLE (HEALTH_DBM_INFO (CAST(NULL AS INTEGER)) ) +AS HEALTH_DBM_INFO; + +-- Snapshot monitor UDF for HMon Snapshot DBM Health Indicator table + +CREATE FUNCTION HEALTH_DBM_HI ( INTEGER ) +RETURNS TABLE ( + SNAPSHOT_TIMESTAMP TIMESTAMP, + HI_ID BIGINT, + SERVER_INSTANCE_NAME VARCHAR(8), + HI_VALUE SMALLINT, + HI_TIMESTAMP TIMESTAMP, + HI_ALERT_STATE BIGINT, + HI_ALERT_STATE_DETAIL VARCHAR(20), + HI_FORMULA VARCHAR(2048), + HI_ADDITIONAL_INFO VARCHAR(4096) +) +SPECIFIC HEALTH_DBM_HI +EXTERNAL NAME 'db2dbappext!health_dbm_hi' +LANGUAGE C +PARAMETER STYLE db2sql +DETERMINISTIC +FENCED +CALLED ON NULL INPUT +NO SQL +EXTERNAL ACTION +SCRATCHPAD +FINAL CALL +DISALLOW PARALLEL; + +SELECT SNAPSHOT_TIMESTAMP, + HI_ID, + SERVER_INSTANCE_NAME, + HI_VALUE, + HI_ALERT_STATE +FROM TABLE (HEALTH_DBM_HI (CAST(NULL AS INTEGER)) ) +AS HEALTH_DBM_HI; + +-- Snapshot monitor UDF for HMon Snapshot DBM Health Indicator History table + +CREATE FUNCTION HEALTH_DBM_HI_HIS ( INTEGER ) +RETURNS TABLE ( + SNAPSHOT_TIMESTAMP TIMESTAMP, + HI_ID BIGINT, + SERVER_INSTANCE_NAME VARCHAR(8), + HI_VALUE SMALLINT, + HI_TIMESTAMP TIMESTAMP, + HI_ALERT_STATE BIGINT, + HI_ALERT_STATE_DETAIL VARCHAR(20), + HI_FORMULA VARCHAR(2048), + HI_ADDITIONAL_INFO VARCHAR(4096) +) +SPECIFIC HEALTH_DBM_HI_HIS +EXTERNAL NAME 'db2dbappext!health_dbm_hi_his' +LANGUAGE C +PARAMETER STYLE db2sql +DETERMINISTIC +FENCED +CALLED ON NULL INPUT +NO SQL +EXTERNAL ACTION +SCRATCHPAD +FINAL CALL +DISALLOW PARALLEL; + +SELECT SNAPSHOT_TIMESTAMP, + HI_ID, + SERVER_INSTANCE_NAME, + HI_VALUE, + HI_ALERT_STATE +FROM TABLE (HEALTH_DBM_HI_HIS (CAST(NULL AS INTEGER)) ) +AS HEALTH_DBM_HI_HIS; + +-- Snapshot monitor UDF for HMon Snapshot DB header table + +CREATE FUNCTION HEALTH_DB_INFO ( VARCHAR(255), INTEGER ) +RETURNS TABLE ( + SNAPSHOT_TIMESTAMP TIMESTAMP, + DB_NAME VARCHAR(8), + INPUT_DB_ALIAS VARCHAR(8), + DB_PATH VARCHAR(256), + DB_LOCATION INT, + SERVER_PLATFORM INT, + ROLLED_UP_ALERT_STATE BIGINT, + ROLLED_UP_ALERT_STATE_DETAIL VARCHAR(20) +) +SPECIFIC HEALTH_DB_INFO +EXTERNAL NAME 'db2dbappext!health_db_info' +LANGUAGE C +PARAMETER STYLE db2sql +DETERMINISTIC +FENCED +CALLED ON NULL INPUT +NO SQL +EXTERNAL ACTION +SCRATCHPAD +FINAL CALL +DISALLOW PARALLEL; + +SELECT SNAPSHOT_TIMESTAMP, + DB_NAME, + INPUT_DB_ALIAS, + DB_LOCATION, + SERVER_PLATFORM +FROM TABLE (HEALTH_DB_INFO('SAMPLE', 0 )) AS HEALTH_DB_INFO; + +-- Snapshot monitor UDF for HMon Snapshot Tablespace Health Indicator table + +CREATE FUNCTION HEALTH_TBS_HI ( VARCHAR(255), INTEGER ) +RETURNS TABLE ( + SNAPSHOT_TIMESTAMP TIMESTAMP, + TABLESPACE_NAME VARCHAR(18), + HI_ID BIGINT, + HI_VALUE SMALLINT, + HI_TIMESTAMP TIMESTAMP, + HI_ALERT_STATE BIGINT, + HI_ALERT_STATE_DETAIL VARCHAR(20), + HI_FORMULA VARCHAR(2048), + HI_ADDITIONAL_INFO VARCHAR(4096) +) +SPECIFIC HEALTH_TBS_HI +EXTERNAL NAME 'db2dbappext!health_tbs_hi' +LANGUAGE C +PARAMETER STYLE db2sql +DETERMINISTIC +FENCED +CALLED ON NULL INPUT +NO SQL +EXTERNAL ACTION +SCRATCHPAD +FINAL CALL +DISALLOW PARALLEL; + +SELECT TABLESPACE_NAME, + HI_ID, + HI_VALUE, + HI_ALERT_STATE +FROM TABLE (HEALTH_TBS_HI( 'SAMPLE', 0 )) AS HEALTH_TBS_HI; + +-- Snapshot monitor UDF for HMon Snapshot Container Health Indicator History +-- table + +CREATE FUNCTION HEALTH_CONT_HI_HIS( VARCHAR(255), INTEGER ) +RETURNS TABLE ( + SNAPSHOT_TIMESTAMP TIMESTAMP, + CONTAINER_NAME VARCHAR(256), + NODE_NUMBER INTEGER, + HI_ID BIGINT, + HI_VALUE SMALLINT, + HI_TIMESTAMP TIMESTAMP, + HI_ALERT_STATE BIGINT, + HI_ALERT_STATE_DETAIL VARCHAR(20), + HI_FORMULA VARCHAR(2048), + HI_ADDITIONAL_INFO VARCHAR(4096) +) +SPECIFIC HEALTH_CONT_HI_HIS +EXTERNAL NAME 'db2dbappext!health_cont_hi_his' +LANGUAGE C +PARAMETER STYLE db2sql +DETERMINISTIC +FENCED +CALLED ON NULL INPUT +NO SQL +EXTERNAL ACTION +SCRATCHPAD +FINAL CALL +DISALLOW PARALLEL; + +SELECT CONTAINER_NAME, + HI_VALUE, + HI_TIMESTAMP, + HI_VALUE +FROM TABLE (HEALTH_CONT_HI_HIS( 'SAMPLE', 0 )) AS HEALTH_CONT_HI_HIS; + +ROLLBACK; + +-- TERMINATE; diff --git a/admin_scripts/ingest_files.sh b/admin_scripts/ingest_files.sh new file mode 100755 index 0000000..87f4f4a --- /dev/null +++ b/admin_scripts/ingest_files.sh @@ -0,0 +1,532 @@ +#! /bin/bash + + +#--------------------------------------------------------------------------- +# (c) Copyright IBM Corp. 2010 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +#--------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------------------------------------------------- +# TITLE: Ingest utility sample script +# +# SAMPLE FILE NAME: ingest_files.sh +# +# PURPOSE: This sample demonstrates ingesting data from files into a single target table with the INGEST utility. This +# sample script is a shell script that generates and runs an INGEST command each time there are files to process. +# +# USAGE SCENARIO: This sample demonstrates the ongoing processing of files as they appear in a directory and ingesting data from +# the file into a target table in the database. +# +# The script continuously monitors a directory for the appearance of new input files for the ingest utility. +# Because files might appear in the directory before they are completely copied, the script waits for files with +# an extension of ".done". When it sees such a file, it assumes that an input file with the specified name but +# without the ".done" extension is complete and runs the INGEST command using that file as input. For example, +# when the script sees a file named "myFile.csv.done", it assumes that input file "myFile.csv" is complete and +# runs the INGEST command using that file as input. +# +# The ".done" files and input files are moved to a SUCCESS directory if the INGEST +# was successful; else the files are moved to a FAILED directory. The script also creates two log files: +# ingest_files.log that stores information messages (preceded by [INFO]), error messages (preceded by +# [ERROR]) if any of all the operations and all the INGEST commands i.e both the successful ones and the failed +# ones; failed_ingest.log stores information about all the failed INGEST commands. +# +# PREREQUISITES: This sample needs a table MY_SCHEMA.MY_TABLE that needs to be setup with two integer columns +# db2 "CREATE TABLE MY_SCHEMA.MY_TABLE (COL1 INTEGER, COL2 INTEGER)" +# This sample requires input data files that contains two integer fields in each row separated by a comma. +# Replace the sample values provided in section 2 with appropriate values. +# * INPUT_FILES_DIRECTORY: specifies the directory to look for the data files +# * DATABASE_NAME: specifies the database name containing the target table +# * SCHEMA_NAME: specifies the schema name +# * TABLE_NAME: specifies the name of the target table +# * MAIL_USER_NAME: specifies the user name who has to be notified through mail about the failed INGEST +# commands +# +# EXECUTION: chmod +x ingest_files.sh +# ./ingest_files.sh +# +# INPUTS: 1) USER_NAME +# 2) PASSWORD +# +# OUTPUT: This sample does not generate any output on the standard output. Check the log ingest_files.log created at +# /logs/ingest_files.log +# +# ---------------------------------------------------------------------------------------------------------------------- + + +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # +# SECTION 1: HANDLE COMMAND LINE ARGUMENTS # +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # + +# ---------- +# check the command line arguments +# ---------- + +if [ $# -ne 2 ] +then + echo -e "INVALID number of arguments" + echo -e "Enter two arguments: USER_NAME and PASSWORD" + exit 1 +fi + +# ---------- +# assign the command line arguments to shell variables +# ---------- + +USER_NAME=$1 +PASSWORD=$2 + +# ---------- +# check if user name and password is non-blank +# ---------- + +# if user name or password is blank +if [ ! -n "$USER_NAME" -o ! -n "$PASSWORD" ] +then + echo -e "username/password cannot be blank" + exit 1 +fi + +# --------------------------------------------------------------------------------------------------------------------- # +# END OF SECTION 1 # +# --------------------------------------------------------------------------------------------------------------------- # + +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # +# SECTION 2: INPUT VALUES # +# (SAMPLE VALUES, TO BE REPLACED BY THE USER OR # +# GOTTEN FROM THE $INGEST_FILE_... ENVIRONMENT VARIABLES SHOWN BELOW) # +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # + +# path to search for the data files +INPUT_FILES_DIRECTORY="$INGEST_FILES_DIRECTORY" +#INPUT_FILES_DIRECTORY="" +# example: INPUT_FILES_DIRECTORY="/home/data" + +# database name +DATABASE_NAME="$INGEST_FILES_DB" +#DATABASE_NAME="" +# example: DATABASE_NAME="OLAPDB" + +# schema name +SCHEMA_NAME="$INGEST_FILES_SCHEMA" +#SCHEMA_NAME="" +# example: SCHEMA_NAME="MY_SCHEMA" + +# target table name +TABLE_NAME="$INGEST_FILES_TABLE" +#TABLE_NAME="" +# example: TABLE_NAME="MY_TABLE" + +# user name of the user who has to be notified through mail about the failed INGEST commands +MAIL_USER_NAME="$INGEST_FILES_USER" + +# ---------- +# get the script path +# ---------- + +SCRIPT_PATH="$( dirname "$( which "$0" )" )" + +# --------------------------------------------------------------------------------------------------------------------- # +# END OF SECTION 2 # +# --------------------------------------------------------------------------------------------------------------------- # + + +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # +# SECTION 3: INGEST COMMAND DETAILS # +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # + +# This script generates an ingest command using the two parts sepcified below as well as the name of a file to be processed +# INGEST COMMAND DETAILS_PART1="FORMAT MESSAGES ${SCRIPT_PATH}/messages.txt RESTART NEW" +INGEST_COMMAND_DETAILS_PART1="FORMAT DELIMITED (\$field1 INTEGER EXTERNAL, \$field2 INTEGER EXTERNAL) MESSAGES ${SCRIPT_PATH}/messages.txt RESTART NEW" + +# INGEST_COMMAND_DETAILS_PART2=" ${SCHEMA_NAME}.${TABLE_NAME} VALUES " +INGEST_COMMAND_DETAILS_PART2="INSERT INTO ${SCHEMA_NAME}.${TABLE_NAME} VALUES (\$field1, \$field2)" + +# --------------------------------------------------------------------------------------------------------------------- # +# END OF SECTION 3 # +# --------------------------------------------------------------------------------------------------------------------- # + + +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # +# SECTION 4: SETUP ENVIRONMENT, LOGS, SUCCESS AND FAILED DIRECTORIES # +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # + +# ---------- +# create a logs directory in the same path as the script, if it already does not exist +# ---------- + +# if the logs directory does not exist at the SCRIPT_PATH, then create a logs directory +if [ ! -d ${SCRIPT_PATH}/logs ] +then + mkdir ${SCRIPT_PATH}/logs + # if mkdir fails then echo to stdout and exit + if [ $? -ne 0 ] + then + echo "unable to create logs directory at $SCRIPT_PATH" + exit 1 + fi +fi + +# ---------- +# create the log files if it already does not exist in the logs directory created above +# ---------- + +# two log files are created +# ingest_files.log: stores informational and error messages pertaining to the script. It stores information from all commands - failed or successful +# failed_ingest.log: stores information only about all the failed INGEST commands + +LOGFILE=${SCRIPT_PATH}/logs/ingest_files.log +FAILEDINGESTLOG=${SCRIPT_PATH}/logs/failed_ingest.log + +# if the log file does not exist in the LOGS directory, then create a logfile named ingest_files.log +if [ ! -f $LOGFILE ] +then + time=`date` + touch $LOGFILE + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$LOGFILE + echo -e "---------- INGEST SCRIPT LOG ----------" >>$LOGFILE + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$LOGFILE + echo -e $time" [INFO] log file $LOGFILE created" >>$LOGFILE +fi + +# if the log file does not exist in the LOGS directory, then create a logfile named failed_ingest.log +if [ ! -f $FAILEDINGESTLOG ] +then + time=`date` + touch $FAILEDINGESTLOG + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$FAILEDINGESTLOG + echo -e "---------- FAILED INGEST COMMANDS LOG ----------" >>$FAILEDINGESTLOG + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$FAILEDINGESTLOG + echo -e $time" [INFO] log file $FAILEDINGESTLOG created" >>$FAILEDINGESTLOG +fi + +# ---------- +# check if INPUT_FILES_DIRECTORY exists +# ---------- + +# if the INPUT_FILES_DIRECTORY is an invalid directory +if [ ! -d "$INPUT_FILES_DIRECTORY" ] +then + time=`date` + echo -e $time" [ERROR] ${INPUT_FILES_DIRECTORY} is not a directory or is not found" >>$LOGFILE + # if target directory does not exist then exit + exit 1 +fi + +# ---------- +# if INPUT_FILES_DIRECTORY exists then create a success and failed directory +# SUCCESS_DIRECTORY holds all the files that were successfully ingested +# FAILED_DIRECTORY holds all the files that were not successfully ingested +# ---------- + +echo -e $time" [INFO] ${INPUT_FILES_DIRECTORY} found" >>$LOGFILE + +# ---------- +# create a success directory if it already does not exist +# ---------- + +SUCCESS_DIRECTORY=${INPUT_FILES_DIRECTORY}/success + +# if SUCCESS_DIRECTORY does not already exist in INPUT_FILES_DIRECTORY, then create it +if [ ! -d "${SUCCESS_DIRECTORY}" ] +then + time=`date` + mkdir ${SUCCESS_DIRECTORY} >>$LOGFILE 2>&1 + # if mkdir fails then write in the log file and exit + if [ $? -ne 0 ] + then + echo -e $time" [ERROR] unable to create success directory at $INPUT_FILES_DIRECTORY" >>$LOGFILE + exit 1 + fi + echo -e $time" [INFO] ${SUCCESS_DIRECTORY} created" >>$LOGFILE +fi + +# ---------- +# create a failed directory if it already does not exists +# ---------- + +FAILED_DIRECTORY=${INPUT_FILES_DIRECTORY}/failed + +# if FAILED_DIRECTORY does not already exist in INPUT_FILES_DIRECTORY, then create it +if [ ! -d "${FAILED_DIRECTORY}" ] +then + time=`date` + mkdir ${FAILED_DIRECTORY} >>$LOGFILE 2>&1 + # if mkdir fails then write in the log file and exit + if [ $? -ne 0 ] + then + echo -e $time" [ERROR] unable to create failed directory at $INPUT_FILES_DIRECTORY" >>$LOGFILE + exit 1 + fi + echo -e $time" [INFO] ${FAILED_DIRECTORY} created" >>$LOGFILE +fi + +# --------------------------------------------------------------------------------------------------------------------- # +# END OF SECTION 4 # +# --------------------------------------------------------------------------------------------------------------------- # + + +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # +# SECTION 5: FIND FILE(S), # +# CONNECT TO THE DATABASE, # +# EXECUTE THE INGEST COMMAND # +# --------------------------------------------------------------------------------------------------------------------- # +# --------------------------------------------------------------------------------------------------------------------- # + + +# ---------- +# find files in the INPUT_FILES_DIRECTORY +# ---------- + +foundOneDoneFile=0 +while true +do + + DONE_FILES=`find ${INPUT_FILES_DIRECTORY} \( -name success -prune \) -o \( -name failed -prune \) -o -name "*.done" -type f -print` + + if [ ! -n "$DONE_FILES" ] + then + if [ "$foundOneDoneFile" = 1 ] + then + # We processed at least one ingest input file. Exit normally. + exit 0 + else + echo -e " " >>$LOGFILE + time=`date` + echo -e $time" [ERROR] no .done files found at $INPUT_FILES_DIRECTORY" >>$LOGFILE + echo -e " " >>$LOGFILE + exit 1 + fi + else + foundOneDoneFile=1 + + # ---------- + # connect to DATABASE_NAME as USER_NAME + # ---------- + + time=`date` + echo -e $time" [INFO] attempting to connect to $DATABASE_NAME as $USER.... ... .. . . ." >>$LOGFILE + + time=`date` + echo -e $time" [INFO] " >>$LOGFILE + db2 connect to $DATABASE_NAME USER $USER_NAME USING $PASSWORD >> $LOGFILE 2>&1 + + # if connection to the DATABASE_NAME AS USER_NAME fails then exit + if [ $? -ne 0 ] + then + time=`date` + echo -e $time" [ERROR] invalid database_name, user_name or password" >>$LOGFILE + # if database_name / user_name / password is invalid then exit + exit 1 + fi + + for DONE_FILE in $DONE_FILES + do + # Remove the ".done" suffix to get the input file name. + FILE=${DONE_FILE%\.done} + if [ ! -f $FILE ] + then + time=`date` + echo -e $time" [ERROR] File $DONE_FILE found but corresponding file $FILE not found. Skipping to next file." >>$LOGFILE + continue + fi + + # ---------- + # for each file found generate a separate INGEST command + # ---------- + + time=`date` + echo -e $time" [INFO] ${FILE} found at $INPUT_FILES_DIRECTORY" >>$LOGFILE + + time=`date` + echo -e $time" [INFO] invoking INGEST command for $FILE found at $INPUT_FILES_DIRECTORY.... ... .. . . ." >>$LOGFILE + + timestamp=`date +%d%m%y%H%M%S` + jobId="${SCHEMA_NAME}.${TABLE_NAME}_${timestamp}" + + echo -e " " >>$LOGFILE + echo -e " " >>$LOGFILE + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$LOGFILE + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$LOGFILE + echo -e "-- Job Descriptors --" >>$LOGFILE + echo -e "Ingest job ID: job"$jobId >>$LOGFILE + echo -e "Start time: "$time >>$LOGFILE + echo -e " " >>$LOGFILE + echo -e "Source file: "$FILE >>$LOGFILE + echo -e "Target table: "$SCHEMA_NAME"."$TABLE_NAME >>$LOGFILE + echo -e "Target database: "$DATABASE_NAME >>$LOGFILE + echo -e "User ID: "$USER_NAME >>$LOGFILE + echo -e " " >>$LOGFILE + + startTime=`date` + startTimeSecs=`date +%s` + echo -e "-- Ingest details --" >>$LOGFILE + echo -e $startTime" [INFO] " >>$LOGFILE + echo -e " " >>$LOGFILE + + db2 -xv "INGEST FROM FILE ${FILE} ${INGEST_COMMAND_DETAILS_PART1} '${jobId}' ${INGEST_COMMAND_DETAILS_PART2}" >>$LOGFILE 2>&1 + + # capture the return status of INGEST. 0 => success and >4 => failure + INGEST_RET_CODE=$? + + endTime=`date` + endTimeSecs=`date +%s` + echo -e $endTime" [INFO] " >>$LOGFILE + duration=$(($endTimeSecs - $startTimeSecs)) + + echo -e " " >>$LOGFILE + echo -e "-- Job execution summary --" >>$LOGFILE + echo -e "Return code: "$INGEST_RET_CODE >>$LOGFILE + echo -e " " >>$LOGFILE + echo -e "Start time: "$startTime >>$LOGFILE + echo -e "End time: "$endTime >>$LOGFILE + echo -e "Duration: "$duration "seconds" >>$LOGFILE + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$LOGFILE + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$LOGFILE + echo -e " " >>$LOGFILE + echo -e " " >>$LOGFILE + + # ---------- + # check the return status of the INGEST command + # ---------- + + # if INGEST was successful for FILE then move to SUCCESS_DIRECTORY + if [ $INGEST_RET_CODE -lt 4 ] + then + time=`date` + echo -e $time" [INFO] $FILE successfully ingested" >>$LOGFILE + + time=`date` + echo -e $time" [INFO] moving $FILE to success directory at ${SUCCESS_DIRECTORY}.... ... .. . . ." >>$LOGFILE + + # ---------- + # move FILE to SUCCESS_DIRECTORY + # ---------- + + time=`date` + mv_cmd_success=`mv ${DONE_FILE} ${FILE} ${SUCCESS_DIRECTORY}/ 2>&1` + + # if FILE was successfully moved to SUCCESS_DIRECTORY + if [ $? -eq 0 ] + then + echo -e $time" [INFO] $FILE successfully moved to success directory at ${SUCCESS_DIRECTORY}" >>$LOGFILE + echo -e " " >>$LOGFILE + # if FILE could not be moved to SUCCESS_DIRECTORY + else + echo -e $time" [ERROR] unable to move $FILE to success directory at ${SUCCESS_DIRECTORY}" >>$LOGFILE + echo -e $time" [ERROR] "$mv_cmd_success >>$LOGFILE + echo -e " " >>$LOGFILE + fi + echo -e " " >>$LOGFILE + + # if INGEST failed failed for FILE then move to FAILED_DIRECTORY + else + time=`date` + echo -e $time" [ERROR] ingesting $FILE failed" >>$LOGFILE + + time=`date` + echo -e $time" [INFO] moving $FILE to failed directory at ${FAILED_DIRECTORY}.... ... .. . . ." >>$LOGFILE + + # ---------- + # move FILE to failed directory + # ---------- + + time=`date` + mv_cmd_error=`mv ${DONE_FILE} ${FILE} ${FAILED_DIRECTORY}/ 2>&1` + + # if FILE was successfully moved to FAILED_DIRECTORY + if [ $? -eq 0 ] + then + echo -e $time" [INFO] $FILE successfully moved to failed directory at ${FAILED_DIRECTORY}" >>$LOGFILE + echo -e " " >>$LOGFILE + # if FILE could not be moved to FAILED_DIRECTORY + else + echo -e $time" [ERROR] unable to move $FILE to failed directory at ${FAILED_DIRECTORY}" >>$LOGFILE + echo -e $time" [ERROR] "${mv_cmd_error} >>$LOGFILE + echo -e " " >>$LOGFILE + fi + + # notify the user by sending a mail + mail $MAIL_USER_NAME <>$FAILEDINGESTLOG + echo -e " " >>$FAILEDINGESTLOG + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$FAILEDINGESTLOG + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$FAILEDINGESTLOG + echo -e "-- Job Descriptors --" >>$FAILEDINGESTLOG + echo -e "Ingest job ID: job"$jobId >>$FAILEDINGESTLOG + echo -e "Start time: "$startTime >>$FAILEDINGESTLOG + echo -e " " >>$FAILEDINGESTLOG + echo -e "Source file: "$FILE >>$FAILEDINGESTLOG + echo -e "Target table: "$SCHEMA_NAME"."$TABLE_NAME >>$FAILEDINGESTLOG + echo -e "Target database: "$DATABASE_NAME >>$FAILEDINGESTLOG + echo -e "User ID: "$USER_NAME >>$FAILEDINGESTLOG + echo -e " " >>$FAILEDINGESTLOG + + echo -e "-- Ingest details --" >>$FAILEDINGESTLOG + echo -e $startTime" [INFO] " >>$FAILEDINGESTLOG + echo -e " " >>$FAILEDINGESTLOG + + # log failed ingest command text + INGEST_COMMAND="INGEST FROM FILE ${FILE} ${INGEST_COMMAND_DETAILS_PART1} '${jobId}' ${INGEST_COMMAND_DETAILS_PART2}" + echo -e $INGEST_COMMAND >>$FAILEDINGESTLOG + + echo -e " " >>$FAILEDINGESTLOG + echo -e $endTime" [INFO] " >>$FAILEDINGESTLOG + echo -e " " >>$FAILEDINGESTLOG + echo -e "-- Message --" >>$FAILEDINGESTLOG + cat ${SCRIPT_PATH}/messages.txt >>$FAILEDINGESTLOG + + echo -e " " >>$FAILEDINGESTLOG + echo -e "-- Job execution summary --" >>$FAILEDINGESTLOG + echo -e "Return code: "$INGEST_RET_CODE >>$FAILEDINGESTLOG + echo -e " " >>$FAILEDINGESTLOG + echo -e "Start time: "$startTime >>$FAILEDINGESTLOG + echo -e "End time: "$endTime >>$FAILEDINGESTLOG + echo -e "Duration: "$duration "seconds" >>$FAILEDINGESTLOG + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$FAILEDINGESTLOG + echo -e "-------------------------------------------------------------------------------------------------------------------------------" >>$FAILEDINGESTLOG + echo -e " " >>$FAILEDINGESTLOG + echo -e " " >>$FAILEDINGESTLOG + + fi + done + fi +done +# ---------- +# end of for +# ---------- + +# --------------------------------------------------------------------------------------------------------------------- # +# END OF SECTION 5 # +# --------------------------------------------------------------------------------------------------------------------- # + diff --git a/admin_scripts/largerid.db2 b/admin_scripts/largerid.db2 new file mode 100644 index 0000000..668aa16 --- /dev/null +++ b/admin_scripts/largerid.db2 @@ -0,0 +1,256 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: largerid.db2 +-- +-- SAMPLE: How to enable Large RIDs support on both new tables/tablespaces and +-- existing tables/tablespaces. +-- +-- This sample shows: +-- 1. Converting a regular DMS tablespaces to a large DMS tablespaces. +-- 2. Table level migration - from earlier versions to new version to +-- support larger table sizes. +-- 3. Reorganizing indexes to support Large RIDs. +-- +-- SQL STATEMENTS USED: +-- ALTER TABLESPACE +-- CREATE TABLE +-- CREATE TABLESPACE +-- REORG +-- SELECT +-- SET INTEGRITY +-- TERMINATE +-- +-- OUTPUT FILE: largerid.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to database. +CONNECT TO sample@ + +-- The following scenario shows how a table which resides in a regular DMS +-- tablespaces can be converted to reside into large DMS tablespaces to +-- support large RIDs. + +-- Create a regular DMS tablespace. +CREATE REGULAR TABLESPACE largetbsp MANAGED BY DATABASE USING (FILE 'cont1' 1000)@ + +-- Create a table in 'largetbsp' DMS tablespace. +CREATE TABLE large (max INT, min INT) IN largetbsp@ + +-- Create an index on 'large' table. +CREATE INDEX large_ind ON large (max)@ + +-- Alter tablespace from a regular DMS tablespace to large DMS tablespace to +-- support large RIDs. +ALTER TABLESPACE largetbsp CONVERT TO LARGE@ + +-- Rebuild/Reogranize indexes on table to support large RIDs. +-- Reorg reorganizes all indexes defined on a table by rebuilding the +-- index data into unfragmented, physically contiguous pages. +-- This will permit the table use 4-byte page numbers but not enable +-- the table to use more than 255 slots on a page. + +-- To use more than 255 slots on a page: +-- a) The table definition and the table space page size must allow it. +-- b) the table must be reorganized using classic, off-line reorg. + +REORG INDEXES ALL FOR TABLE large@ + +-- Drop index, table and tablespace. +DROP INDEX large_ind@ +DROP TABLE large@ +DROP TABLESPACE largetbsp@ + +-- The following scenario shows how a partitioned table which resides in a +-- regular DMS tablespaces can be converted to reside into large DMS +-- tablespaces to support large RIDs. + +-- Create regular DMS tablespaces. +CREATE REGULAR TABLESPACE tbsp1 MANAGED BY DATABASE USING (FILE 'cont1' 1000)@ +CREATE REGULAR TABLESPACE tbsp2 MANAGED BY DATABASE USING (FILE 'cont2' 1000)@ +CREATE REGULAR TABLESPACE tbsp3 MANAGED BY DATABASE USING (FILE 'CONT3' 1000)@ + +-- Create a partitioned table. +CREATE TABLE large (max SMALLINT NOT NULL, CONSTRAINT CC CHECK (max>0)) + PARTITION BY RANGE (max) + (PART part1 STARTING FROM (1) ENDING (3) IN tbsp1, + PART part2 STARTING FROM (4) ENDING (6) IN tbsp2, + PART part3 STARTING FROM (7) ENDING (9) IN tbsp3)@ + +-- Insert data into the table. +INSERT INTO large VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9)@ + +-- Display records from the table. +SELECT * FROM large@ + +-- If a partitioned table has data partitions in different regular DMS +-- tablespaces, then the tablespaces cannot be converted to large +-- with the current definition. +-- To do this, first detach all the partitions of the table, later +-- convert all the tablespaces to large, reorg all the detached +-- partitions to support large RID. Finally, reattach the partitions. +-- Now the entire table supports large RIDs. + +create procedure tableExists (IN schemaName varchar(128), IN tableName varchar(128), OUT notFound int) + specific tableExists + language SQL +BEGIN + + declare dpid int; + + declare tabCheck cursor for + select DATAPARTITIONID from sysibm.sysdatapartitions where tabschema = schemaName and tabname = tableName; + declare exit handler for NOT FOUND + set notFound = 1; + + open tabCheck; + fetch tabCheck into dpid; + close tabCheck; + +END@ + +create procedure waitForDetach (OUT msg varchar(128), IN schemaName varchar(128), IN tableName varchar(128), IN partName varchar(128) DEFAULT NULL) + specific waitForDetach + language SQL +BEGIN + + declare dpid int; + declare dpstate char; + declare done int default 0; + declare tabNotFound int default 0; + + declare allDetachCheck cursor for + select DATAPARTITIONID, STATUS from sysibm.sysdatapartitions + where tabschema = schemaName and tabname = tableName and (status = 'L' OR status = 'D'); + + declare oneDetachCheck cursor for + select DATAPARTITIONID, STATUS from sysibm.sysdatapartitions + where tabschema = schemaName and tabname = tableName and datapartitionname = partName; + + declare continue handler for NOT FOUND + set done = 1; + + set current lock timeout 120; + + -- if table does not exist in sysdatapartitions, return error + call tableExists (schemaName, tableName, tabNotFound); + if tabNotFound = 1 + THEN + set msg = 'Table not found'; + RETURN -1; + END IF; + +wait_loop: + LOOP + if partName IS NOT NULL + THEN + open oneDetachCheck; + fetch oneDetachCheck into dpid, dpstate; + + -- two cases here: + -- (i) detach has already completed hence partition entry not found in catalogs (indicated by done == 1, handled later) + -- (ii) detach in progress, partition state should not be visible + IF done <> 1 AND (dpstate = '' OR dpstate = 'A') + THEN + set msg = 'Cannot waitForDetach if DETACH was not issued on this partition'; + return -1; + END IF; + + close oneDetachCheck; + ELSE + open allDetachCheck; + fetch allDetachCheck into dpid, dpstate; + close allDetachCheck; + END IF; + if done = 1 + THEN + set msg = 'DETACH completed'; + LEAVE wait_loop; + ELSE + ITERATE wait_loop; + END IF; + END LOOP; + +END@ + +ALTER TABLE large DETACH PARTITION PART3 INTO TABLE detach_part3@ +CALL waitForDetach(?, CURRENT SCHEMA, 'DETACH_PART3')@ +ALTER TABLE large DETACH PARTITION PART2 INTO TABLE detach_part2@ +CALL waitForDetach(?, CURRENT SCHEMA, 'DETACH_PART2')@ + +-- Display records contained in each table. +SELECT * FROM large@ +CALL waitForDetach(?, CURRENT SCHEMA, 'LARGE')@ + +SELECT * FROM detach_part2@ +SELECT * FROM detach_part3@ + +-- Convert all tablespaces from regular DMS tablespace to large DMS tablespace. +ALTER TABLESPACE tbsp3 CONVERT TO LARGE@ +ALTER TABLESPACE tbsp2 CONVERT TO LARGE@ +ALTER TABLESPACE tbsp1 CONVERT TO LARGE@ + +-- Reorganize the detached partitions in order to support large RIDs. +-- Reorg reorganizes a table by reconstructing the rows to eliminate +-- fragmented data, and by compacting information. + +REORG TABLE detach_part3@ +REORG TABLE detach_part2@ +REORG TABLE large@ + +-- Reattach the reorganized detached partitions for table to support +-- large RIDs. +ALTER TABLE large ATTACH PARTITION part2 STARTING FROM (4) ENDING (6) + FROM TABLE detach_part2@ +ALTER TABLE large ATTACH PARTITION part3 STARTING FROM (7) ENDING (9) + FROM TABLE detach_part3@ +-- After performing above ALTER statements, table is put into +-- set integrity peniding state. +-- Before performing SELECT, table must be brought out from pending state. +SET INTEGRITY FOR large IMMEDIATE CHECKED@ + +-- Display records from the table. +SELECT * FROM large@ + +-- Drop procedures +DROP PROCEDURE tableExists@ +DROP PROCEDURE waitForDetach@ + +-- Drop tables and tablespaces. +DROP TABLE large@ +DROP TABLESPACE tbsp1@ +DROP TABLESPACE tbsp2@ +DROP TABLESPACE tbsp3@ + +-- Disconnect from a database. +CONNECT RESET@ + +TERMINATE@ + diff --git a/admin_scripts/lbac.db2 b/admin_scripts/lbac.db2 new file mode 100644 index 0000000..4df7656 --- /dev/null +++ b/admin_scripts/lbac.db2 @@ -0,0 +1,734 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: lbac.db2 +-- +-- SAMPLE: How to take advantage of DB2 LBAC (Label Based Access Control) +-- feature +-- +-- PREREQUISITES FOR RUNNING THE SAMPLE: +-- The sample assumes the existance of the following users along with +-- the specified passwords +-- secadm with password "secadm123" +-- joe with password "joe123" +-- bob with password "bob123" +-- pat with password "pat123" +-- +-- SQL STATEMENTS USED: +-- CONNECT +-- CREATE SECURITY LABEL +-- CREATE SECURITY POLICY +-- CREATE TABLE +-- DELETE +-- DROP SECURITY LABEL +-- DROP TABLE +-- GRANT SECURITY LABEL +-- GRANT EXEMPTION +-- REVOKE SECURITY LABEL +-- REVOKE EXEMPTION +-- INSERT +-- UPDATE +-- SELECT +-- +-- OUTPUT FILE: lbac.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Disconnect from any existing database connection. +CONNECT RESET; + +-- This example shows how to take advantage of the DB2 LBAC feature. +-- It shows LBAC being used in a hypothetical government setting. + +-- Grant SECADM authority to a user secadm +-- An user with SYSADM authority can grant SECADM authority to a user + +CONNECT TO sample; +GRANT SECADM ON DATABASE TO USER secadm; + +-- Connect as the user with SECADM authority +CONNECT TO sample USER secadm USING secadm123; + +-- First, a user with SECADM authority creates the security label components +-- that will be part of the security policy. This sample uses three security +-- label components: level, departments, and groups. + +-- The level component is of type ARRAY and has these elements: +-- +-- TOP SECRET (Highest) +-- SECRET +-- CONFIDENTIAL +-- UNCLASSIFIED (Lowest) +-- +-- This statement creates the level component: + +CREATE SECURITY LABEL COMPONENT level ARRAY ['TOP SECRET', + 'SECRET', + 'CONFIDENTIAL', + 'UNCLASSIFIED']; + +-- The departments component is of type SET and has these elements: +-- +-- ALPHA, SIGMA, and DELTA +-- +-- This statement creates the departments component: + +CREATE SECURITY LABEL COMPONENT departments SET {'ALPHA', 'DELTA', 'SIGMA'}; + +-- The groups component is of type TREE and has these elements: +-- +-- G1 (ROOT) +-- +--+--+ +-- | | +-- G2 G3 +-- +--+--+ +-- | | +-- G4 G5 +-- +-- This statement creates the groups component: + +CREATE SECURITY LABEL COMPONENT groups + TREE ('G1' ROOT, + 'G2' UNDER 'G1', + 'G3' UNDER 'G1', + 'G4' UNDER 'G3', + 'G5' UNDER 'G3'); + +-- Next, a user with SECADM authority executes this statement to +-- create a security policy named secpolicy that has the three +-- components previously created and uses the DB2LBACRULES rule set. + +CREATE SECURITY POLICY secpolicy + COMPONENTS level, departments, groups + WITH DB2LBACRULES; + +-- Now the user with SECADM authority can execute the following +-- statements to create some security labels that are part of the +-- security policy secpolicy. + +-- For the purposes of this example the security label names end with +-- a number that indicates the relative "strength" of the label. +-- In other words seclabel1 is blocked by seclabel2 and seclabel2 is +-- blocked by seclabel3 but not by seclabel1, etc. This is only to make +-- the example easier to follow. + +CREATE SECURITY LABEL secpolicy.seclabel1 + COMPONENT level 'UNCLASSIFIED', + COMPONENT departments 'ALPHA', 'DELTA', + COMPONENT groups 'G4'; + +CREATE SECURITY LABEL secpolicy.seclabel2 + COMPONENT level 'CONFIDENTIAL', + COMPONENT departments 'ALPHA', 'DELTA', + COMPONENT groups 'G4'; + +CREATE SECURITY LABEL secpolicy.seclabel3 + COMPONENT level 'SECRET', + COMPONENT departments 'ALPHA', 'DELTA', + COMPONENT groups 'G4'; + +CREATE SECURITY LABEL secpolicy.seclabel4 + COMPONENT level 'TOP SECRET', + COMPONENT departments 'ALPHA', 'DELTA', + COMPONENT groups 'G4'; + +-- Granting seclabel2 to user joe in order to create a column +-- secured with seclabel2 +GRANT SECURITY LABEL secpolicy.seclabel2 TO USER joe; + +CONNECT TO sample USER joe USING joe123; + +-- The user with SECADM authority now creates a protected table +-- and attaches the security policy to the table. The table includes +-- a column named rowseclabel that will hold the security labels +-- protecting the rows. It also has a column named payrank that is +-- protected by the security label seclabel2. The payrank column has +-- a default value of 0. + +-- This is the statement that creates a protected table: + +CREATE TABLE joe.employee_lbac ( + empno int, + lastname char(10), + deptno int, + payrank int SECURED WITH seclabel2 DEFAULT 0, + rowseclabel DB2SECURITYLABEL + ) + SECURITY POLICY secpolicy; + +-- The protected table is now ready for use. + +-- The user with SECADM authority grants security label seclabel1 to user joe +CONNECT TO sample USER secadm USING secadm123; + +REVOKE SECURITY LABEL secpolicy.seclabel2 FROM USER joe; +GRANT SECURITY LABEL secpolicy.seclabel1 TO USER joe; + +-- Joe now holds the security label seclabel1 for both read and write access. + +-- turn off echo Current Command option to suppress printing of echo command +UPDATE COMMAND OPTIONS USING v OFF; + +!echo ---------------------------------------------------------------------; +!echo -- INSERTING INTO A PROTECTED TABLE ---; +!echo ---------------------------------------------------------------------; + +-- turn on the Echo Current Command option +UPDATE COMMAND OPTIONS USING v ON; + +-- Joe tries to insert a row to the table by specifying a value for every +-- column except rowseclabel: + +CONNECT TO sample USER joe USING joe123; + +INSERT INTO joe.employee_lbac (empno, lastname, deptno, payrank) + VALUES (1, 'Smith', 11, 3); + +-- The insert fails because the column 'payrank' is protected by the +-- security label seclabel2 and joe holds security label seclabel1. The security +-- label seclabel1 cannot read from or write to security label seclabel2. + +-- Joe removes the column payrank from the INSERT statement. This time the insert +-- is successful because the column payrank has a default value and therefore it +-- is not necessary that an explicit value be given for it. + +INSERT INTO joe.employee_lbac (empno, lastname, deptno) VALUES (1, 'Smith', 11); + +-- Because no value is given for the column rowseclabel, the security label that +-- the user holds for writing is inserted by default. In the case of user joe +-- that is seclabel1. + +-- The rows in table employee_lbac now look like this: + +-- EMPNO LASTNAME DEPTNO PAYRANK ROWSECLABEL +-- 1 Smith 11 0 UNCLASSIFIED:(ALPHA,DELTA):G4 + +-- Now the user with SECADM authority revokes seclabel1 from joe and grants +-- him seclabel2 instead, by executing these statements: +CONNECT TO sample USER secadm USING secadm123; + +REVOKE SECURITY LABEL secpolicy.seclabel1 FROM USER joe; +GRANT SECURITY LABEL secpolicy.seclabel2 TO USER joe; + +-- Joe now holds the security label seclabel2 for both read and write access. +-- He no longer holds the security label seclabel1. + +-- Joe inserts another row as he did before: +CONNECT TO sample USER joe USING joe123; +INSERT INTO joe.employee_lbac (empno, lastname, deptno) VALUES (2, 'Haas', 11); + +-- Select the rows in the table employee_lbac +SELECT empno, + lastname, + deptno, + payrank, CAST(rowseclabel AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- The values in the rowseclabel column are shown in a character representation +-- of the internal format. This is the default. Joe wants to read them in +-- security label string format so he executes the select again, this time using +-- the SECLABEL_TO_CHAR built-in function to convert the security labels as below: +-- CAST to VARCHAR(30) is done on rowseclabel column only to make the output fit +-- the screen and is not otherwise required. + +-- Select the rows in the table employee_lbac +SELECT empno, + lastname, + deptno, + payrank, CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- Joe wants the next row he writes to be protected by seclabel1 rather than the +-- security label he currently holds. He uses the SECLABEL_BY_NAME built-in +-- function to provide seclabel1 for insert. +INSERT INTO joe.employee_lbac (empno, lastname, deptno, rowseclabel) + VALUES (3, 'Miller', 11, SECLABEL_BY_NAME('SECPOLICY', 'SECLABEL1')); + +-- The statement does not give joe the results he wants. When you provide an +-- explicit security label to protect a row you must be able to write to data +-- protected by that security label, otherwise it cannot be used. You cannot +-- insert a row that you would be unable to write to. +-- The reason that seclabel2 cannot write to seclabel1 is the rule DB2LBACWRITEARRAY. +-- That rule prevents writing to any security label that has an element for an ARRAY +-- type component that is different than the element for the same component in your +-- security label. The security label seclabel1 has a value of 'UNCLASSIFIED' for +-- the level component while seclabel2 has a value of 'CONFIDENTIAL' for that component. + +-- What happens when you try to insert a security label that you cannot write to +-- depends on whether or not the security policy was created with the +-- RESTRICT NOT AUTHORIZED WRITE SECURITY LABEL option. It the option was used +-- then the statement fails and an error is returned. If it was not used then no +-- error is given but the provided security label is ignored and the user's +-- security label for write access is used instead. +-- The security policy secpolicy was created without +-- the RESTRICT NOT AUTHORIZED WRITE SECURITY LABEL option, so no error is given +-- and joe's current security label is used instead. + +-- Select the rows in the table employee_lbac +SELECT empno, + lastname, + deptno, + payrank, CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- A user with SECADM authority now grants joe an exemption to the part of +-- the DB2LBACWRITEARRAY rule that prevents writing to elements that are lower +-- than yours (the write-down portion): + +CONNECT TO sample USER secadm USING secadm123; + +GRANT EXEMPTION ON RULE DB2LBACWRITEARRAY WRITEDOWN + FOR secpolicy + TO USER joe; + +-- Joe again tries to insert a row protected by seclabel1: +CONNECT TO sample USER joe USING joe123; + +INSERT INTO joe.employee_lbac (empno, lastname, deptno, rowseclabel) + VALUES (4, 'Barberra', 11, SECLABEL_BY_NAME('SECPOLICY', 'SECLABEL1')); + +-- This insert does what joe expects because joe can now write to data +-- protected by seclabel1 + +-- Select the rows in the table employee_lbac +SELECT empno, + lastname, + deptno, + payrank, CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- The next row that joe needs to insert must be protected by a security label in +-- which level = UNCLASSIFIED, departments = ALPHA, and groups = G4. There is no +-- named security label with those values so joe must use the SECLABEL built-in +-- function. The SECLABEL function creates a security label based on a list of +-- element values. + +INSERT INTO joe.employee_lbac (empno, lastname, deptno, rowseclabel) + VALUES (5, 'Kubrick', 11, SECLABEL('SECPOLICY', 'UNCLASSIFIED:ALPHA:G4')); + +-- Joe is able to write to data protected by a security label with the +-- values 'UNCLASSIFIED:ALPHA:G4' so the insert takes place and the +-- supplied security label is used. + +-- Select the rows in the table employee_lbac +SELECT empno, + lastname, + deptno, + payrank, CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- Joe must now insert a row that includes a payrank of 2 and is to be protected +-- by seclabel2. Joe currently holds security label seclabel2 for write access. +-- This means that he is able to write to the column payrank, which is protected +-- by seclabel2. It also means that when he does not explicitly provide a security +-- label for the column rowseclabel, the security label seclabel2 will be used. +-- Joe executes this insert statement, which executes without error: + +INSERT INTO joe.employee_lbac (empno, lastname, deptno, payrank) + VALUES (6, 'Little', 11, 2); + +-- Select the rows in the table employee_lbac +SELECT empno, + lastname, + deptno, + payrank, CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- Joe has one last row to insert. This one must be protected by seclabel4 and +-- must have a payrank of 5. Security labels seclabel2 and seclabel4 both have +-- the same values for the departments and groups components. They are only +-- different in the level component. So, if Joe is granted an exemption to the +-- rule DB2WRITEARRAY for write-up he will be able to write to data protected +-- by seclabel4 and will therefore be able to insert seclabel4 into the column. + +-- Note: Granting an exemption is a somewhat drastic solution to this problem +-- and is only being done here for demonstration purposes. + +-- A user with SECADM authority grants joe an exemption to the write-up portion +-- of the DB2WRITEARRAY rule by executing this statement: + +CONNECT TO sample USER secadm USING secadm123; + +GRANT EXEMPTION ON RULE DB2LBACWRITEARRAY WRITEUP + FOR secpolicy + TO USER joe; + +-- Joe now does an insert with security label seclabel4 +CONNECT TO sample USER joe USING joe123; + +INSERT INTO joe.employee_lbac (empno, lastname, deptno, payrank, rowseclabel) + VALUES (7, 'Addams', 22, 5, SECLABEL_BY_NAME('SECPOLICY', 'SECLABEL4')); + +-- The rows in table employee_lbac now look like this: + +-- EMPNO LASTNAME DEPTNO PAYRANK ROWSECLABEL +-- ----------- ---------- ----------- ----------- ------------------------------ +-- 1 Smith 11 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 2 Haas 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 3 Miller 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 4 Barberra 11 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 5 Kubrick 11 0 UNCLASSIFIED:ALPHA:G4 +-- 6 Little 11 2 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 7 Addams 22 5 TOP SECRET:(ALPHA,DELTA):G4 + +-- turn off echo Current Command option to suppress printing of echo command +UPDATE COMMAND OPTIONS USING v OFF; + +!echo ---------------------------------------------------------------------; +!echo -- READING FROM A PROTECTED TABLE ---; +!echo ---------------------------------------------------------------------; + +-- turn on the Echo Current Command option +UPDATE COMMAND OPTIONS USING v ON; + +-- Just after finishing the previous inserts. Joe wants to make sure that all of +-- the data is in the table so he executes this SELECT statement to count the rows: + +SELECT COUNT(*) AS count FROM joe.employee_lbac; + +-- The statement returns a count of 6. There seems to be a row missing. +-- Joe executes this statement to view the rows: + +-- Select the rows in the table employee_lbac +SELECT empno, + lastname, + deptno, + payrank, CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- The reason is that joe holds only seclabel2 for read access and has been granted +-- no exemptions to the rules for read access. He cannot read the last row because +-- his LBAC credentials prevent it. + +-- To allow joe to view the entire table, a user with SECADM authority revokes +-- seclabel2 from joe and grants seclabel4 to him: + +CONNECT TO sample USER secadm USING secadm123; + +REVOKE SECURITY LABEL secpolicy.seclabel2 FROM USER joe; +GRANT SECURITY LABEL secpolicy.seclabel4 TO USER joe; + +-- Select the rows in the table employee_lbac +CONNECT TO sample USER joe USING joe123; + +SELECT empno, + lastname, + deptno, + payrank, CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- Joe is now done with the inserts so the user with SECADM authority revokes +-- all of joe's exemptions and sets his security label back to seclabel1 with +-- these statements: +CONNECT TO sample USER secadm USING secadm123; + +REVOKE EXEMPTION ON RULE ALL FOR secpolicy FROM USER joe; +REVOKE SECURITY LABEL secpolicy.seclabel4 FROM USER joe; +GRANT SECURITY LABEL secpolicy.seclabel1 TO USER joe; + +-- Joe now tries to count the rows again. This time the count is 3 because with +-- a security label of seclabel1 he is only able to read 3 of the rows. +CONNECT TO sample USER joe USING joe123; +SELECT COUNT(*) AS count FROM joe.employee_lbac; + +-- Joe tries to view the rows with this statement but because the +-- asterisk (*) includes the column payrank in the select the +-- statement fails. Joe no longer has read access to the column payrank. + +SELECT * FROM joe.employee_lbac; + +-- Joe changes the statement to exclude the payrank column and also to convert +-- the security labels to a security label string format, then executes it: + +SELECT empno, + lastname, + deptno, + CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) AS rowseclabel + FROM joe.employee_lbac; + +-- turn off echo Current Command option to suppress printing of echo command +UPDATE COMMAND OPTIONS USING v OFF; + +!echo ---------------------------------------------------------------------; +!echo -- UPDATING A PROTECTED TABLE ---; +!echo ---------------------------------------------------------------------; + +-- turn on the Echo Current Command option +UPDATE COMMAND OPTIONS USING v ON; + +-- These rows are in table employee_lbac: + +-- EMPNO LASTNAME DEPTNO PAYRANK ROWSECLABEL +-- ----------- ---------- ----------- ----------- ------------------------------ +-- 1 Smith 11 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 2 Haas 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 3 Miller 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 4 Barberra 11 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 5 Kubrick 11 0 UNCLASSIFIED:ALPHA:G4 +-- 6 Little 11 2 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 7 Addams 22 5 TOP SECRET:(ALPHA,DELTA):G4 + +-- User bob needs to make some updates to the employee_lbac table. A user +-- with SECADM authority grants him security label seclabel1 with this statement: +CONNECT TO sample USER secadm USING secadm123; +GRANT SECURITY LABEL secpolicy.seclabel1 TO USER bob; + +-- Grant select, insert, update, delete privileges on employee_lbac +-- table to bob, pat. This can be done by joe using the below statement +CONNECT TO sample user joe USING joe123; +GRANT INSERT, SELECT, UPDATE, DELETE ON TABLE joe.employee_lbac TO USER bob, pat; + +-- Bob issues the following update statement: +CONNECT TO sample USER bob USING bob123; +UPDATE joe.employee_lbac SET deptno = 0; + +-- The update executes without error but rows to which bob does not have +-- read access are not affected. Also, because the update does not explicitly +-- set the column rowseclabel it is automatically set to the security label +-- that bob holds for write access (seclabel1). + +-- After the statement, the rows in the table look like this: + +-- EMPNO LASTNAME DEPTNO PAYRANK ROWSECLABEL +-- ----------- ---------- ----------- ----------- ------------------------------ +-- 1 Smith 0 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 2 Haas 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 3 Miller 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 4 Barberra 0 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 5 Kubrick 0 0 UNCLASSIFIED:ALPHA:G4 +-- 6 Little 11 2 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 7 Addams 22 5 TOP SECRET:(ALPHA,DELTA):G4 + +-- Now bob tries to change all payranks greater than 0 to 1. He executes this +-- statement but the statement fails because he does not have write access or +-- read access to the column payrank: + +UPDATE joe.employee_lbac SET payrank = 1 WHERE payrank > 0; + +-- A user with SECADM authority changes bob's security label to seclabel3 + +-- Connect as the SECADM user +CONNECT TO sample USER secadm USING secadm123; + +REVOKE SECURITY LABEL secpolicy.seclabel1 FROM USER bob; +GRANT SECURITY LABEL secpolicy.seclabel3 TO USER bob; + +-- Bob tries the update again. This time it fails because seclabel3, which bob +-- holds for write access, has a value of 'SECRET' for the component level +-- and the security label protecting the row has a value of 'CONFIDENTIAL' for +-- that component. Writing to the row would violate the write-down part of the +-- DB2LBACWRITEARRAY rule. To allow bob to make the update, a user with SECADM +-- could either grant the security label seclabel2 to him or grant him an exemption +-- on the write-down portion of the DB2LBACWRITEARRAY rule. Granting a new security +-- label is by far the safest way to grant access, but for demonstration purposes +-- assume the user with SECADM authority grants the exemption: + +GRANT EXEMPTION ON RULE DB2LBACWRITEARRAY WRITEDOWN + FOR secpolicy + TO USER bob; + +-- Bob executes the update again. This time it executes with no error because bob has +-- both read and write access to the column payrank and also to the row. The update +-- does not affect the row where empno = 7, however because bob is not able to read that +-- row. Also, the security label protecting the updated row is changed to the security +-- label that bob holds for write access, namely seclabel3. + +CONNECT TO sample USER bob USING bob123; +UPDATE joe.employee_lbac SET payrank = 1 WHERE payrank > 0; + +-- After the statement, the rows in the table look like this: +-- EMPNO LASTNAME DEPTNO PAYRANK ROWSECLABEL +-- ----------- ---------- ----------- ----------- ------------------------------ +-- 1 Smith 0 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 2 Haas 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 3 Miller 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 4 Barberra 0 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 5 Kubrick 0 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 6 Little 11 1 SECRET:(ALPHA,DELTA):G4 +-- 7 Addams 22 5 TOP SECRET:(ALPHA,DELTA):G4 + +-- To check his work, bob selects the rows of the table. He uses the SECLABEL_TO_CHAR +-- built-in function to convert the security labels to a more readable form. + +SELECT empno, + lastname, + deptno, + payrank, CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- Bob needs to change the row where empno = 6 so that it it protected by seclabel2 +-- instead of seclabel3. Because he already holds an exemption to the write-down portion +-- of the DB2LBACWRITEARRAY rule he can write to seclabel2 and can therefore explicitly +-- use it in his update: + +UPDATE joe.employee_lbac + SET rowseclabel = SECLABEL_BY_NAME('SECPOLICY', 'SECLABEL2') + WHERE empno = 6; + +-- After the statement, the rows in the table look like this: +-- EMPNO LASTNAME DEPTNO PAYRANK ROWSECLABEL +-- ----------- ---------- ----------- ----------- ------------------------------ +-- 1 Smith 0 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 2 Haas 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 3 Miller 11 0 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 4 Barberra 0 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 5 Kubrick 0 0 UNCLASSIFIED:(ALPHA,DELTA):G4 +-- 6 Little 11 1 CONFIDENTIAL:(ALPHA,DELTA):G4 +-- 7 Addams 22 5 TOP SECRET:(ALPHA,DELTA):G4 + +-- Bob is finished with his updates. The user with SECADM authority revokes all +-- exemptions from him and also changes his security label back to seclabel1 + +CONNECT TO sample USER secadm USING secadm123; + +REVOKE EXEMPTION ON RULE ALL FOR secpolicy FROM USER bob; +REVOKE SECURITY LABEL secpolicy.seclabel3 FROM USER bob; +GRANT SECURITY LABEL secpolicy.seclabel1 TO USER bob; + +-- turn off echo Current Command option to suppress printing of echo command +UPDATE COMMAND OPTIONS USING v OFF; + +!echo ---------------------------------------------------------------------; +!echo -- DELETING FROM A PROTECTED TABLE ---; +!echo ---------------------------------------------------------------------; + +-- turn on the Echo Current Command option +UPDATE COMMAND OPTIONS USING v ON; + +-- User pat needs to delete some rows from the table employee_lbac. A user +-- with SECADM authority grants her security label seclabel1 with this statement: + +GRANT SECURITY LABEL secpolicy.seclabel1 TO USER pat; + +-- Pat issues the following SQL statement. It fails because she has neither +-- read access nor write access to the column payrank. + +CONNECT TO sample USER pat USING pat123; +DELETE FROM joe.employee_lbac WHERE EMPNO >= 1; + +-- A user with SECADM authority grants security label seclabel2 to pat: +CONNECT TO sample USER secadm USING secadm123; +REVOKE SECURITY LABEL secpolicy.seclabel1 FROM USER pat; +GRANT SECURITY LABEL secpolicy.seclabel2 TO USER pat; + +-- Pat tries the delete again. +CONNECT TO sample USER pat USING pat123; +DELETE FROM joe.employee_lbac WHERE EMPNO >= 1; + +-- This time the delete gives an error because some of the rows selected for deletion +-- are protected by security labels that pat cannot write to. For example the row in +-- which empno = 1 is protected by the security label seclabel1. Pat is able to read +-- that row but is unable to write to it because that would violate the write-down +-- portion of the DB2LBACWRITEARRAY rule. +-- No rows are affected by the statement. + +-- A user with SECADM authority grants pat an exemption to both the write-up and the +-- write-down portions of the DB2LBACWRITEARRAY rule: + +CONNECT TO sample USER secadm USING secadm123; + +GRANT EXEMPTION ON RULE DB2LBACWRITEARRAY WRITEUP + FOR secpolicy + TO USER pat; + +GRANT EXEMPTION ON RULE DB2LBACWRITEARRAY WRITEDOWN + FOR secpolicy + TO USER pat; + +-- Components of type ARRAY will have no effect when pat is writing. + +-- Pat tries the delete again. This time it executes without error because pat is able +-- to write to all of the rows she is able to read. The rows that she is unable to +-- read, however, are unaffected by the delete: + +CONNECT TO sample USER pat USING pat123; +DELETE FROM joe.employee_lbac WHERE EMPNO >= 1; + +-- After the statement, there is only one row in the table: +-- EMPNO LASTNAME DEPTNO PAYRANK ROWSECLABEL +-- 7 Addams 22 5 TOP SECRET:(ALPHA,DELTA):G4 + +-- If pat executes a select on the table, however, she will see no rows because she +-- is unable to read the row that is there. +SELECT empno, + lastname, + deptno, + payrank, CAST(SECLABEL_TO_CHAR('SECPOLICY', rowseclabel) AS VARCHAR(30)) + AS rowseclabel FROM joe.employee_lbac; + +-- No rows are returned. + +-- The user with SECADM authority revokes all exemptions from pat and +-- grants her security label seclabel1: +CONNECT TO sample USER secadm USING secadm123; + +REVOKE EXEMPTION ON RULE ALL FOR secpolicy FROM USER pat; +REVOKE SECURITY LABEL secpolicy.seclabel2 FROM USER pat; +GRANT SECURITY LABEL secpolicy.seclabel1 TO USER pat; + +-- turn off echo Current Command option to suppress printing of echo command +UPDATE COMMAND OPTIONS USING v OFF; + +!echo ---------------------------------------------------------------------; +!echo -- REVOKING SECURITY LABELS FROM USERS. ----; +!echo -- DROPPING SECURITY LABELS, SECURITY POLICY, PROTECTED TABLE ----; +!echo -- SECURITY LABEL COMPONENTS. ----; +!echo ---------------------------------------------------------------------; + +-- turn on the Echo Current Command option +UPDATE COMMAND OPTIONS USING v ON; + +-- Revoke the security labels from joe, bob and pat +REVOKE SECURITY LABEL secpolicy.seclabel1 FROM USER joe; +REVOKE SECURITY LABEL secpolicy.seclabel1 FROM USER bob; +REVOKE SECURITY LABEL secpolicy.seclabel1 FROM USER pat; + +-- Drop the protected table 'employee_lbac' + +CONNECT TO sample USER joe USING joe123; +DROP TABLE joe.employee_lbac; + +-- Drop the security labels created +CONNECT TO sample USER secadm USING secadm123; + +DROP SECURITY LABEL secpolicy.seclabel1; +DROP SECURITY LABEL secpolicy.seclabel2; +DROP SECURITY LABEL secpolicy.seclabel3; +DROP SECURITY LABEL secpolicy.seclabel4; + +-- Drop the security policy 'secpolicy' +DROP SECURITY POLICY secpolicy; + +-- Drop the security label components +DROP SECURITY LABEL COMPONENT level; +DROP SECURITY LABEL COMPONENT departments; +DROP SECURITY LABEL COMPONENT groups; + +-- Disconnect from the database +CONNECT RESET; diff --git a/admin_scripts/monitor.db2 b/admin_scripts/monitor.db2 new file mode 100644 index 0000000..0b27edc --- /dev/null +++ b/admin_scripts/monitor.db2 @@ -0,0 +1,100 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: monitor.db2 +-- +-- SAMPLE: The sample will demonstrate the usage of the table functions +-- MON_GET_CONNECTION, MON_GET_UTILITY and the views +-- SYSIBMADM.SNAPUTIL_PROGRESS and SYSIBMADM.MON_TBSP_UTILIZATION in +-- retrieving the monitor and snapshot data associated with the corresponding +-- snapshot groupings and elements as follows. +-- +-- 1. Retrieve the connection statistics about the top CPU consuming +-- applications for the currently connected database on the +-- currently connected member using the table functions +-- MON_GET_CONNECTION(). +-- +-- 2. Retrieve the statistics about the progress of all +-- the active utilities on all members using the table function +-- MON_GET_UTILITY and the view SYSIBMADM.SNAPUTIL_PROGRESS. +-- +-- 3. Retrieve the statistics about the total amount of +-- space used by all tablespaces in the currently connected +-- database using the view SYSIBMADM.MON_TBSP_UTILIZATION. +-- +-- SQL STATEMENTS USED: +-- CONNECT +-- SELECT +-- TERMINATE +-- +-- OUTPUT FILE: monitor.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to SAMPLE +CONNECT TO sample; + +-- List the top CPU consuming applications for the currently connected +-- database on the currently connected member +SELECT s1.APPLICATION_NAME, + s1.APPLICATION_ID, + s1.APPLICATION_HANDLE, + s1.SYSTEM_AUTH_ID, + s1.TOTAL_CPU_TIME + FROM TABLE( MON_GET_CONNECTION( NULL, -1 )) as s1 + ORDER BY s1.TOTAL_CPU_TIME DESC, s1.APPLICATION_NAME; + +-- Retrieving the statistics about the progress +-- of all active utilities per member. +SELECT u1.OBJECT_NAME, + u1.OBJECT_TYPE, + u1.OBJECT_SCHEMA, + u1.MEMBER, + u1.UTILITY_INVOCATION_ID, + u1.UTILITY_ID, + u1.UTILITY_PRIORITY, + u1.UTILITY_DETAIL, + u2.UTILITY_STATE, + u2.PROGRESS_WORK_METRIC, + u2.PROGRESS_COMPLETED_UNITS, + u2.PROGRESS_TOTAL_UNITS, + DEC( ( FLOAT( u2.PROGRESS_COMPLETED_UNITS ) / FLOAT( u2.PROGRESS_TOTAL_UNITS ) ) * 100, 4, 2 ) + AS PERCENT_SEQ_COMPLETE + FROM TABLE(MON_GET_UTILITY(-2)) as u1, SYSIBMADM.SNAPUTIL_PROGRESS as u2 + WHERE u1.UTILITY_ID = u2.UTILITY_ID and u1.MEMBER = u2.DBPARTITIONNUM + ORDER BY u1.OBJECT_NAME, u1.MEMBER, u2.PROGRESS_SEQ_NUM; + +-- Retrieving the statistics about total amount of space +-- used by all tablespaces per member in the currently connected member. +SELECT SUM( TBSP_TOTAL_SIZE_KB ) AS DBPART_TBSP_TOTAL_SIZE, + MEMBER FROM SYSIBMADM.MON_TBSP_UTILIZATION + GROUP BY MEMBER ORDER BY DBPART_TBSP_TOTAL_SIZE DESC; + +-- Connect reset +CONNECT RESET; diff --git a/admin_scripts/onlineload.db2 b/admin_scripts/onlineload.db2 new file mode 100644 index 0000000..3afb31b --- /dev/null +++ b/admin_scripts/onlineload.db2 @@ -0,0 +1,208 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: onlineload.db2 +-- +-- SAMPLE: How to do online loading using the ALLOW READ ACCESS option +-- for both partitioned and non-partitioned tables. +-- +-- Note: +-- This sample assumes that the configuration parameters +-- LOGRETAIN and USEREXIT are disabled. Otherwise the tablespace +-- enters into a 'backup pending' state after the load. +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- DELETE +-- DROP TABLE +-- EXPORT +-- INSERT +-- LOAD +-- +-- OUTPUT FILE: onlineload.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +--Use of LOAD utility on non-partitioned table + +-- Connect to sample database. +CONNECT TO sample; + +CREATE TABLE ed(ed INT); + +-- Insert data into the table and export that data in order to obtain File1 +-- and File2 in the required format for load. +INSERT INTO ed VALUES(1); +INSERT INTO ed VALUES(2); +INSERT INTO ed VALUES(3); + +EXPORT TO file1 OF DEL SELECT * FROM ed; + +DELETE FROM ed; + +INSERT INTO ed VALUES(4); +INSERT INTO ed VALUES(5); + +EXPORT TO file2 OF del SELECT * FROM ed; + +DELETE FROM ed; + +-- Now table ED is empty. +-- Load 3 rows +LOAD FROM file1 OF del MESSAGES loadmsg.txt INSERT INTO ed; + +-- Query the table +SELECT * FROM ed; + +-- Perform a load operation with the ALLOW READ ACCESS option specified +-- and load two more rows of data. +LOAD FROM file2 OF DEL MESSAGES loadmsg.txt INSERT INTO ed ALLOW READ ACCESS; + +-- At the same time, on another connection the table could be queried while +-- the load operation is in progress +-- SELECT * FROM ed +-- ED +-- ----------- +-- 1 +-- 2 +-- 3 + +-- Wait for the load operation to finish and then query the table +SELECT * FROM ed; +-- ED +-- ----------- +-- 1 +-- 2 +-- 3 +-- 4 +-- 5 + +-- In case eitherthe LOGRETAIN or USEREXIT parameter is not disabled, +-- the tablespace enters into a 'backup pending' state. To prevent this +-- the following two SQL statements must be uncommented. +-- BACKUP DB SAMPLE; +-- CONNECT TO SAMPLE; + +DROP TABLE ed; +COMMIT; + +-- The following two system commands delete the temporary files created for +-- load. +! rm file1; +! rm file2; + +-- uncomment the below line for deleting the file created to hold the +-- progress messages generated during load. +-- ! rm loadmsg.txt; +--End: Use of LOAD utility on non-partitioned table + ------------------------------------------------------------------------ +--Use of LOAD utility on partitioned table + +--Create tablespaces +CREATE TABLESPACE tbsp1 MANAGED BY SYSTEM USING('tbsp1'); +GRANT USE OF TABLESPACE tbsp1 TO PUBLIC; + +CREATE TABLESPACE tbsp2 MANAGED BY SYSTEM USING('tbsp2'); +GRANT USE OF TABLESPACE tbsp2 TO PUBLIC; + +CREATE TABLESPACE tbsp3 MANAGED BY SYSTEM USING('tbsp3'); +GRANT USE OF TABLESPACE tbsp3 TO PUBLIC; + +--Create a partition table +CREATE TABLE employee_details (emp_id INT NOT NULL PRIMARY KEY, + dept_name VARCHAR (10)) + IN tbsp1, tbsp2, tbsp3 + PARTITION BY RANGE (emp_id) + (STARTING 1 ENDING 100 EVERY 10); + +-- Create Exception table.(This table will hold the rows rejected by +-- the LOAD utility) +CREATE TABLE exception_tab AS (SELECT employee_details.*, + CURRENT TIMESTAMP AS TIMESTAMP, + cast ('' AS CLOB (32K)) + AS MSG FROM employee_details) + WITH NO DATA; + +--Create a non partition table +CREATE TABLE table_for_creating_datafile(emp_id INT, dept_name VARCHAR(10)); + +--Insert into the partition table, having rows such that EMP_ID has +-- duplicate values and some values exceeding the Range limits, and +-- export that data in order to obtain a file in the required format +-- for load. +INSERT INTO table_for_creating_datafile VALUES (1, 'D1'), + (2, 'D2'), + (10, 'D3'), + (10, 'D4'), + (100, 'D5'), + (110, 'D6'); + +--Create the file data_unique_range.del +EXPORT TO data_unique_range.del + OF DEL MESSAGES msg.txt + SELECT * FROM table_for_creating_datafile; + +--The load below demonstrates the usage of NOUNIQUEEXC +--and ALLOW NO READ ACCESS together. +LOAD FROM data_unique_range.del + OF DEL INSERT INTO employee_details + FOR EXCEPTION exception_tab + NOUNIQUEEXC NONRECOVERABLE ALLOW READ ACCESS; + +SELECT * FROM employee_details; + +-- Check rows inserted into the exception table. +SELECT emp_id,dept_name FROM exception_tab; + +LOAD FROM data_unique_range.del + OF DEL REPLACE INTO employee_details + FOR EXCEPTION exception_tab + NORANGEEXC NONRECOVERABLE ALLOW NO ACCESS; + +SELECT * FROM employee_details; + +-- Check rows inserted into the exception table. +SELECT emp_id,dept_name FROM exception_tab; + +DROP TABLE employee_details; +DROP TABLE exception_tab; +DROP TABLE table_for_creating_datafile; +DROP TABLESPACE tbsp1; +DROP TABLESPACE tbsp2; +DROP TABLESPACE tbsp3; +COMMIT; + +-- The following system command delete the temporary files created for +-- load. +! rm data_unique_range.del; + +-- uncomment the below line for deleting the file created to hold the +-- progress messages generated during load. +-- ! rm msg.txt; +--End: Use of LOAD utility on a partitioned table. diff --git a/admin_scripts/partitionindex.db2 b/admin_scripts/partitionindex.db2 new file mode 100644 index 0000000..ef1e1fe --- /dev/null +++ b/admin_scripts/partitionindex.db2 @@ -0,0 +1,110 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: partitionindex.db2 +-- +-- SAMPLE: How to create indexes on a partitioned table. +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- CREATE TABLESPACE +-- CREATE INDEX +-- TERMINATE +-- +-- OUTPUT FILE: partitionindex.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to database. +CONNECT TO sample; + +-- Create DMS tablespaces. +CREATE TABLESPACE tbsp1 MANAGED BY DATABASE USING (FILE 'conta' 10000); +CREATE TABLESPACE tbsp2 MANAGED BY DATABASE USING (FILE 'contb' 10000); +CREATE TABLESPACE tbsp3 MANAGED BY DATABASE USING (FILE 'contc' 10000); + +-- Create a partitioned table on a list of tablespaces. A table 'number1'with +-- four partitions will be created i.e. part0 is placed in tbsp1, part1 is +-- placed in tbsp2, part2 is placed in tbsp3, and part3 is placed in tbsp1. +-- The partitions will be placed in Round Robin fashion in tablespaces. +CREATE TABLE number1(num0 INT, + num1 INT) + PARTITION BY (num0) + (PART part1 STARTING FROM (1) ENDING AT (10000), + PART part2 STARTING FROM (10001) ENDING AT (20000), + PART part3 STARTING FROM (20001) ENDING AT (20010), + PART part4 STARTING FROM (20011) ENDING AT (20020)); + +-- Create index without IN clause. The default for indexes on partitioned +-- tables is NOT PARTITIONED. +-- Index should be placed in the tablespace of the first data partition. +CREATE INDEX idx1_tab1 ON number1(num0); + +-- Create index with IN clause. +-- Index will be placed in the mentioned tablespace. +-- This overrides the tablespace specified in CREATE TABLE statement +-- regardless of whether the base table's table space is DMS or SMS. +CREATE INDEX idx2_tab2 ON number1(num1) IN tbsp3; + +-- Drop the indexes. +DROP INDEX idx1_tab1; +DROP INDEX idx2_tab2; + +-- Create a partitioned table with the IN clause for the index creation. +-- A table 'number2' with four partitions will be created. i.e part0 is +-- placed in tbsp1, part1 is placed in tbsp2, part3 is placed in tbsp1, +-- part4 is placed in tbsp2. +CREATE TABLE number2(num1 INT NOT NULL PRIMARY KEY, + num2 INT) LONG IN tbsp1 CYCLE INDEX IN tbsp2 + PARTITION BY (num1) + (PART part1 STARTING FROM (1) ENDING AT (10000), + PART part2 STARTING FROM (10001) ENDING AT (20000), + PART part3 STARTING FROM (20001) ENDING AT (20010), + PART part4 STARTING FROM (20011) ENDING AT (20020)); + +-- Create index with IN clause. +-- Index should be placed in the tablespace specified. +CREATE INDEX idx1_tab2 ON number2(num2) IN tbsp3; + +-- Drop the index. +DROP INDEX idx1_tab2; + +-- Drop the partitioned tables. +DROP TABLE number1; +DROP TABLE number2; + +-- Drop the tablespaces. +DROP TABLESPACE tbsp1; +DROP TABLESPACE tbsp2; +DROP TABLESPACE tbsp3; + +-- Disconnect from database. +CONNECT RESET; + +TERMINATE; diff --git a/admin_scripts/public_alias.db2 b/admin_scripts/public_alias.db2 new file mode 100644 index 0000000..504d98a --- /dev/null +++ b/admin_scripts/public_alias.db2 @@ -0,0 +1,501 @@ +--/**************************************************************************** +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ****************************************************************************** +-- +-- SAMPLE FILE NAME: public_alias.db2 +-- +-- PURPOSE : The purpose of this sample is to demonstrate the use of +-- public aliases for database objects such as tables and modules. +-- This sample will demonstrate the following features: +-- +-- 1) Use of public aliases for tables +-- 2) Use of private aliases for modules +-- 3) Use of public aliases for modules +-- 4) Object resolution +-- +-- USAGE SCENARIO : An enterprise database contains number of objects such as +-- tables, views, modules and so on. Some objects are created by +-- database administrators in a specific schema which can be used by other DBAs +-- to perform certain operations. Some objects are created by users +-- in their schema. Users use the fully qualified object name +-- (.) to use any object outside their +-- schema. There are some objects which are frequently used +-- by the DBA or the user. It is preferable to create public aliases +-- for frequently used objects because those objects can be referenced independently +-- of the current SQL path or CURRENT SCHEMA by using by its simpler, +-- one-part name. +-- +-- +-- PREREQUISITE : The following users should exist in the operating system. +-- bob with password "bob12345" +-- pat with password "pat12345" +-- +-- EXECUTION : db2 -td@ -vf public_alias.db2 +-- +-- INPUT : NONE +-- +-- OUTPUT : Successful creation of public alias. +-- +-- DEPENDENCIES : NONE +-- +-- SQL STATEMENTS : +-- USED +-- ALTER MODULE PUBLISH PROCEDURE +-- ALTER MODULE ADD PROCEDURE +-- ALTER MODULE DROP PROCEDURE +-- CONNECT +-- CREATE MODULE +-- CREATE PUBLIC alias FOR TABLE +-- CREATE PUBLIC alias FOR MODULE +-- DROP MODULE +-- DROP PUBLIC alias FOR TABLE +-- DROP PUBLIC alias FOR MODULE +-- SELECT +-- ************************************************************************* +-- +-- SAMPLE DESCRIPTION +-- +-- A. Schema used in the sample +-- +-- 1) dba_object : Contains objects frequently used by DBAs. +-- +-- B. Tables used in the sample +-- +-- 1) SYSIBMADM.APPLICATIONS : Contains details of connected applications. +-- 2) SYSIBMADM.TBSP_UTILIZATION : Contains details of tablespaces. +-- +-- C. Aliases used in the sample +-- +-- 1) app : Public alias for the table SYSIBMADM.APPLICATIONS +-- 2) tbsp : Public alias for the table SYSIBMADM.TBSP_UTILIZATION +-- 3) dbms_monit : Public alias for the module database_monitoring +-- 4) db_monitoring : Private alias for the module database_monitoring +-- +-- D. The application processing is performed by the following routines: +-- +-- 1) database_monitoring : Contains various stored procedures. This module is +-- used by DBAs to monitor the database. +-- +-- a) tbsp_details : Procedure to monitor table spaces. +-- +-- b) app_details : Procedure to monitor connected applications. +-- +-- +-- SAMPLE DETAILS +-- +-- (1) Admin user creates PUBLIC alias "app", "tbsp" for table +-- SYSIBMADM.APPLICATIONS and SYSIBMADM.TBSP_UTILIZATION respectively. +-- +-- (2) Admin creates a module database_monitoring in dba_object schema so +-- that DBAs can use it. +-- +-- (3) Admin user creates public alias dbms_monit for module database_monitoring. +-- +-- (4) Admin user alters the module by adding procedures. +-- +-- (5) User bob and pat use the module database_monitoring for monitoring the database, +-- but they use dbms_monit alias for monitoring. +-- +-- (6) User pat creates one more module of same name dbms_monit in the schema "pat". +-- +-- (7) User pat calls the procedure in different ways. +-- +-- (8) User bob calls the procedure in different ways. +-- +-- ***************************************************/ +-- SET UP */ +-- ***************************************************/ + +-- Connect to Sample +CONNECT TO sample@ + +echo@ +echo ********************************@ +echo USE OF PUBLIC ALIASES FOR TABLE @ +echo ********************************@ +echo@ + +-- Create schema to store objects used by DBA +CREATE SCHEMA dba_object@ +SET CURRENT SCHEMA = dba_object@ +SET CURRENT PATH = CURRENT PATH, dba_object@ + +-- Create public alias for table SYSIBMADM.APPLICATIONS +CREATE PUBLIC ALIAS app FOR TABLE SYSIBMADM.APPLICATIONS@ + +-- Create public alias for table SYSIBMADM.TBSP_UTILIZATION +CREATE PUBLIC ALIAS tbsp FOR TABLE SYSIBMADM.TBSP_UTILIZATION@ + + +-- Create module database_monitoring +CREATE MODULE database_monitoring@ + +-- Grant execute privilege to user bob +GRANT EXECUTE ON MODULE database_monitoring TO USER bob@ + +-- Reset connection +CONNECT RESET@ + + +-- Connect to sample +CONNECT TO sample@ + +-- Alter module database_monitoring to publish procedure +-- tbsp_detail. Users will use full module name to alter +-- the module. +ALTER MODULE dba_object.database_monitoring PUBLISH +PROCEDURE tbsp_detail()@ + +-- Alter module database_monitoring to publish procedure +-- app_detail. Users will use full module name to alter +-- the module. +ALTER MODULE dba_object.database_monitoring PUBLISH +PROCEDURE app_detail()@ + + +-- Alter module database_monitoring to add procedure +-- tbsp_detail. Users will use full module name to alter +-- the module. +ALTER MODULE dba_object.database_monitoring ADD +PROCEDURE tbsp_detail() + BEGIN + -- Declare variables + DECLARE v_tbsp_id INTEGER; + DECLARE v_tbsp_name CHAR(15); + DECLARE v_tbsp_type CHAR(5); + DECLARE v_tbsp_content_type CHAR(10); + DECLARE v_tbsp_util_prcntg DECIMAL(5,2); + DECLARE v_dbpgname CHAR(20); + DECLARE c_tbsp_statistics CURSOR; + + SET c_tbsp_statistics = CURSOR FOR SELECT TBSP_ID, TBSP_NAME, + TBSP_TYPE, TBSP_CONTENT_TYPE, TBSP_UTILIZATION_PERCENT, + DBPGNAME + FROM tbsp; + + -- Open cursor c_tbsp_statistics + OPEN c_tbsp_statistics; + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('---------------------'); + CALL DBMS_OUTPUT.PUT_LINE('TABLESPACE STATISTICS'); + CALL DBMS_OUTPUT.PUT_LINE('---------------------'); + CALL DBMS_OUTPUT.NEW_LINE; + + CALL DBMS_OUTPUT.PUT ('TBSPACE ID'||' '|| 'TBSPACE NAME'||' '|| + 'TYPE'||' '||'CONTENT TYPE'||' '|| '% USED'||' '||'DBPAGENAME'); + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('----------'||' '||'------------'||' '|| + '----'||' '||'------------'||' '||'------'||' '||'----------'); + + fetch_loop: + LOOP + + -- Fetch values from cursor + FETCH FROM c_tbsp_statistics INTO + v_tbsp_id, v_tbsp_name, v_tbsp_type, v_tbsp_content_type, + v_tbsp_util_prcntg, v_dbpgname; + + + IF c_tbsp_statistics IS NOT FOUND + THEN LEAVE fetch_loop; + END IF; + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT(v_tbsp_id); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_tbsp_name); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_tbsp_type); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_tbsp_content_type); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_tbsp_util_prcntg); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_dbpgname); + CALL DBMS_OUTPUT.NEW_LINE; + END LOOP fetch_loop; + + -- Close cursor c_tbsp_statistics + CLOSE c_tbsp_statistics; +END@ + +echo @ +echo ********************************@ +echo USE OF PUBLIC ALIAS FOR MODULE @ +echo ********************************@ +echo @ + + +-- Now admin user creates public alias for object dba_object.database_monitoring +-- which can be accessed by all the users who have privilege to use this +-- object, without using the full object name. +CREATE PUBLIC ALIAS dbms_monit FOR MODULE dba_object.database_monitoring@ + +-- Reset connection +CONNECT RESET@ + + +echo @ +echo ********************************@ +echo USE OF PRIVATE ALIAS FOR MODULE @ +echo ********************************@ +echo @ + +-- User bob calls the procedure in different ways +CONNECT TO SAMPLE USER bob USING bob12345@ +SET SERVEROUTPUT ON@ + +-- Call module by using full object name +CALL dba_object.database_monitoring.tbsp_detail()@ + +-- Create private alias of object dba_object.database_monitoring +-- to avoid use of full object name +CREATE ALIAS db_monitoring FOR MODULE dba_object.database_monitoring@ + +-- Call module by using private alias +CALL db_monitoring.tbsp_detail()@ + +-- Call module by using public alias +CALL dbms_monit.tbsp_detail()@ + +-- Connect to sample +CONNECT TO sample@ + +-- Alter module database_monitoring to add procedure +-- app_detail. Users will use full module name to alter +-- the module. + +ALTER MODULE dba_object.database_monitoring ADD +PROCEDURE app_detail() + BEGIN + -- Declare variables + DECLARE v_agent_id INTEGER ; + DECLARE v_app_name CHAR(20); + DECLARE v_auth_id CHAR(15); + DECLARE v_app_id CHAR(26); + DECLARE v_app_status CHAR(15); + DECLARE c_app_detail CURSOR; + + SET c_app_detail = CURSOR FOR SELECT AGENT_ID, APPL_NAME, + AUTHID, APPL_ID, APPL_STATUS + FROM app + ORDER BY AGENT_ID ASC; + + -- Open cursor c_app_detail + OPEN c_app_detail; + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('------------------'); + CALL DBMS_OUTPUT.PUT_LINE('APPLICATION STATUS'); + CALL DBMS_OUTPUT.PUT_LINE('------------------'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT + ('AGENT ID '||' '|| 'APPLICATION NAME '||' '|| + 'AUTHORIZATION ID '||' '|| 'APPLICATION ID '||' '|| + 'STATUS'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('--------'||' '|| + '----------------'||' '||' -----------------'||' '|| + '-------------------------'||' '|| '-----------'); + + fetch_loop: + LOOP + + -- Fetch values from cursor + FETCH FROM c_app_detail INTO + v_agent_id, v_app_name, v_auth_id, v_app_id, + v_app_status; + + IF c_app_detail IS NOT FOUND + THEN LEAVE fetch_loop; + END IF; + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT(v_agent_id); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_app_name); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_auth_id); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_app_id); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_app_status); + CALL DBMS_OUTPUT.NEW_LINE; + + END LOOP fetch_loop; + + -- Close cursor c_app_detail + CLOSE c_app_detail; +END@ + +-- Reset connection +CONNECT RESET@ + +-- User bob calls the procedure in different ways +CONNECT TO SAMPLE USER bob using bob12345@ +SET SERVEROUTPUT ON@ + +-- Call procedure by using full object name +CALL dba_object.database_monitoring.app_detail()@ + +-- Call procedure by using private alias +CALL db_monitoring.app_detail()@ + +-- Call procedure by using public alias +CALL dbms_monit.app_detail()@ + +-- Reset connection +CONNECT RESET@ + +echo@ +echo ******************@ +echo OBJECT RESOLUTION @ +echo ******************@ +echo@ + +-- Connect to sample +CONNECT TO sample USER pat USING pat12345@ + +-- User pat creates one more module of same name in "pat" schema +CREATE MODULE dbms_monit@ + +-- Alter module dbms_monit to publish same procedure app_detail +ALTER MODULE dbms_monit PUBLISH +PROCEDURE app_detail()@ + +ALTER MODULE dbms_monit ADD +PROCEDURE app_detail() + BEGIN + -- Declare variables + DECLARE v_agent_id INTEGER ; + DECLARE v_app_name CHAR(20); + DECLARE v_app_status CHAR(15); + DECLARE c_app_detail CURSOR; + + SET c_app_detail = CURSOR FOR SELECT AGENT_ID, APPL_NAME, + APPL_STATUS + FROM app + ORDER BY AGENT_ID ASC; + + -- Open cursor c_app_detail + OPEN c_app_detail; + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('------------------'); + CALL DBMS_OUTPUT.PUT_LINE('APPLICATION STATUS'); + CALL DBMS_OUTPUT.PUT_LINE('------------------'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT + ('AGENT ID '||' '|| 'APPLICATION NAME '||' '|| 'STATUS'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('--------'||' '|| + '----------------'||' '|| '-----------'); + + fetch_loop: + LOOP + + -- Fetch values from cursor + FETCH FROM c_app_detail INTO + v_agent_id, v_app_name, v_app_status; + + IF c_app_detail IS NOT FOUND + THEN LEAVE fetch_loop; + END IF; + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT(v_agent_id); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_app_name); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(v_app_status); + CALL DBMS_OUTPUT.NEW_LINE; + + END LOOP fetch_loop; + + -- Close cursor c_app_detail + CLOSE c_app_detail; +END@ + + +-- User pat calls the procedure in different ways +SET SERVEROUTPUT ON@ + +-- Call procedure of schema pat +CALL dbms_monit.app_detail()@ + +echo "Above output is expected"@ +echo@ + +-- Reset connection +CONNECT RESET@ + +-- User bob drops procedure from module +CONNECT TO sample user bob using bob12345@ +SET SERVEROUTPUT ON@ + +-- Alter module by dropping procedure +ALTER MODULE pat.dbms_monit +DROP PROCEDURE app_detail@ + +echo "Above output is expected"@ +echo@ + +-- Call procedure +CALL dbms_monit.app_detail()@ + + -- User pat drops procedure from module +CONNECT TO sample USER pat USING pat12345@ +SET SERVEROUTPUT ON@ + +-- Alter module by dropping procedure +ALTER MODULE dbms_monit +DROP PROCEDURE app_detail@ + +-- Call procedure +CALL dbms_monit.app_detail()@ + +echo "Above output is expected"@ +echo@ + +-- Drop module dbms_monit +DROP MODULE dbms_monit@ + +-- Call procedure after dropping module +CALL dbms_monit.app_detail()@ + +echo "Above output is expected"@ +echo@ + +-- Reset connection +CONNECT RESET@ + +-- Drop modules and aliases +CONNECT TO sample@ + +DROP PUBLIC ALIAS app FOR TABLE@ +DROP PUBLIC ALIAS tbsp FOR TABLE @ +DROP ALIAS bob.db_monitoring FOR MODULE@ +DROP MODULE dba_object.database_monitoring@ +DROP PUBLIC ALIAS dbms_monit FOR MODULE@ +DROP SCHEMA dba_object RESTRICT@ + +CONNECT RESET@ diff --git a/admin_scripts/redistribute_cmd.db2 b/admin_scripts/redistribute_cmd.db2 new file mode 100644 index 0000000..f18f7b1 --- /dev/null +++ b/admin_scripts/redistribute_cmd.db2 @@ -0,0 +1,296 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: redistribute_cmd.db2 +-- +-- PURPOSE : To demonstrate how to redistribute the table data among +-- database partitions in a partitioned database environment +-- using REDISTRIBUTE DATABASE PARTITION GROUP command. +-- +-- USAGE SCENARIO : The customer database initially has two partitions (0, 1) +-- and a database partition group that is defined on (0, 1). +-- Due to business requirements the customer decides to add +-- a new partition to the existing database partition group +-- and redistribute the data in the database partition group. +-- As the system has a very small maintenance window, +-- redistribution of table data can be done gradually. +-- During redistribution, the customer wants to collect the +-- statistics, rebuild the indexes and limit the data buffer +-- to certain percentage of the utility heap. +-- +-- This sample demonstrates the operations described in the +-- above scenario. +-- +-- PREREQUISITE : Redistribute cannot work on single partition system. +-- This sample has to be run on multiple database partitions. +-- The partition numbers need to be 0, 1, 2 and 3. +-- +-- EXECUTION : db2 -tvf redistribute_cmd.db2 +-- +-- INPUTS : NONE +-- +-- OUTPUTS : Redistributes data into different database partitions. +-- +-- OUTPUT FILE : redistribute_cmd.out (available in the online documentation) +-- +-- DEPENDENCIES : NONE +-- +-- SQL STATEMENTS USED: +-- BACKUP DATABASE +-- CREATE DATABASE PARTITION GROUP +-- CREATE INDEX +-- CREATE TABLESPACE +-- CREATE TABLE +-- DROP TABLE +-- DROP TABLESPACE +-- DROP DATABASE PARTITION GROUP +-- INSERT +-- LIST DBPARTITIONNUMS +-- REDISTRIBUTE DATABASE PARTITION GROUP +-- TERMINATE +-- **************************************************************************** +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- **************************************************************************** +-- SAMPLE DESCRIPTION +-- **************************************************************************** +-- The sample demonstrates the use and behavior of the various command options +-- of the REDISTRIBUTE DATABASE PARTITION GROUP command including: +-- ADD, DROP, STOP AT, PARALLEL TABLE, FIRST | ONLY, STATISTICS USE PROFILE, +-- INDEXING MODE, DATA BUFFER MODE and COMPACT. + +-- *NOTE: Perform a full database backup before executing REDISTRIBUTE DATABASE +-- PARTITION GROUP command, since this utility is not forward recoverable. +-- If no back up is taken and there is a catastrophic failure during +-- REDISTRIBUTE DATABASE PARTITION GROUP command, then database containers may +-- be lost due to bad disk and there could be data loss. +-- **************************************************************************** +-- SETUP +-- **************************************************************************** +-- Connect to sample database. +CONNECT TO SAMPLE; + +-- **************************************************************************** + +-- Get the list of partitions. +-- The below statement results in a list of 3 database partitions. +LIST DBPARTITIONNUMS; + +-- Create database partition group 'dbpg_1' on database partition (0, 1). +CREATE DATABASE PARTITION GROUP dbpg_1 ON dbpartitionnum (0,1); + +-- Create table space 'tbsp1' in database partition group 'dbpg_1'. +CREATE TABLESPACE tbsp1 IN DATABASE PARTITION GROUP dbpg_1; + +-- Create table space 'tbsp2' in database partition group 'dbpg_1'. +CREATE TABLESPACE tbsp2 IN DATABASE PARTITION GROUP dbpg_1; + +-- Create table 'temp.tab_temp1' in tablespace 'tbsp1'. +CREATE TABLE temp.tab_temp1 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp1; + +-- Populate table 'temp.tab_temp1' with the following data. +INSERT INTO temp.tab_temp1 VALUES ('a', 'b', 'c', 'd', 'e', + 'f', 'g', 'h', 'i', 'j' ); + +-- Create index on 'temp.tab_temp1'; +CREATE INDEX tab_temp1_index ON temp.tab_temp1 (c3); + +-- Create table 'temp.tab_temp2' in tablespace 'tbsp1'. +CREATE TABLE temp.tab_temp2 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp1; + +-- Populate table 'temp.tab_temp2' with the following data. +INSERT INTO temp.tab_temp2 VALUES ('k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't' ); + +-- Create table 'temp.tab_temp3' in tablespace 'tbsp2'. +CREATE TABLE temp.tab_temp3 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp2; + +-- Populate table 'temp.tab_temp3' with the following data. +INSERT INTO temp.tab_temp3 VALUES ('u', 'v', 'w', 'x', 'y', + 'z', 'a', 'b', 'c', 'd' ); + +-- Create index on 'temp.tab_temp3'; +CREATE INDEX tab_temp3_index ON temp.tab_temp3 (c1); + +-- Create table 'temp.tab_temp4' in tablespace 'tbsp2'. +CREATE TABLE temp.tab_temp4 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp2; + +-- Populate table 'temp.tab_temp4' with the following data. +INSERT INTO temp.tab_temp4 VALUES ('a', 'b', 'c', 'd', 'e', + 'f', 'g', 'h', 'i', 'j' ); + +-- Create table 'temp.tab_temp5' in tablespace 'tbsp2'. +CREATE TABLE temp.tab_temp5 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp2; + +-- Populate table 'temp.tab_temp5' with the following data. +INSERT INTO temp.tab_temp5 VALUES ('k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't' ); + +-- Create index on 'temp.tab_temp5'; +CREATE INDEX tab_temp5_index ON temp.tab_temp5 (c8); + +-- Create table 'temp.tab_temp6' in tablespace 'tbsp1' +CREATE TABLE temp.tab_temp6 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp1; + +-- Populate table 'temp.tab_temp6 with the following data. +INSERT INTO temp.tab_temp6 VALUES ('u', 'v', 'w', 'x', 'y', + 'z', 'a', 'b', 'c', 'd' ); + +-- Take full database backup before executing the REDISTRIBUTE DATABASE +-- PARTITION GROUP command since REDISTRIBUTE DATABASE PARTITION GROUP +-- command is not forward recoverable. +CONNECT RESET; +BACKUP DATABASE sample; + +-- Connect to sample database. +CONNECT TO SAMPLE; + +-- The below command will add new database partition (2) to group 'dbpg_1' +-- and change the group definition from (0, 1) to (0, 1, 2) and +-- redistribute all the tables data into these partitions. +-- INDEXING MODE parameter specifies how indexes are maintained during +-- redistribute. REBUILD specifies that index pages will be clustered +-- together on the disk. Indexes do not need to be valid to use this +-- option and indexes will be rebuilt from scratch. +REDISTRIBUTE DATABASE PARTITION GROUP dbpg_1 NOT ROLLFORWARD RECOVERABLE UNIFORM + ADD dbpartitionnum(2) + INDEXING MODE REBUILD; + +-- The below command will add partition 3. This will redistribute +-- tables 'temp.tab_temp6' and 'temp.tab_temp5' only with 5000 4K utility heap pages per +-- table. + +-- The command below throws the following waring: +-- SQL1379W Database partition group "DBPG_1" has been partially redistributed. +-- The number of tables redistributed is "2", and the number of tables yet to be +-- redistributed is "4". Reason code = "1". + +REDISTRIBUTE DATABASE PARTITION GROUP dbpg_1 NOT ROLLFORWARD RECOVERABLE UNIFORM + ADD dbpartitionnums (3) + TABLE (temp.tab_temp6, temp.tab_temp5) ONLY + DATA BUFFER 5000; +!echo "Above warning is expected !"; + +-- Tables 'temp.tab_temp6' and 'temp.tab_temp5' are redistributed now. +-- Tables 'temp.tab_temp1', 'temp.tab_temp2', 'temp.tab_temp3' and 'temp.tab_temp4' are not +-- yet redistributed. The following command will first redistribute data on +-- table 'temp.tab_temp1' and later redistributes the data on other tables in +-- 'dbpg_1' in a arbitrary order. +REDISTRIBUTE DATABASE PARTITION GROUP dbpg_1 NOT ROLLFORWARD RECOVERABLE CONTINUE + TABLE (temp.tab_temp1) FIRST; + +-- Get the time statistic for table 'temp.tab_temp1'. +SELECT stats_time FROM SYSIBM.SYSTABLES WHERE name = 'TAB_TEMP1' + ORDER BY NAME; + +-- Perform RUNSTATS to make a profile and collect statistics at the same time. +RUNSTATS ON TABLE temp.tab_temp1 WITH DISTRIBUTION DEFAULT NUM_FREQVALUES 50 + AND SAMPLED DETAILED INDEXES ALL SET PROFILE; + +-- Collect statistics for tables with statistic profile. +REDISTRIBUTE DATABASE PARTITION GROUP dbpg_1 NOT ROLLFORWARD RECOVERABLE UNIFORM + DROP dbpartitionnums (3) STATISTICS USE PROFILE; + +-- Get the time statistic for table 'temp.tab_temp1' after redistributing the data. +SELECT stats_time FROM SYSIBM.SYSTABLES WHERE name = 'TAB_TEMP1' + ORDER BY NAME; + +-- Redistribute will not only move records to their target partitions, +-- but also uses the staying records from the logical end of the table to +-- fill up holes. On completion of this command, tables data will be +-- redistributed in partitions (0, 1) only. +-- Partition 2 will be dropped from the database group 'dbpg_1'. +REDISTRIBUTE DATABASE PARTITION GROUP dbpg_1 NOT ROLLFORWARD RECOVERABLE UNIFORM + DROP dbpartitionnums (2); + +-- The below command will redistribute the tables' data into all remaining +-- partitions (0 and 1) and into partitions (2 and 3) uniformly. +-- The STOP AT option will stop data redistribution at the time specified +-- in the command. + +-- The command below throws the following warning: +-- SQL1379W Database partition group "DBPG_1" has been partially redistributed. +-- The number of tables redistributed is "0", and the number of tables yet to be +-- redistributed is "6". Reason code = "2". +REDISTRIBUTE DATABASE PARTITION GROUP dbpg_1 NOT ROLLFORWARD RECOVERABLE UNIFORM + ADD dbpartitionnums (2, 3) + STOP AT 2007-04-02-04.00.00.000000; + +!echo "Above warning is expected !"; + +-- The below command will abort redistribution of data on database partition +-- group level and undo tables 'temp.tab_temp1', 'temp.tab_temp2', 'temp.tab_temp3', +-- 'temp.tab_temp4' and 'temp.tab_temp5'. Once this is done, all the tables will be back +-- to their original state i.e. all tables data will be distributed only in +-- partition number (0 and 1). +-- The ABORT option in the following REDISTRIBUTE DATABASE PARTITION GROUP +-- command is only appropriate if the STOP AT option in the previous +-- REDISTRIBUTE DATABASE PARTITION GROUP command caused the utility to +-- terminate before it had fully redistributed the entire database partition +-- group. +REDISTRIBUTE DATABASE PARTITION GROUP dbpg_1 NOT ROLLFORWARD RECOVERABLE ABORT; + +-- Drop tables. +DROP TABLE temp.tab_temp1; +DROP TABLE temp.tab_temp2; +DROP TABLE temp.tab_temp3; +DROP TABLE temp.tab_temp4; +DROP TABLE temp.tab_temp5; +DROP TABLE temp.tab_temp6; + +-- Drop table spaces. +DROP TABLESPACE tbsp1; +DROP TABLESPACE tbsp2; + +-- Drop database partition group. +DROP DATABASE PARTITION GROUP dbpg_1; + +-- Disconnect from the sample database. +CONNECT RESET; +TERMINATE; diff --git a/admin_scripts/rollindata.db2 b/admin_scripts/rollindata.db2 new file mode 100644 index 0000000..e44b939 --- /dev/null +++ b/admin_scripts/rollindata.db2 @@ -0,0 +1,160 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: rollindata.db2 +-- +-- SAMPLE: How to perform data-roll-in into a partitioned table. +-- +-- SQL STATEMENTS USED: +-- ALTER TABLE +-- CREATE TABLE +-- CREATE TABLESPACE +-- DROP TABLE +-- EXPORT +-- IMPORT +-- INSERT +-- LOAD +-- SET INTEGRITY +-- TERMINATE +-- +-- OUTPUT FILE: rollindata.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to database. +CONNECT TO sample; + +-- Create DMS tablespaces. +CREATE TABLESPACE tbsp1 MANAGED BY DATABASE USING (FILE 'conta' 1000); +CREATE TABLESPACE tbsp2 MANAGED BY DATABASE USING (FILE 'contb' 1000); +CREATE TABLESPACE tbsp3 MANAGED BY DATABASE USING (FILE 'contc' 1000); + +-- Create a partitioned table on a list of tablespaces. A table 'emp_table' +-- with three partitions will be created. i.e part0 will be placed in tbsp1, +-- part1 will be placed in tbps2, and part2 will be placed in tbsp3. +CREATE TABLE emp_table (emp_no INTEGER, emp_name VARCHAR(10)) + IN tbsp1, tbsp2, tbsp3 + PARTITION BY RANGE (emp_no) + (STARTING FROM (1) ENDING (10), + STARTING FROM (11) ENDING (20), + STARTING FROM (21) ENDING (30)); + +-- Create a temporary table. +CREATE TABLE temp_table(emp_no INTEGER, emp_name VARCHAR(10)) + IN tbsp1, tbsp2, tbsp3 + PARTITION BY RANGE (emp_no) + (STARTING FROM (1) ENDING (10), + STARTING FROM (11) ENDING (20), + STARTING FROM (21) ENDING (30)); + +-- Insert data into the table and export the data in order to obtain +-- dummy.del file in the required format for load. + +INSERT INTO temp_table VALUES(1, 'John'), (11, 'Sam'), (21, 'Bill'); +EXPORT TO dummy.del OF DEL SELECT * FROM temp_table; +LOAD FROM dummy.del OF DEL INSERT INTO emp_table; + +-- Display the contents of 'emp_table' table. +SELECT * FROM emp_table; + +-- The following scenario shows addition of a new partition to the base table +-- through ALTER statement along with ATTACH PARTITION clause to it. + +-- Create a temporary table 'attach_part4' This table will be attached to the +-- base table. +CREATE TABLE attach_part4(emp_no INTEGER, emp_name VARCHAR(10)) IN tbsp1; + +-- Insert data into 'attach_part4'. +INSERT INTO attach_part4 VALUES(32, 'Chan'); + +-- Attach a partition to base table 'emp_table'. ALTER TABLE along with ATTACH +-- clause is used to add a new partition to the existing base table. +ALTER TABLE emp_table ATTACH PARTITION part3 STARTING FROM (31) ENDING (40) + FROM attach_part4; + +-- Create a temporary table 'emp_exception'. This table will be used hold the +-- exceptions returned by SET INTEGRITY statement. +CREATE TABLE emp_exception(emp_no INTEGER, emp_name VARCHAR(10)); + +-- The data in the ATTACHed partition is not yet visible, as it has not yet +-- been validated by set integrity. +-- The previous ALTER statement puts the table 'emp_table' into check pending +-- state. +-- Before performing SELECT statement on 'emp_table' table, it need to be +-- brought out of check pending state. +-- SET INTEGRITY statement brings the table out of check +-- pending state and makes the table available. +SET INTEGRITY FOR emp_table IMMEDIATE CHECKED + FOR EXCEPTION IN emp_table USE emp_exception; + +-- Display the contents of 'emp_table' table. +-- The rows added by the new partition are also displayed. +SELECT * FROM emp_table; +DROP TABLE emp_exception; + +-- The following scenario shows addition of partition to the base table +-- through ALTER statement along with ADD PARTITION clause to it. + +-- Create a temporary table 'attach_part3'. This table will be added to +-- the base table. +CREATE TABLE attach_part3 (emp_no INTEGER, emp_name VARCHAR(10)) IN tbsp1; + +-- Insert data into 'attach_part3'. +INSERT INTO attach_part3 VALUES(36, 'Steve'); + +-- Add partition to the base table. +-- Similar to ALTER STATEMENT with ATTACH clause, ADD partition clause can +-- also be used with ALTER TABLE statement to add a new partition to the +-- existing base table. +ALTER TABLE emp_table ADD PARTITION part4 STARTING FROM (41) ENDING (50); + +-- Export the data in order to obtain dummy.del file in the required format +-- for load. + +EXPORT TO dummy.del OF DEL SELECT * FROM attach_part3; +LOAD FROM dummy.del OF DEL INSERT INTO emp_table; + +-- Display the contents of 'emp_table' table. +SELECT * FROM emp_table; + +-- Drop the tables. +DROP TABLE temp_table; +DROP TABLE emp_table; + +! rm dummy.del; + +-- Drop the tablespaces. +DROP TABLESPACE tbsp1; +DROP TABLESPACE tbsp2; +DROP TABLESPACE tbsp3; + +-- Disconnect from database. +CONNECT RESET; + +TERMINATE; diff --git a/admin_scripts/rolloutdata.db2 b/admin_scripts/rolloutdata.db2 new file mode 100644 index 0000000..3081d93 --- /dev/null +++ b/admin_scripts/rolloutdata.db2 @@ -0,0 +1,178 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: rolloutdata.db2 +-- +-- SAMPLE: How to perform data-roll-out from a partitioned table. +-- +-- SQL STATEMENTS USED: +-- ALTER TABLE +-- CREATE TABLE +-- CREATE TABLESPACE +-- DROP TABLE +-- INSERT +-- TERMINATE +-- +-- OUTPUT FILE: rolloutdata.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to database. +CONNECT TO sample@ + +-- Create DMS tablespaces. +CREATE TABLESPACE tbsp1 MANAGED BY DATABASE USING (FILE 'conta' 1000)@ +CREATE TABLESPACE tbsp2 MANAGED BY DATABASE USING (FILE 'contb' 1000)@ + +-- Create a partitioned table on a list of tablespaces. A table 'emp_table' +-- with three partitions will be created i.e. part0 is placed in tbsp1, +-- part1 is placed in tbsp2, and part2 is placed in tbsp1. Data partitions +-- are placed in tablespaces in Round Robin fashion. + +CREATE TABLE emp_table (emp_no INTEGER NOT NULL, + emp_name VARCHAR(10), + dept VARCHAR(5), + salary DOUBLE DEFAULT 3.14) + IN tbsp1, tbsp2 + PARTITION BY RANGE (emp_no) + (STARTING FROM (1) ENDING (100), + STARTING FROM (101) ENDING (200), + STARTING FROM (201) ENDING (300))@ + +-- Insert data into 'emp_table'. +INSERT INTO emp_table VALUES + (1, 'Sam', 'E31', 3.34), + (101, 'James','E32', 4.00), + (201, 'Bill', 'E33', 3.75)@ + +-- Detach a partition from 'emp_table'. +-- ALTER TABLE statement along with DETACH PARTITION clause is used to +-- remove a partition from the base table. +create procedure tableExists (IN schemaName varchar(128), IN tableName varchar(128), OUT notFound int) + specific tableExists + language SQL +BEGIN + + declare dpid int; + + declare tabCheck cursor for + select DATAPARTITIONID from sysibm.sysdatapartitions where tabschema = schemaName and tabname = tableName; + declare exit handler for NOT FOUND + set notFound = 1; + + open tabCheck; + fetch tabCheck into dpid; + close tabCheck; + +END@ + +create procedure waitForDetach (OUT msg varchar(128), IN schemaName varchar(128), IN tableName varchar(128), IN partName varchar(128) DEFAULT NULL) + specific waitForDetach + language SQL +BEGIN + + declare dpid int; + declare dpstate char; + declare done int default 0; + declare tabNotFound int default 0; + + declare allDetachCheck cursor for + select DATAPARTITIONID, STATUS from sysibm.sysdatapartitions + where tabschema = schemaName and tabname = tableName and (status = 'L' OR status = 'D'); + + declare oneDetachCheck cursor for + select DATAPARTITIONID, STATUS from sysibm.sysdatapartitions + where tabschema = schemaName and tabname = tableName and datapartitionname = partName; + + declare continue handler for NOT FOUND + set done = 1; + + set current lock timeout 120; + + -- if table does not exist in sysdatapartitions, return error + call tableExists (schemaName, tableName, tabNotFound); + if tabNotFound = 1 + THEN + set msg = 'Table not found'; + RETURN -1; + END IF; + +wait_loop: + LOOP + if partName IS NOT NULL + THEN + open oneDetachCheck; + fetch oneDetachCheck into dpid, dpstate; + + -- two cases here: + -- (i) detach has already completed hence partition entry not found in catalogs (indicated by done == 1, handled later) + -- (ii) detach in progress, partition state should not be visible + IF done <> 1 AND (dpstate = '' OR dpstate = 'A') + THEN + set msg = 'Cannot waitForDetach if DETACH was not issued on this partition'; + return -1; + END IF; + + close oneDetachCheck; + ELSE + open allDetachCheck; + fetch allDetachCheck into dpid, dpstate; + close allDetachCheck; + END IF; + if done = 1 + THEN + set msg = 'DETACH completed'; + LEAVE wait_loop; + ELSE + ITERATE wait_loop; + END IF; + END LOOP; + +END@ + +ALTER TABLE emp_table DETACH PARTITION part1 INTO emp_part0@ +CALL waitForDetach(?, CURRENT SCHEMA, 'EMP_TABLE')@ + +-- Display the contents of each table. +SELECT emp_no, emp_name, dept, salary FROM emp_part0@ +SELECT emp_no, emp_name, dept, salary FROM emp_table@ + +-- Drop the tables. +DROP TABLE emp_part0@ +DROP TABLE emp_table@ + +-- Drop the tablespaces. +DROP TABLESPACE tbsp1@ +DROP TABLESPACE tbsp2@ + +-- Disconnect from database. +CONNECT RESET@ + +TERMINATE@ + diff --git a/admin_scripts/sec_rcac.db2 b/admin_scripts/sec_rcac.db2 new file mode 100644 index 0000000..27ba0bf --- /dev/null +++ b/admin_scripts/sec_rcac.db2 @@ -0,0 +1,783 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2011 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: rcac.db2 +-- +-- SAMPLE: How to take advantage of DB2 RCAC (Row and Column Access Control) +-- feature +-- +-- Scenario: A healthcare organization which has patient healthcare information +-- and different users with different roles. Few users maintain the database and +-- others access the organizations applications according to theie roles. To comply +-- with HIPPA(Health Insurance portability and accountability act.) the users should +-- have access to those data that they are authorised to view. The following sample +-- demonstrates the how the security policy is implemented using DB2 RCAC. + +-- PREREQUISITES FOR RUNNING THE SAMPLE: +-- The sample assumes the existance of the following users along with +-- the specified passwords +-- alex with password "test1234" SECADM role +-- peter with password "test1234" DBADM role +-- paul with password "test1234" DEVELOPER role +-- lee with password "test1234" PHYSICIAN role +-- bob with password "test1234" PATIENT role +-- tom with password "test1234" MEMBERSHIP role +-- john with password "test1234" ACCOUNTATNT role +-- jane with password "test1234" DRUG RESEARCHER role +-- +-- DB Admins +-- alex SECADM who can create RCAC objects. +-- peter DBADM who can create database objects. +-- paul Developer who develops is database application logic. +-- +-- DB Users +-- lee Physician who should view only his patients information. +-- bob Patient can view only his medical information +-- tom Enrols all patients to the hospital, can view +-- all patient information. +-- john Accountant who should view all patients information +-- and their account details. +-- jane Drug Researcher who should view only medical information +-- of those patients who have opted to give for reasearch. +-- +-- Make sure that the above users are created in windows machine. +-- +-- SQL STATEMENTS USED: +-- CONNECT +-- CREATE TABLE +-- CREATE ROLE +-- CREATE ROW PERMISSION +-- CREATE MASK +-- CREATE VIEW +-- CREATE FUNCTION +-- ALTER +-- GRANT +-- GRANT CREATE_SECURE_OBJECT +-- REVOKE +-- INSERT +-- UPDATE +-- SELECT +-- +-- OUTPUT FILE: rcac.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Disconnect from any existing database connection.; + +CONNECT RESET@ + +-- turn off echo Current Command option to suppress printing of echo command; + +UPDATE COMMAND OPTIONS USING v OFF@ +!echo ---------------------------------------------------------------------@ +!echo --Connect as System administrator and make peter the SECADM and DBADM--@ +!echo ---------------------------------------------------------------------@ +UPDATE COMMAND OPTIONS USING v ON@ + +CONNECT TO sample@ + + +---------------------------------------------------------------------; +-- peter initially is the DBADM and SECADM and creates the tables--; +-- and GRANTS roles.--; +---------------------------------------------------------------------; + + +GRANT SECADM,DBADM ON DATABASE TO USER peter@ + + +---------------------------------------------------------------------; +-- connect to sample as peter the SECADM and DBADM ---; +---------------------------------------------------------------------; + + +CONNECT TO sample USER peter USING test1234@ + + +-- Patient table stores information regarding patients-- ; + + +CREATE TABLE ADMINISTRATOR.PATIENT ( + SSN CHAR(11), + USERID VARCHAR(18), + NAME VARCHAR(128), + ADDRESS VARCHAR(128), + PHARMACY VARCHAR(5000), + ACCT_BALANCE DECIMAL(12,2) WITH DEFAULT, + PCP_ID VARCHAR(18) + )@ + + +---------------------------------------------------------------------; +-- Patientchoice table which stores what patient opts ; +-- to expose regarding his health information.; +-- 'opt-in' a patient willing to expose his medical information; +-- 'opt-out' a patient not willing to expose his medical information; +---------------------------------------------------------------------; + + +CREATE TABLE ADMINISTRATOR.PATIENTCHOICE ( + SSN CHAR(11), + CHOICE VARCHAR(128), + VALUE VARCHAR(128) + +)@ + + +-- History table to track account balance before and after update to ; +-- patient table.; + + +CREATE TABLE ADMINISTRATOR.ACCT_HISTORY( + SSN CHAR(11), + BEFORE_BALANCE DECIMAL(12,2), + AFTER_BALANCE DECIMAL(12,2), + WHEN DATE, + BY_WHO VARCHAR(20) +)@ + + +-- Inserting sample patient data.; + + +INSERT INTO ADMINISTRATOR.PATIENT VALUES('123-55-1234', 'MAX', 'Max', 'First Strt', 'hypertension', 89.70,'LEE')@ +INSERT INTO ADMINISTRATOR.PATIENTCHOICE VALUES('123-55-1234', 'drug-research', 'opt-out')@ + + +INSERT INTO ADMINISTRATOR.PATIENT VALUES('123-58-9812', 'MIKE', 'Mike', 'Long Strt', 'diabetics', 8.30,'james')@ +INSERT INTO ADMINISTRATOR.PATIENTCHOICE VALUES('123-58-9812', 'drug-research', 'opt-out')@ + + +INSERT INTO ADMINISTRATOR.PATIENT VALUES('123-11-9856', 'SAM', 'Sam', 'Big Strt', 'High blood pressure', 0.00,'LEE')@ +INSERT INTO ADMINISTRATOR.PATIENTCHOICE VALUES('123-11-9856', 'drug-research', 'opt-in')@ + +INSERT INTO ADMINISTRATOR.PATIENT VALUES('123-19-1454', 'DUG', 'Dug', 'Good Strt', 'Influenza', 0.00,'james')@ +INSERT INTO ADMINISTRATOR.PATIENTCHOICE VALUES('123-19-1454', 'drug-research', 'opt-in')@ + + +-- Creating roles and granting authority; + + + +CREATE ROLE PCP@ +GRANT SELECT ON ADMINISTRATOR.PATIENT TO ROLE PCP@ +GRANT UPDATE ON ADMINISTRATOR.PATIENT TO ROLE PCP@ + + +CREATE ROLE DRUG_RESEARCH@ +GRANT SELECT ON ADMINISTRATOR.PATIENT TO ROLE DRUG_RESEARCH@ + + +CREATE ROLE ACCOUNTING@ +GRANT SELECT ON ADMINISTRATOR.PATIENT TO ROLE ACCOUNTING@ +GRANT UPDATE ON ADMINISTRATOR.PATIENT TO ROLE ACCOUNTING@ +GRANT SELECT ON ADMINISTRATOR.ACCT_HISTORY TO ROLE ACCOUNTING@ + + +CREATE ROLE MEMBERSHIP@ +GRANT SELECT ON ADMINISTRATOR.PATIENT TO ROLE MEMBERSHIP@ +GRANT INSERT ON ADMINISTRATOR.PATIENT TO ROLE MEMBERSHIP@ +GRANT INSERT ON ADMINISTRATOR.PATIENTCHOICE TO ROLE MEMBERSHIP@ +GRANT UPDATE ON ADMINISTRATOR.PATIENT TO ROLE MEMBERSHIP@ + + +CREATE ROLE PATIENT@ +GRANT SELECT ON ADMINISTRATOR.PATIENT TO ROLE PATIENT@ + + +-- Grant roles and privileges to Users; + + +GRANT SELECT ON ADMINISTRATOR.PATIENT TO USER alex@ +GRANT ALTER ON ADMINISTRATOR.PATIENT TO USER alex@ +GRANT ALTER ON ADMINISTRATOR.PATIENT TO USER paul@ +GRANT INSERT ON ADMINISTRATOR.ACCT_HISTORY TO USER paul@ +GRANT SELECT ON ADMINISTRATOR.PATIENT TO USER paul@ + +GRANT INSERT ON ADMINISTRATOR.ACCT_HISTORY TO USER paul@ +GRANT SELECT ON ADMINISTRATOR.PATIENT TO USER paul@ + + +GRANT ROLE PCP TO USER lee@ +GRANT ROLE DRUG_RESEARCH TO USER jane@ +GRANT ROLE ACCOUNTING TO USER john@ +GRANT ROLE MEMBERSHIP TO USER tom@ +GRANT ROLE PATIENT TO USER bob@ + +GRANT SECADM ON DATABASE TO USER alex@ + + +-- Connect as alex; + + +CONNECT TO sample USER alex USING test1234@ + + +-- Removing SECADM authority of peter hence; +-- alex is the only SECADM in the database; + + +REVOKE SECADM ON DATABASE FROM USER peter@ + + +-- turn off echo Current Command option to suppress printing of echo command +UPDATE COMMAND OPTIONS USING v OFF@ +!echo -----------------------------------------------------------------------------------------@ +!echo -- Creating row permission based on user role and the rows which they should have access.@ +!echo ------------------------------------------------------------------------------------------@ +UPDATE COMMAND OPTIONS USING v ON@ + +-- Accounting information; +-- ROLE PATIENT is allowed to access his or her own row; +-- ROLE PCP is allowed to access his or her patients rows; +-- ROLE MEMBERSHIP, ACCOUNTING, and DRUG_RESEARCH are; +-- allowed to access all rows.; + + +CREATE PERMISSION ADMINISTRATOR.ROW_ACCESS ON ADMINISTRATOR.PATIENT +FOR ROWS WHERE (VERIFY_ROLE_FOR_USER(SESSION_USER,'PATIENT') = 1 +AND +ADMINISTRATOR.PATIENT.USERID = SESSION_USER) OR +(VERIFY_ROLE_FOR_USER(SESSION_USER,'PCP') = 1 +AND +ADMINISTRATOR.PATIENT.PCP_ID = SESSION_USER) OR + (VERIFY_ROLE_FOR_USER(SESSION_USER,'MEMBERSHIP') = 1 OR + VERIFY_ROLE_FOR_USER(SESSION_USER,'ACCOUNTING') = 1 OR + VERIFY_ROLE_FOR_USER(SESSION_USER, 'DRUG_RESEARCH') = 1) +ENFORCED FOR ALL ACCESS +ENABLE@ + + +--Altering the table to activate the row access control feature.; + + +ALTER TABLE ADMINISTRATOR.PATIENT ACTIVATE ROW ACCESS CONTROL@ + + +-- Connect as tom the membership officer; + + +CONNECT TO sample USER tom USING test1234@ + + +-- Inserting patient Bobs information; + + +INSERT INTO ADMINISTRATOR.PATIENT VALUES('123-45-6789', 'BOB', 'Bob', '123 Some St.', 'hypertension', 9.00,'LEE')@ +INSERT INTO ADMINISTRATOR.PATIENTCHOICE VALUES('123-45-6789', 'drug-research', 'opt-in')@ + + +-- Querying all the patient information; + + +SELECT SESSION_USER AS "LOGGED_USER",SSN, USERID, NAME, ADDRESS, PHARMACY, ACCT_BALANCE, PCP_ID +FROM ADMINISTRATOR.PATIENT @ + + +-- Connect as lee; + + +CONNECT TO sample USER lee USING test1234@ + + +-- Dr.Lee updating patient Sam information (updates as Sam is Dr. Lee patient); + + +UPDATE ADMINISTRATOR.PATIENT SET PHARMACY = 'codeine' WHERE NAME = 'Bob'@ + + +-- Dr.Lee updating patient Dug information (will not get updated as Dug is not Dr.Lee patient); +-- Throws a warning saying as no record found for update.; + + +UPDATE ADMINISTRATOR.PATIENT SET PHARMACY = 'codeine' WHERE NAME = 'Dug'@ + + +-- Query the patient table as Dr.Lee; + + +SELECT +SESSION_USER AS "LOGGED_USER",SSN, USERID, NAME, ADDRESS, PHARMACY, ACCT_BALANCE, PCP_ID +FROM ADMINISTRATOR.PATIENT@ + + +-- Connect as Bob; + + +CONNECT TO sample USER bob USING test1234@ + + +-- Query the patient table as patient bob; + + +SELECT +SESSION_USER AS "LOGGED_USER",SSN, USERID, NAME, ADDRESS, PHARMACY, ACCT_BALANCE, PCP_ID +FROM ADMINISTRATOR.PATIENT@ + + + +-- Connect as Alex + +CONNECT TO sample USER alex USING test1234@ + +-- turn off echo Current Command option to suppress printing of echo command +UPDATE COMMAND OPTIONS USING v OFF@ +!echo -----------------------------------------------------------------------------------------@ +!echo -- Creating column mask based on user role and the columns which they have access@ +!echo ------------------------------------------------------------------------------------------@ +UPDATE COMMAND OPTIONS USING v ON@ + +-----------------------------------------------------------------; +-- Creating a Column MASK ON ACCT_BALANCE column on PATIENT TABLE; +-- Accounting information:; +-- Role ACCOUNTING is allowed to access the full information; +-- on column ACCT_BALANCE.; +-- Other roles accessing this column will strictly view a; +-- zero value.; +-----------------------------------------------------------------; + + +CREATE MASK ADMINISTRATOR.ACCT_BALANCE_MASK ON ADMINISTRATOR.PATIENT FOR +COLUMN ACCT_BALANCE RETURN + CASE WHEN VERIFY_ROLE_FOR_USER(SESSION_USER,'ACCOUNTING') = 1 + THEN ACCT_BALANCE + ELSE 0.00 + END +ENABLE@ + + +-----------------------------------------------------------------; +-- Mask on Column SSN. ; +-- Roles PATIENT, PCP, MEMBERSHIP, and ACCOUNTING are allowed; +-- to access the full information on columns SSN, USERID, NAME,; +-- and ADDRESS. Other roles accessing these columns will; +-- strictly view a masked value.; +-----------------------------------------------------------------; + + +CREATE MASK ADMINISTRATOR.SSN_MASK ON ADMINISTRATOR.PATIENT FOR +COLUMN SSN RETURN + CASE WHEN + VERIFY_ROLE_FOR_USER(SESSION_USER,'PATIENT') = 1 OR + VERIFY_ROLE_FOR_USER(SESSION_USER,'PCP') = 1 OR + VERIFY_ROLE_FOR_USER(SESSION_USER,'MEMBERSHIP') = 1 OR + VERIFY_ROLE_FOR_USER(SESSION_USER,'ACCOUNTING') = 1 + THEN SSN + ELSE CHAR('XXX-XX-' || SUBSTR(SSN,8,4)) + END +ENABLE@ + + +-----------------------------------------------------------------; +-- Mask on Column Pharmacy. ; +-- Role PCP is allowed to access the full information on; +-- column PHARMACY.; +-- For the purposes of drug research, Role DRUG_RESEARCH can; +-- conditionally see a patients medical information; +-- provided that the patient has opted-in.; +-- In all other cases, 'XXXXXXXXXXX' values are rendered as column; +-- values.; +-----------------------------------------------------------------; + + +CREATE MASK ADMINISTRATOR.PHARMACY_MASK ON ADMINISTRATOR.PATIENT FOR +COLUMN PHARMACY RETURN + CASE WHEN + VERIFY_ROLE_FOR_USER(SESSION_USER,'PCP') = 1 OR + (VERIFY_ROLE_FOR_USER(SESSION_USER,'DRUG_RESEARCH')=1 + AND + SSN IN (SELECT C.SSN FROM ADMINISTRATOR.PATIENTCHOICE C + WHERE SSN = C.SSN AND C.CHOICE = 'drug-research' AND C.VALUE = 'opt-in')) + THEN PHARMACY + ELSE 'XXXXXXXXXXX' +END +ENABLE@ + + +-- Enabling column access control to implement column masking; + + +ALTER TABLE ADMINISTRATOR.PATIENT ACTIVATE COLUMN ACCESS CONTROL@ + + +-- Connect as Dr.Lee; + + +CONNECT TO sample USER lee USING test1234@ + + +-- Query the patient table ; +-- Dr.Lee can view his patients with account balnce as zero; + + +SELECT +SESSION_USER AS "LOGGED_USER",SSN, USERID, NAME, ADDRESS, PHARMACY, ACCT_BALANCE, PCP_ID +FROM ADMINISTRATOR.PATIENT@ + + +-- Connect as Jane the DRUG RESEARCHER + + +CONNECT TO sample USER jane USING test1234@ + + +-- Query the patient table ; +-- All patients information with pharmacy information of; +-- those patients who have opted-in are not masked.; +-- The SSN and account balance are also masked; + + +SELECT +SESSION_USER AS "LOGGED_USER",SSN, USERID, NAME, ADDRESS, PHARMACY, ACCT_BALANCE, PCP_ID +FROM ADMINISTRATOR.PATIENT@ + + +-- Connect as John the accountant + + +CONNECT TO sample USER john USING test1234@ + + +-- Query the patient table ; +-- All patient information are retived with account balance ans SSN but with; +-- masked pharmacy information.; + + +SELECT +SESSION_USER AS "LOGGED_USER",SSN, USERID, NAME, ADDRESS, PHARMACY, ACCT_BALANCE, PCP_ID +FROM ADMINISTRATOR.PATIENT@ + + +-- Connect as Bob; + + +CONNECT TO sample USER bob USING test1234@ + + +-- Query the patient table ; +-- Bob is a patient and can view his information; + + +SELECT +SESSION_USER AS "LOGGED_USER",SSN, USERID, NAME, ADDRESS, PHARMACY, ACCT_BALANCE, PCP_ID +FROM ADMINISTRATOR.PATIENT@ + + +-- Connect as Alex; + + +CONNECT TO sample USER alex USING test1234@ + + +-- Query the patient table ; +-- Alex even with highest authority; +-- cannot view patient data. No data is retireved; + + +SELECT +SESSION_USER AS "LOGGED_USER",SSN, USERID, NAME, ADDRESS, PHARMACY, ACCT_BALANCE, PCP_ID +FROM ADMINISTRATOR.PATIENT@ + + +-- Connect as peter; + + +CONNECT TO sample USER peter USING test1234@ + +-- turn off echo Current Command option to suppress printing of echo command +UPDATE COMMAND OPTIONS USING v OFF@ +!echo -----------------------------------------------------------------------------------------@ +!echo -- Creating view on RCAC protected table.@ +!echo ------------------------------------------------------------------------------------------@ +UPDATE COMMAND OPTIONS USING v ON@ + +-- Creating view on RCAC protected table; +-- The view retrieves those patient who have opted to give their medical information for; +-- drug research.; + + +CREATE VIEW ADMINISTRATOR.PATIENT_INFO_VIEW AS +SELECT P.SSN, P.NAME,C.CHOICE FROM ADMINISTRATOR.PATIENT P, ADMINISTRATOR.PATIENTCHOICE C +WHERE P.SSN = C.SSN AND + C.CHOICE = 'drug-research' AND + C.VALUE = 'opt-in'@ + + + +-- Grant permission to use the view for these users; + + +GRANT SELECT ON ADMINISTRATOR.PATIENT_INFO_VIEW TO USER alex@ +GRANT SELECT ON ADMINISTRATOR.PATIENT_INFO_VIEW TO USER lee@ +GRANT SELECT ON ADMINISTRATOR.PATIENT_INFO_VIEW TO USER bob@ +GRANT SELECT ON ADMINISTRATOR.PATIENT_INFO_VIEW TO USER jane@ + + +-- Connect as Dr.Lee; + + +CONNECT TO sample USER lee USING test1234@ + + +-- Dr.Lee's patients with the view filter condition are retrived.; +-- View works with RCAC as the tables in which RCAC rules are enforced; + + +SELECT SSN, NAME,CHOICE FROM ADMINISTRATOR.PATIENT_INFO_VIEW@ + + +-- Connect as patient Bob; + + +CONNECT TO sample USER bob USING test1234@ + + +-- Views Bob's information only; + + +SELECT SSN, NAME,CHOICE FROM ADMINISTRATOR.PATIENT_INFO_VIEW@ + + +-- Creating SECURE database objects to access RCAC protected; +-- data.; + +-- Connect as alex; + + +CONNECT TO sample USER alex USING test1234@ + + +-- connect as SECADM Alex; +-- Grant the user paul to create secure object.; + + +GRANT CREATE_SECURE_OBJECT ON DATABASE TO USER paul@ + + +-- connect as paul and run the below script.; + + +CONNECT TO sample USER paul USING test1234@ + + +-- Functions for ExampleHMO Accounting department; + +-- turn off echo Current Command option to suppress printing of echo command +UPDATE COMMAND OPTIONS USING v OFF@ +!echo -----------------------------------------------------------------------------------------@ +!echo -- Creating secure objects to access RCAC protected data.@ +!echo -----------------------------------------------------------------------------------------@ +UPDATE COMMAND OPTIONS USING v ON@ + +CREATE FUNCTION ADMINISTRATOR.EXPHMOACCOUNTINGUDF(X DECIMAL(12,2)) + RETURNS DECIMAL(12,2) + LANGUAGE SQL + CONTAINS SQL + DETERMINISTIC + NO EXTERNAL ACTION + RETURN X*(1.0 + RAND(X))@ + + +-- Paul alters the function to be secured ; +-- Hence the function can be used inside a RCAC object; + + +ALTER FUNCTION ADMINISTRATOR.EXPHMOACCOUNTINGUDF SECURED@ + + +-- Connect as alex; + + +CONNECT TO sample USER alex USING test1234@ + + +-- Dropping the mask to recreate it with secure function; + + +DROP MASK ADMINISTRATOR.ACCT_BALANCE_MASK@ + + +-- Recreate the mask which was dropped.; +-- Role ACCOUNTING is allowed to invoke the secured UDF; +-- EXPHMOACCOUNTINGUDF passing column ACCT_BALANCE as; +-- the input argument; + +-- Any un secured function cannot be used inside a RCAC object,; +-- thus preventing data leak and perfromance issue.; + + +CREATE MASK ADMINISTRATOR.ACCT_BALANCE_MASK ON ADMINISTRATOR.PATIENT FOR +COLUMN ACCT_BALANCE RETURN +CASE WHEN VERIFY_ROLE_FOR_USER(SESSION_USER,'ACCOUNTING') = 1 +THEN ACCT_BALANCE +ELSE ADMINISTRATOR.EXPHMOACCOUNTINGUDF(ACCT_BALANCE) +END +ENABLE@ + + +-- Connect as paul; + + +CONNECT TO sample USER paul USING test1234@ + + +-- Functions for NetHMO Pharmacy department,; +-- to be used inside a query.; + + +CREATE FUNCTION ADMINISTRATOR.DRUGUDF(NAME VARCHAR(128)) + RETURNS VARCHAR(5000) + NO EXTERNAL ACTION + BEGIN ATOMIC + IF NAME IS NULL THEN + RETURN NULL; + ELSE + RETURN 'Normal'; + END IF; + END@ + + +-- Securing the UDF; + + +ALTER FUNCTION ADMINISTRATOR.DRUGUDF SECURED@ + + +-- Granting execute permissions to Dr.Lee; + + +GRANT EXECUTE ON FUNCTION ADMINISTRATOR.DRUGUDF TO USER lee@ + + +-- Connect as lee; + + +CONNECT TO sample USER lee USING test1234@ + + +-- Dr.Lee querying after the function is secured; + + +SELECT PHARMACY FROM ADMINISTRATOR.PATIENT +WHERE ADMINISTRATOR.DRUGUDF(NAME) = 'Normal' AND +SSN = '123-45-6789'@ + + + +CONNECT TO sample USER paul USING test1234@ + + +-- Connect as Paul.; +-- Trigger to maintain the account balance history; +-- of patient which fires when ever a update ; +-- is done on a patient table.; +-- The trigger is made secured by using the SECURED keyword; +-- during creation.; + + +CREATE TRIGGER ADMINISTRATOR.EXPHMO_ACCT_BALANCE_TRIGGER + AFTER UPDATE OF ACCT_BALANCE ON ADMINISTRATOR.PATIENT + REFERENCING OLD AS O NEW AS N + FOR EACH ROW MODE DB2SQL SECURED + BEGIN ATOMIC + INSERT INTO ADMINISTRATOR.ACCT_HISTORY + (SSN, BEFORE_BALANCE, AFTER_BALANCE, WHEN, BY_WHO) + VALUES (O.SSN, O.ACCT_BALANCE, N.ACCT_BALANCE, + CURRENT TIMESTAMP, SESSION_USER); +END@ + + +-- Connect as john the accountant; + + +CONNECT TO sample USER john USING test1234@ + + +-- The account balance of the patients is updated in patient table; +-- and the trigger fires updating the ACCT_HISTORY table; +-- with acct_balance before and after update; + +-- Before updation; + + +SELECT ACCT_BALANCE FROM ADMINISTRATOR.PATIENT WHERE SSN = '123-45-6789'@ +SELECT SSN,BEFORE_BALANCE,AFTER_BALANCE,BY_WHO FROM ADMINISTRATOR.ACCT_HISTORY WHERE SSN = '123-45-6789'@ + + +-- John updates the table patient (Trigger fires); + + +UPDATE ADMINISTRATOR.PATIENT SET ACCT_BALANCE = ACCT_BALANCE * 0.9 +WHERE SSN = '123-45-6789'@ + + +-- After updation; + + +SELECT ACCT_BALANCE FROM ADMINISTRATOR.PATIENT WHERE SSN = '123-45-6789'@ +SELECT SSN,BEFORE_BALANCE,AFTER_BALANCE,BY_WHO FROM ADMINISTRATOR.ACCT_HISTORY WHERE SSN = '123-45-6789'@ + + +-- Connect as Alex and revoke Pauls privilege to create; +-- secure object.; + + +CONNECT TO sample USER alex USING test1234@ + +REVOKE CREATE_SECURE_OBJECT ON DATABASE FROM USER paul@ + +--Sample complete + +--Dropping all objects +DROP MASK ADMINISTRATOR.ACCT_BALANCE_MASK@ +DROP MASK ADMINISTRATOR.SSN_MASK@ +DROP MASK ADMINISTRATOR.PHARMACY_MASK@ +DROP PERMISSION ADMINISTRATOR.ROW_ACCESS@ + + +CONNECT RESET@ + +CONNECT TO sample@ + +DROP VIEW ADMINISTRATOR.PATIENT_INFO_VIEW@ +DROP FUNCTION ADMINISTRATOR.EXPHMOACCOUNTINGUDF@ +DROP FUNCTION ADMINISTRATOR.DRUGUDF@ +DROP TRIGGER ADMINISTRATOR.EXPHMO_ACCT_BALANCE_TRIGGER@ + +DROP TABLE ADMINISTRATOR.PATIENT@ +DROP TABLE ADMINISTRATOR.PATIENTCHOICE@ +DROP TABLE ADMINISTRATOR.ACCT_HISTORY@ + +DROP ROLE PCP@ +DROP ROLE DRUG_RESEARCH@ +DROP ROLE ACCOUNTING@ +DROP ROLE MEMBERSHIP@ +DROP ROLE PATIENT@ + +CONNECT RESET@ diff --git a/admin_scripts/security.db2 b/admin_scripts/security.db2 new file mode 100644 index 0000000..80314ad --- /dev/null +++ b/admin_scripts/security.db2 @@ -0,0 +1,72 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: security.db2 +-- +-- SAMPLE: How users can query details about the groups, authorities, +-- privileges and ownerships by using APIs without querying various +-- catalog tables for this purpose. +-- +-- The sample shows how to: +-- 1. Retrieve the groups to which the user belongs to using the UDF +-- SYSPROC.AUTH_LIST_GROUPS_FOR_AUTHID +-- 2. Retrieve the objects owned by the user by using the view +-- SYSCAT.OBJECTOWNERS +-- 3. Retrieve authorities/privileges directly granted to the user +-- by using the view SYSCAT.PRIVILEGES +-- 4. Retrieve the authid type of an authid by using the view +-- SYSCAT.AUTHORIZATIONIDS. +-- +-- SQL STATEMENTS USED: +-- CONNECT +-- SELECT +-- TERMINATE +-- +-- OUTPUT FILE: security.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- +-- Connect to sample database +CONNECT TO SAMPLE; + +-- Retrieve the group to which the user belongs to +SELECT * FROM table (SYSPROC.AUTH_LIST_GROUPS_FOR_AUTHID (CURRENT USER)) AS ST; + +-- Retrieve the objects owned by the current user +SELECT * FROM SYSIBMADM.OBJECTOWNERS WHERE OWNER = CURRENT USER; + +-- Retrieve authorities/privileges directly granted to the user +SELECT * FROM SYSIBMADM.PRIVILEGES WHERE AUTHID = CURRENT USER; + +-- Retrieve the authorization type of the authid +SELECT * FROM SYSIBMADM.AUTHORIZATIONIDS WHERE AUTHID = CURRENT USER; + +-- Disconnect from the sample database; +CONNECT RESET; + +TERMINATE; diff --git a/admin_scripts/setintegrity.db2 b/admin_scripts/setintegrity.db2 new file mode 100644 index 0000000..814a147 --- /dev/null +++ b/admin_scripts/setintegrity.db2 @@ -0,0 +1,300 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: setintegrity.db2 +-- +-- SAMPLE: How to perform online SET INTEGRITY on a table. +-- +-- This sample shows: +-- 1. Availability of table during SET INTEGRITY after LOAD utility. +-- 2. Availability of table during SET INTEGRITY after adding a new +-- partition is added to the table via the ALTER ATTACH. +-- 3. Shows how SET INTEGRITY statement will generate the proper +-- values for both generated columns and identity values whenever +-- a partition which violates the constraint is attached a data +-- partitioned table. +-- 4. Shows new ALL IMMEDIATE UNCHECKED option in the SET INTEGRITY +-- statement which can skip range and constraints violation checking, +-- making the newly attached data visible immediately. +-- +-- Note:- New otion ALL IMMEDIATE UNCHECKED in SET INTEGRITY +-- statement skips the range and constraints violation +-- checking, user assumes full responsibility for the data +-- integrity. +-- +-- SQL STATEMENTS USED: +-- ALTER TABLE +-- CREATE TABLE +-- CREATE TABLE +-- DROP TABLE +-- EXPORT +-- IMPORT +-- INSERT +-- LOAD +-- SELECT +-- SET INTEGRITY +-- TERMINATE +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to database. +CONNECT TO sample; + +-- Create DMS tablespaces. +CREATE TABLESPACE tbsp1 MANAGED BY DATABASE USING (FILE 'conta' 1000); +CREATE TABLESPACE tbsp2 MANAGED BY DATABASE USING (FILE 'contb' 1000); +CREATE TABLESPACE tbsp3 MANAGED BY DATABASE USING (FILE 'contc' 1000); + +-- The following scenario shows the availability of table during +-- SET INTEGRITY after LOAD utility. + +-- Create a partitioned table. + +CREATE TABLE fact_table (min SMALLINT NOT NULL, CONSTRAINT CC CHECK (min>0)) + PARTITION BY RANGE (min) + (PART part1 STARTING FROM (-1) ENDING (3) IN tbsp1, + PART part2 STARTING FROM (4) ENDING (6) IN tbsp2, + PART part3 STARTING FROM (7) ENDING (9) IN tbsp3); + +-- Insert data into table. +INSERT INTO fact_table VALUES (1), (2), (3); + +-- Create a temporary table. +CREATE TABLE temp_table (min SMALLINT NOT NULL); + +-- Insert data into temporary table and export the data in order to obtain +-- 'dummy.del' file in the required format for load. + +INSERT INTO temp_table VALUES (4), (5), (6), (7), (0), (-1); +EXPORT TO dummy.del OF DEL SELECT * FROM temp_table; +LOAD FROM dummy.del OF DEL INSERT INTO fact_table; + +-- Create a temporary table to hold exceptions thrown by SET INTEGRITY statement. +CREATE TABLE fact_exception (min SMALLINT NOT NULL); + +-- The following SET INTEGRITY statement will check the table 'fact_table' for +-- constraint violations and at the same time it provides read access to the +-- table 'fact_table'. If there are any constraint violations then the +-- violating data will be deleted from fact_table and inserted into +-- 'fact_exception' table (a temporary table). + +SET INTEGRITY FOR fact_table ALLOW READ ACCESS IMMEDIATE CHECKED + FOR EXCEPTION IN fact_table USE fact_exception; + +-- Display the contents of each table. +SELECT * FROM fact_table; +SELECT * FROM fact_exception; + +-- Drop the tables. +DROP TABLE fact_table; +DROP TABLE fact_exception; +DROP TABLE temp_table; + +-- The following scenario shows the availability of table during SET INTEGRITY +-- along with GENERATE IDENTITY clause after LOAD. + +-- Create a partitioned table. +CREATE TABLE fact_table (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)) + PARTITION BY RANGE (min) + (PART part1 STARTING FROM (1) ENDING (3) IN tbsp1, + PART part2 STARTING FROM (4) ENDING (6) IN tbsp2, + PART part3 STARTING FROM (7) ENDING (9) IN tbsp3); + +-- Create temporary table to load data into base table. +CREATE TABLE temp_table(min SMALLINT NOT NULL); + +-- Insert data into temporary table and export the data in order to obtain +-- 'dummy.del' file in the required format for load. + +INSERT INTO temp_table VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9); +EXPORT TO dummy.del OF DEL SELECT * FROM temp_table; + +-- Load data from 'dummy.del' into 'fact_table'. +LOAD FROM dummy.del OF DEL INSERT INTO fact_table; + +-- The following SET INTEGRITY statement will check the table fact_table for +-- constraint violations and at the same time the GENERATE IDENTITY along with +-- NOT INCREMENTAL options will generate new identity values for all rows +-- currently in the table and all loaded rows. + +SET INTEGRITY FOR fact_table GENERATE IDENTITY IMMEDIATE CHECKED + NOT INCREMENTAL; + +-- Display the contents of 'fact_table'. +SELECT * FROM fact_table; + +-- Drop the tables. +DROP TABLE fact_table; + +-- The following scenario show the availability of table during SET INTEGRITY +-- along with FORCE GENERATED clause after LOAD. + +-- Create a partitioned table. +CREATE TABLE fact_table (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)) + PARTITION BY RANGE (min) + (PART part1 STARTING FROM (1) ENDING (3) IN tbsp1, + PART part2 STARTING FROM (4) ENDING (6) IN tbsp2, + PART part3 STARTING FROM (7) ENDING (9) IN tbsp3); + +-- Load data from 'dummy.del' into 'fact_table'. +LOAD FROM dummy.del OF DEL INSERT INTO fact_table; + +-- The following SET INTEGRITY statement will check the table fact_table for +-- constraint violations and at the same time the force generated clause +-- will operate on rows that do not evaluate to the proper expression. + +SET INTEGRITY FOR fact_table IMMEDIATE CHECKED FORCE GENERATED; + +-- Display the contents of 'fact_table'. +SELECT * FROM fact_table; + +-- Drop the tables. +DROP TABLE fact_table; + +-- The following scenario shows the availability of table during SET INTEGRITY +-- after ATTACH. + +-- Create a partitioned table. +CREATE TABLE fact_table (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)) + PARTITION BY RANGE (min) + (PART part1 STARTING FROM (1) ENDING (3) IN tbsp1, + PART part2 STARTING FROM (4) ENDING (6) IN tbsp2, + PART part3 STARTING FROM (7) ENDING (9) IN tbsp3); + +LOAD FROM dummy.del OF DEL INSERT INTO fact_table; + +-- Create a table to be attached. +CREATE TABLE attach_part (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)); + +-- Create a temporary table to load data into base table. +CREATE TABLE attach(min SMALLINT NOT NULL); + +INSERT INTO attach VALUES (10), (11), (12); +EXPORT TO dummy1.del OF DEL SELECT * FROM attach; + +-- Load data from 'dummy1.del' into 'fact_table'. +LOAD FROM dummy1.del OF DEL INSERT INTO attach_part; + +-- Attach partition to 'fact_table' table. +ALTER TABLE fact_table ATTACH PARTITION part4 STARTING FROM (10) ENDING AT (12) + FROM TABLE attach_part; + +-- The following SET INTEGRITY statement will check the table fact_table for +-- constraint violations and at the same time the GENERATE IDENTITY along with +-- INCREMENTAL options will generate new identity values for attached +-- rows only. + +SET INTEGRITY FOR fact_table GENERATE IDENTITY IMMEDIATE CHECKED INCREMENTAL; + +-- Display the contents of 'fact_table' table. +SELECT * FROM fact_table; + + +-- Drop the tables. +DROP TABLE fact_table; +DROP TABLE temp_table; +DROP TABLE attach; + +-- The SET INTEGRITY statement is used for checking constraints and +-- integrity violations. It is a long-running operation, and the cost +-- is proportional to the amount of newly attached data. In scenarios +-- where the constraints and integrity checking of the data in +-- the attached partition has already been done using application +-- logic outside of the database then there is no need to check for +-- violations again using the SET INTEGRITY statement. + +-- The following scenario shows the quick availability of table after +-- ATTACH with the new option ALL IMMEDIATE UNCHECKED in SET INTEGRITY +-- which skips the range and constraints violation checking, making the +-- newly attached data visible immediately. + +-- Create a partitioned table. +CREATE TABLE fact_table (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)) + PARTITION BY RANGE (min) + (PART part1 STARTING FROM (1) ENDING (3) IN tbsp1, + PART part2 STARTING FROM (4) ENDING (6) IN tbsp2, + PART part3 STARTING FROM (7) ENDING (9) IN tbsp3); + +LOAD FROM dummy.del OF DEL INSERT INTO fact_table; + +-- Create a table to be attached. +CREATE TABLE attach_part (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)); + +-- Create a temporary table to load data into base table. +CREATE TABLE attach(min SMALLINT NOT NULL); + +INSERT INTO attach VALUES (10), (11), (12); +EXPORT TO dummy1.del OF DEL SELECT * FROM attach; + +-- Load data from 'dummy1.del' into 'fact_table'. +LOAD FROM dummy1.del OF DEL INSERT INTO attach_part; + +-- Attach partition to 'fact_table' table. +ALTER TABLE fact_table ATTACH PARTITION part4 STARTING FROM (10) ENDING AT (12) + FROM TABLE attach_part; + +-- The following SET INTEGRITY statement skips the range and constraints +-- violation checking for table fact_table, making the newly attached data +-- visible immediately. + +SET INTEGRITY FOR fact_table ALL IMMEDIATE UNCHECKED; + +-- Display the contents of 'fact_table' table. +SELECT * FROM fact_table; + +-- Drop the tables. +DROP TABLE fact_table; +DROP TABLE temp_table; +DROP TABLE attach; + +-- Drop the tablespaces. +DROP TABLESPACE tbsp1; +DROP TABLESPACE tbsp2; +DROP TABLESPACE tbsp3; + +-- Remove created temporary files. +! rm -rf dummy.del; +! rm -rf dummy1.del; + +-- Disconnect from database. +CONNECT RESET; + +TERMINATE; diff --git a/admin_scripts/ssv_backup_db.db2 b/admin_scripts/ssv_backup_db.db2 new file mode 100644 index 0000000..cb2f037 --- /dev/null +++ b/admin_scripts/ssv_backup_db.db2 @@ -0,0 +1,135 @@ +-- /***************************************************************************/ +-- /* (c) Copyright IBM Corp. 2007 All rights reserved. +-- /* +-- /* The following sample of source code ("Sample") is owned by International +-- /* Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- /* copyrighted and licensed, not sold. You may use, copy, modify, and +-- /* distribute the Sample in any form without payment to IBM, for the purpose of +-- /* assisting you in the development of your applications. +-- /* +-- /* The Sample code is provided to you on an "AS IS" basis, without warranty of +-- /* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- /* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- /* not allow for the exclusion or limitation of implied warranties, so the above +-- /* limitations or exclusions may not apply to you. IBM shall not be liable for +-- /* any damages you suffer as a result of using, copying, modifying or +-- /* distributing the Sample, even if IBM has been advised of the possibility of +-- /* such damages. +-- /***************************************************************************/ +-- /* */ +-- /* PURPOSE : This sample demonstrates performing a database backup */ +-- /* in a massively parallel processing (MPP) environment. */ +-- /* */ +-- /* USAGE SCENARIO : This sample demonstrates different options of */ +-- /* performing database BACKUP in an MPP environment. */ +-- /* In an MPP environment, you can back up a database on */ +-- /* a single database partition, on several database */ +-- /* partitions at once, or on all database partitions at */ +-- /* once. This command can be run from any database */ +-- /* partition (catalog or non-catalog). It will backup */ +-- /* the database partition that is mentioned in the */ +-- /* DBPARTITIONNUM clause. */ +-- /* */ +-- /* PREREQUISITE : MPP setup with 3 database partitions: */ +-- /* NODE 0: Catalog Node */ +-- /* NODE 1: Non-catalog node */ +-- /* NODE 2: Non-catalog node */ +-- /* */ +-- /* EXECUTION : db2 -tvf ssv_backup_db.db2 */ +-- /* */ +-- /* INPUTS : NONE */ +-- /* */ +-- /* OUTPUT : Successful backups of database on different database */ +-- /* partitions. */ +-- /* */ +-- /* OUTPUT FILE : ssv_backup_db.out */ +-- /* (available in the online documentation) */ +-- /***************************************************************************/ +-- /*For more information about the command line processor (CLP) scripts, */ +-- /*see the README file. */ +-- /*For information on using SQL statements, see the SQL Reference. */ +-- /* */ +-- /*For the latest information on programming, building, and running DB2 */ +-- /*applications, visit the DB2 application development website: */ +-- /*http://www.software.ibm.com/data/db2/udb/ad */ +-- /***************************************************************************/ + +-- /***************************************************************************/ +-- /* SAMPLE DESCRIPTION */ +-- /***************************************************************************/ +-- /* 1. Back up the database on current database partition (DB2NODE). */ +-- /* 2. Back up the database on any specified database partition. */ +-- /* 3. Back up the database on a range of database partitions. */ +-- /* 4. Back up the database on all database partitions except any one */ +-- /* database partition. */ +-- /* 5. Back up the database on all database partitions. */ +-- /***************************************************************************/ + +-- /***************************************************************************/ +-- /* SETUP */ +-- /***************************************************************************/ + +-- Create directories that will be used for storing backup images. +! mkdir $HOME/0; +! mkdir $HOME/1; +! mkdir $HOME/2; + +-- /***************************************************************************/ +-- /*1. Back up the database on current database partition (DB2NODE). */ +-- /***************************************************************************/ + +-- This is the default behavior of BACKUP command if the command is specified +-- without any options (DBPARTITIONNUM). This will back up the database on +-- current database partition. +BACKUP DB SAMPLE; + +-- /***************************************************************************/ +-- /* 2. Back up the database on a specified database partition. */ +-- /***************************************************************************/ + +-- Backup can be performed on any particular database partition using +-- DBPARTITIONNUM clause. +-- Following command will back up the database on database partition 1. +BACKUP DB SAMPLE ON DBPARTITIONNUM (1); + +-- /***************************************************************************/ +-- /* 3. Back up the database on a range of database partitions. */ +-- /***************************************************************************/ + +-- Backup can be performed on any range of database partitions. +-- Following command will back up the database from database partition 1 to +-- database partition 2. +BACKUP DB SAMPLE ON DBPARTITIONNUM (1 TO 2); + +-- /***************************************************************************/ +-- /* 4. Back up the database on all database partitions except any one */ +-- /* database partition. */ +-- /***************************************************************************/ + +-- Backup can be performed on any range of database partitions with some +-- exceptions. +-- Following command will back up the database on all database partitions +-- except database partition 1. +BACKUP DB SAMPLE ON ALL DBPARTITIONNUMS EXCEPT DBPARTITIONNUM (1); + +-- /***************************************************************************/ +-- /* 5. Back up the database on all database partitions. */ +-- /***************************************************************************/ + +-- Backup can be performed on all database partitions. If path expressions +-- are used, then the backup image for each database partition can be stored +-- into seperate storage space. +-- Note: The target directory must exist before the command is run. +! db2 "BACKUP DB SAMPLE ON ALL DBPARTITIONNUMS TO "$HOME/ $N""; + +-- /***************************************************************************/ +-- /* CLEAN UP */ +-- /***************************************************************************/ + +-- Remove temporary directories +! rm -rf $HOME/0; +! rm -rf $HOME/1; +! rm -rf $HOME/2; + +TERMINATE; \ No newline at end of file diff --git a/admin_scripts/ssv_backup_tbsp.db2 b/admin_scripts/ssv_backup_tbsp.db2 new file mode 100644 index 0000000..ba14e82 --- /dev/null +++ b/admin_scripts/ssv_backup_tbsp.db2 @@ -0,0 +1,127 @@ +-- /***************************************************************************/ +-- /* (c) Copyright IBM Corp. 2007 All rights reserved. +-- /* +-- /* The following sample of source code ("Sample") is owned by International +-- /* Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- /* copyrighted and licensed, not sold. You may use, copy, modify, and +-- /* distribute the Sample in any form without payment to IBM, for the purpose of +-- /* assisting you in the development of your applications. +-- /* +-- /* The Sample code is provided to you on an "AS IS" basis, without warranty of +-- /* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- /* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- /* not allow for the exclusion or limitation of implied warranties, so the above +-- /* limitations or exclusions may not apply to you. IBM shall not be liable for +-- /* any damages you suffer as a result of using, copying, modifying or +-- /* distributing the Sample, even if IBM has been advised of the possibility of +-- /* such damages. +-- /***************************************************************************/ +-- /* */ +-- /* SAMPLE FILE NAME: ssv_backup_tbsp.db2 */ +-- /* */ +-- /* PURPOSE : This sample demonstrates performing a tablespace */ +-- /* backup in a massively parallel processing (MPP) */ +-- /* environment. */ +-- /* */ +-- /* USAGE SCENARIO : This sample demonstrates different options of */ +-- /* performing tablespace BACKUPs in an MPP environment. */ +-- /* In an MPP environment, you can back up tablespaces */ +-- /* on a single database partition, on several database */ +-- /* partitions at once, or on all database partitions at */ +-- /* once. */ +-- /* */ +-- /* PREREQUISITE : MPP setup with 3 database partitions: */ +-- /* NODE 0: Catalog Node */ +-- /* NODE 1: Non-catalog node */ +-- /* NODE 2: Non-catalog node */ +-- /* */ +-- /* EXECUTION : db2 -tvf ssv_backup_tbsp.db2 */ +-- /* */ +-- /* INPUTS : NONE */ +-- /* */ +-- /* OUTPUT : Three tablespace backups */ +-- /* - Two successful backups */ +-- /* - One backup with warning */ +-- /* */ +-- /* OUTPUT FILE : ssv_backup_tbsp.out */ +-- /* (available in the online documentation) */ +-- /***************************************************************************/ +-- /*For more information about the command line processor (CLP) scripts, */ +-- /*see the README file. */ +-- /*For information on using SQL statements, see the SQL Reference. */ +-- /* */ +-- /*For the latest information on programming, building, and running DB2 */ +-- /*applications, visit the DB2 application development website: */ +-- /*http://www.software.ibm.com/data/db2/udb/ad */ +-- /***************************************************************************/ + +-- /***************************************************************************/ +-- /* SAMPLE DESCRIPTION */ +-- /***************************************************************************/ +-- /* 1. Back up a tablespace on a set of specified database partitions */ +-- /* (database partition 1 and database partition 2.) */ +-- /* 2. Back up a tablespace on all database partitions at once. */ +-- /***************************************************************************/ + +-- /***************************************************************************/ +-- /* SETUP */ +-- /***************************************************************************/ + +-- Create a directory to store database logs. +! mkdir $HOME/archive; + +CONNECT TO SAMPLE; + +-- Create a database partition group on database partitions 1 and 2. +CREATE DATABASE PARTITION GROUP dbpgroup ON DBPARTITIONNUMS (1, 2); + +-- Create a tablespace on the partition group just created, dbpgroup. +CREATE TABLESPACE t1 IN dbpgroup; + +-- Before performing a tablespace backup, the database must be made recoverable. +-- This will make the logs available which are necessary to restore/rollforward +-- the tablespace. Without making the database recoverable, tablespace can not +-- be backed up. +-- To make the database recoverable, set the LOGARCHMETH1 configuration parameter +-- and take a full backup of the database. +! db2 "UPDATE DB CFG FOR SAMPLE USING logarchmeth1 disk:$HOME/archive"; + +CONNECT RESET; +BACKUP DB sample ON ALL DBPARTITIONNUMS; + +-- /***************************************************************************/ +-- /* 1. Back up a tablespace on a specified set of database partitions. */ +-- /***************************************************************************/ + +-- Back up the tablespace t1 on the database partitions 1 and 2. +BACKUP DATABASE SAMPLE ON DBPARTITIONNUM (1, 2) TABLESPACE t1; + +-- /***************************************************************************/ +-- /* 2. Back up a tablespace on all database partitions at once. */ +-- /***************************************************************************/ + +-- Back up tablespace t1 on all the database partitions. The DB2 data server +-- will return a warning on database partition 0 when you run the following +-- command because the tablespace t1 does not exist on database partition 0. +-- However, this warning does not cause the overall backup to fail. When you +-- run this command, the DB2 data server will display the results of the backup, +-- including the individual results for each database partition. +BACKUP DATABASE SAMPLE ON ALL DBPARTITIONNUMS TABLESPACE t1; + +-- /***************************************************************************/ +-- /* CLEAN UP */ +-- /***************************************************************************/ + +CONNECT TO SAMPLE; + +-- Drop the tablespace +DROP TABLESPACE t1; + +-- Drop the database partition group. +DROP DATABASE PARTITION GROUP dbpgroup; + +-- Remove the temporary directories +! rm -rf $HOME/archive; + +TERMINATE; \ No newline at end of file diff --git a/admin_scripts/ssv_db_cfg.db2 b/admin_scripts/ssv_db_cfg.db2 new file mode 100644 index 0000000..b5c80d2 --- /dev/null +++ b/admin_scripts/ssv_db_cfg.db2 @@ -0,0 +1,164 @@ +-- /***************************************************************************/ +-- /* (c) Copyright IBM Corp. 2007 All rights reserved. +-- /* +-- /* The following sample of source code ("Sample") is owned by International +-- /* Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- /* copyrighted and licensed, not sold. You may use, copy, modify, and +-- /* distribute the Sample in any form without payment to IBM, for the purpose of +-- /* assisting you in the development of your applications. +-- /* +-- /* The Sample code is provided to you on an "AS IS" basis, without warranty of +-- /* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- /* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- /* not allow for the exclusion or limitation of implied warranties, so the above +-- /* limitations or exclusions may not apply to you. IBM shall not be liable for +-- /* any damages you suffer as a result of using, copying, modifying or +-- /* distributing the Sample, even if IBM has been advised of the possibility of +-- /* such damages. +-- /***************************************************************************/ +-- /* */ +-- /* SAMPLE FILE NAME: ssv_db_cfg.db2 */ +-- /* */ +-- /* PURPOSE : This sample demonstrates updating database */ +-- /* configuration parameters in a massively parallel */ +-- /* processing (MPP) environment. */ +-- /* */ +-- /* USAGE SCENARIO : This sample demonstrates different options of */ +-- /* updating database configuration parameters in an MPP */ +-- /* environment. In an MPP environment, database */ +-- /* configuration parameters can either be updated on a */ +-- /* single database partition or on all database */ +-- /* partitions at once. The UPDATE command can be run */ +-- /* from any database partition (catalog or non-catalog). */ +-- /* It will update the database configuration parameter */ +-- /* on the database partition that is mentioned in the */ +-- /* DBPARTITIONNUM clause. The sample will use the DB CFG */ +-- /* parameter 'MAXAPPLS', to demonstrate different UPDATE */ +-- /* & RESET db cfg command options. */ +-- /* */ +-- /* PREREQUISITE : MPP setup with 3 database partitions: */ +-- /* NODE 0: Catalog Node */ +-- /* NODE 1: Non-catalog node */ +-- /* NODE 2: Non-catalog node */ +-- /* */ +-- /* EXECUTION : db2 -tvf ssv_db_cfg.db2 */ +-- /* */ +-- /* INPUTS : NONE */ +-- /* */ +-- /* OUTPUT : Successful updation of database configuration */ +-- /* parameters on different database partitions. */ +-- /* */ +-- /* OUTPUT FILE : ssv_db_cfg.out */ +-- /* (available in the online documentation) */ +-- /***************************************************************************/ +-- /*For more information about the command line processor (CLP) scripts, */ +-- /*see the README file. */ +-- /*For information on using SQL statements, see the SQL Reference. */ +-- /* */ +-- /*For the latest information on programming, building, and running DB2 */ +-- /*applications, visit the DB2 application development website: */ +-- /*http://www.software.ibm.com/data/db2/udb/ad */ +-- /***************************************************************************/ + +-- /***************************************************************************/ +-- /* SAMPLE DESCRIPTION */ +-- /***************************************************************************/ +-- /* 1. Update DB CFG parameter on all database partitions(Default behavior) */ +-- /* 2. Update DB CFG parameter on one database partition(partition 1) */ +-- /* 3. Reset DB CFG parameter on one database partition(partition 1) */ +-- /* 4. Reset DB CFG parameter on all database partitions(Default behavior) */ +-- /***************************************************************************/ + +CONNECT TO SAMPLE; + +-- Check the current value of DB CFG parameter MAXAPPLS on all database +-- partitions. +-- The default value for MAXAPPLS is set to "AUTOMATIC'. + +-- Use db2_all utility to run any DB2 command on all database partitions. +-- db2_all utility can also be used to run a command on specific database +-- partition. +! db2_all "<<+0< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+1< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+2< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +-- /***************************************************************************/ +-- /*1. Update DB CFG parameter on all database partitions.(Default behavior) */ +-- /***************************************************************************/ + +-- This is the default behavior of UPDATE DB CFG command, if it is +-- specified without any DBPARTITIONNUM clause. +-- The following command will update the db cfg parameter on all database +-- partitions. +UPDATE DB CFG FOR SAMPLE USING MAXAPPLS 50; + +-- Verify the value of DB CFG parameter MAXAPPLS on all database partitions. +-- The value will be 50 on all database partitions. + +! db2_all "<<+0< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+1< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+2< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + + +-- /***************************************************************************/ +-- /* 2. Update DB CFG parameter on one database partition (partition 1) */ +-- /***************************************************************************/ + +-- UPDATE DB CFG command can be executed on any particular database partition +-- using DBPARTITIONNUM clause. +-- The following command will update the value of MAXAPPLS to 100 on database +-- partition 1. +UPDATE DB CFG FOR SAMPLE DBPARTITIONNUM 1 USING MAXAPPLS 100; + +-- Verify the value of DB CFG parameter MAXAPPLS on all database partitions. +-- The value will be 100 on partition 1 and 50 on other partitions. + +! db2_all "<<+0< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+1< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+2< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +-- /***************************************************************************/ +-- /* 3. Reset DB CFG parameter on one database partition (partition 1) */ +-- /***************************************************************************/ + +-- RESET CFG command can be executed on any particular database partition using +-- DBPARTITIONNUM clause. +-- The following command will reset the value of 'MAXAPPLS' database parameter on +-- database partition 1. +RESET DB CFG FOR SAMPLE DBPARTITIONNUM 1; + +-- Verify the value of DB CFG parameter MAXAPPLS on all database partitions. +-- The value will be AUTOMATIC on partition 1 and 50 on other partitions. + +! db2_all "<<+0< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+1< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+2< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +-- /***************************************************************************/ +-- /* 4. Reset DB CFG parameter on all database partitions.(Default behavior) */ +-- /***************************************************************************/ + +-- This is the default behavior of RESET DB CFG command, if it is specified +-- without any DBPARTITIONNUM clause. +-- The following command will reset the db cfg parameter on all database partitions. +RESET DB CFG FOR SAMPLE; + +-- Verify the value of DB CFG parameter MAXAPPLS on all database partitions. +-- The value will be AUTOMATIC on all partitions. + +! db2_all "<<+0< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+1< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +! db2_all "<<+2< db2 GET DB CFG FOR SAMPLE" | grep "(MAXAPPLS) ="; + +TERMINATE; diff --git a/admin_scripts/tablepartition.db2 b/admin_scripts/tablepartition.db2 new file mode 100644 index 0000000..0dce874 --- /dev/null +++ b/admin_scripts/tablepartition.db2 @@ -0,0 +1,171 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: tablepartition.db2 +-- +-- SAMPLE: How to create a partitioned table. +-- +-- This sample demonstrates: +-- +-- - Various ways of creating a partitioned table using CREATE TABLE +-- statement. +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- CREATE TABLESPACE +-- DROP TABLE +-- TERMINATE +-- +-- OUTPUT FILE: tablepartition.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to database. +CONNECT TO sample; + +-- Create DMS tablespaces. +CREATE TABLESPACE tbsp1 MANAGED BY DATABASE USING (FILE 'conta' 1000); +CREATE TABLESPACE tbsp2 MANAGED BY DATABASE USING (FILE 'contb' 1000); +CREATE TABLESPACE tbsp3 MANAGED BY DATABASE USING (FILE 'contc' 1000); +CREATE TABLESPACE tbsp4 MANAGED BY DATABASE USING (FILE 'contd' 1000); + +-- Creating a partitioned table on a list of tablespaces. A table 'emp_table' +-- with four partitions will be created. i.e part0 is placed in tbsp1, +-- part1 will be placed in tbsp2, part2 will be placed in tbsp3 and +-- part3 will be placed in tbsp4. +CREATE TABLE emp_table(emp_no INT) IN tbsp1, tbsp2, tbsp3, tbsp4 + PARTITION BY RANGE(emp_no) + (STARTING 0 ENDING 9, + STARTING 10 ENDING 19, + STARTING 20 ENDING 29, + STARTING 30 ENDING 39); + +-- Drop the table. +DROP TABLE emp_table; + +-- Creating a partitioned table by specifying tablespace for an individual +-- data partition. A table 'emp_table' with four partitions will be created. +-- i.e part0 is placed in tbsp1, part1 will be placed in tbsp2, +-- part2 will be placed in tbsp3 and part3 will be placed in tbsp4. +CREATE TABLE emp_table(emp_no INT) + PARTITION BY RANGE(emp_no) + (STARTING 0 ENDING 9 IN tbsp1, + STARTING 10 ENDING 19 IN tbsp2, + STARTING 20 ENDING 29 IN tbsp3, + STARTING 30 ENDING 39 IN tbsp4); + +-- Drop the table. +DROP TABLE emp_table; + +-- Creating a partitioned table by placing data in a Round Robin +-- fashion among the tablespaces. +-- A table 'emp_table' will be created with data placed in a Round Robin +-- fashion among tbsp1, tbsp2, tbps3 tablespaces. +CREATE TABLE emp_table(emp_no INT) IN tbsp1, tbsp2, tbsp3 + PARTITION BY RANGE(emp_no) + (STARTING 2 ENDING 9 EVERY 2); + +-- Drop the table. +DROP TABLE emp_table; + +-- Creating a partitioned table by combining both the short and the long +-- forms of the syntax. +CREATE TABLE emp_table(emp_no INT) IN tbsp1, tbsp2 + PARTITION BY RANGE(emp_no) + (STARTING 10 ENDING 19 EVERY 2, + STARTING 0 ENDING 9, + STARTING 20 ENDING 29); + +-- Drop the table. +DROP TABLE emp_table; + +-- Creating a partitioned table 'document' by using LONG IN clause to place +-- the LOB data in a specified tablespace. +CREATE TABLE document(sno INT, empid INT)LONG IN tbsp3, tbsp4 + PARTITION BY RANGE(empid) (STARTING 1 ENDING 1000 EVERY 100); + +-- Drop the table. +DROP TABLE document; + +-- Creatng a partitioned table 'persons' using MINVALUE and MAXVALUE. +CREATE TABLE persons (last character(15) not null, + first character(15), + middle character(15)) + PARTITION BY RANGE(last, first, middle ) + (part 0 starting from (MINVALUE, MINVALUE, MINVALUE), + part 1 starting from ('COX', 'ELIZABETH', 'ELLEN' ) exclusive, + part 2 starting from ('HARDING', 'TONYA', MINVALUE), + part 3 starting from ('MACCA', MINVALUE, MINVALUE), + part 4 starting from ('SMITH', MAXVALUE, MAXVALUE), + part 5 starting from ('ZYZYCK', 'MARK', MAXVALUE) + ending (MAXVALUE, MAXVALUE, MAXVALUE)); + +-- Drop the table. +DROP TABLE persons; + +-- Creating a partitioned table. This shows how a partitioned table can be +-- multi-dimensionally clustered to allow finer granularity of data partition +-- and block elimination using ORGANIZE BY clause. +CREATE TABLE orders (YearAndMonth INT, Province CHAR(2), Country CHAR(3)) + IN tbsp1, tbsp2 + PARTITION BY RANGE (YearAndMonth) + (STARTING 9901 ENDING 9904 EVERY 2) + ORGANIZE BY (Province); + +-- Drop the table. +DROP TABLE orders; + +-- The following creates a partitioned table. +-- This shows how to spread the data across different database partitions +-- using DISTRIBUTE BY clause. All rows with the same value of column +-- 'Country' will be in the same database partition. All rows with the same +-- value of column 'YearAndMonth' will be in the same tablespace. +-- For a given value of 'Country' and 'YearAndMonth', all rows with the same +-- value 'Province' will be clustered together on disk. + +CREATE TABLE orders (YearAndMonth INT, Province CHAR(2), Country CHAR(3)) + IN tbsp1, tbsp2 + DISTRIBUTE BY HASH(Country) + PARTITION BY RANGE(YearAndMonth) (STARTING 9901 ENDING 9904 EVERY 2) + ORGANIZE BY DIMENSIONS(Province); + +-- Drop the table. +DROP TABLE orders; + +-- Drop the tablespaces. +DROP TABLESPACE tbsp1; +DROP TABLESPACE tbsp2; +DROP TABLESPACE tbsp3; +DROP TABLESPACE tbsp4; + +-- Disconnect from database. +CONNECT RESET; + +TERMINATE; + diff --git a/admin_scripts/tbeventmon.db2 b/admin_scripts/tbeventmon.db2 new file mode 100644 index 0000000..03c4e92 --- /dev/null +++ b/admin_scripts/tbeventmon.db2 @@ -0,0 +1,120 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: tbeventmon.db2 +-- +-- SAMPLE: How to create and use event monitors written to a table. +-- +-- SQL STATEMENTS USED: +-- CREATE EVENT MONITOR +-- SET EVENT MONITOR +-- CONNECT +-- DROP TABLE +-- +-- OUTPUT FILE: tbeventmon.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- To create event monitors for event types statements , deadlocks and +-- connections which are written to a table + +CREATE EVENT MONITOR dlmon + FOR STATEMENTS, DEADLOCKS WITH DETAILS, CONNECTIONS + WRITE TO TABLE + CONNHEADER (TABLE CONNHEADER_dlmon, + INCLUDES (AGENT_ID, + APPL_ID, + APPL_NAME, + TERRITORY_CODE )), + DEADLOCK (TABLE DEADLOCK_dlmon), + DLCONN (TABLE mydept.dlconnections, + EXCLUDES ( + LOCK_OBJECT_NAME, + LOCK_OBJECT_TYPE, + TABLESPACE_NAME )), + STMT (TABLE STMT_dlmon, + INCLUDES (AGENT_ID, + APPL_ID, + CREATOR, + INT_ROWS_DELETED, + INT_ROWS_INSERTED, + INT_ROWS_UPDATED, + ROWS_READ, + ROWS_WRITTEN, + SQLCODE, + SQLSTATE, + SQLWARN, + START_TIME, + STMT_OPERATION, + STMT_TEXT )), + CONN , + CONTROL (TABLE CONTROL_dlmon, + INCLUDES (EVENT_MONITOR_NAME, + MESSAGE, + MESSAGE_TIME )) + BUFFERSIZE 8 NONBLOCKED MANUALSTART; + +-- Activate event monitor +SET EVENT MONITOR dlmon STATE=1; + +-- The following SQL statements generate sample events that populate +-- COLL_dlmon table +CONNECT RESET; +CONNECT TO SAMPLE; + +-- Reactivate event monitor +SET EVENT MONITOR dlmon STATE = 1; + +-- Retrieve data from the event monitor tables +SELECT agent_id, appl_id, territory_code FROM CONNHEADER_dlmon; +SELECT agent_id, appl_id, int_rows_inserted, + system_cpu_time FROM CONN_dlmon; +SELECT * FROM CONTROL_dlmon; + +-- Deactivate event monitor +SET EVENT MONITOR dlmon STATE = 0; + +-- Drop event monitor +DROP EVENT MONITOR dlmon; + +-- Dropping the monitor doesn't remove tables. They have to be +-- dropped explicitly +DROP TABLE CONNHEADER_dlmon; +DROP TABLE DEADLOCK_dlmon; +DROP TABLE mydept.dlconnections; +DROP TABLE STMT_dlmon; +DROP TABLE CONN_dlmon; +DROP TABLE CONTROL_dlmon; + +-- db2evtbl is a tool that generates sample CREATE EVENT MONITOR SQL +-- statements that can be used when defining event monitors that write +-- to sql tables. +-- Uuncomment the following statement to generate a CREATE EVENT +-- MONITOR sql statement +-- ! db2evtbl -evm dlmon STATEMENTS, DEADLOCKS WITH DETAILS, CONNECTIONS; diff --git a/admin_scripts/tbonlineinx.db2 b/admin_scripts/tbonlineinx.db2 new file mode 100644 index 0000000..7d1ce4c --- /dev/null +++ b/admin_scripts/tbonlineinx.db2 @@ -0,0 +1,138 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: tbonlineinx.db2 +-- +-- SAMPLE: How to create and reorg indexes on a table +-- +-- SQL STATEMENTS USED: +-- CREATE BUFFERPOOL +-- CREATE INDEX +-- CREATE TABLE +-- CREATE TABLESPACE +-- DROP BUFFERPOOL +-- DROP INDEX +-- DROP TABLE +-- DROP TABLESPACE +-- +-- OUTPUT FILE: tbonlineinx.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- create online index on a table + +-- connect to sample database +CONNECT TO SAMPLE; + +-- create an index on a table with different levels of access to the table +-- like read-write, read-only, no access + +-- create an online index with read-write access to the table +CREATE INDEX index1 ON employee (lastname ASC); + +-- drop the index +DROP INDEX index1; + +-- create an index on a table while allowing only read access to it +LOCK TABLE employee IN SHARE MODE; + +CREATE INDEX index1 ON employee (lastname ASC); + +-- drop the index +DROP INDEX index1; + +-- create an online index allowing no access to the table +LOCK TABLE employee IN EXCLUSIVE MODE; + +CREATE INDEX index1 ON employee (lastname ASC); + +-- reorg online index on the table + +-- reorganize the indexes on the table +REORG INDEXES ALL FOR TABLE employee; + +-- reorganize the indexes on the table allowing read-only +-- REORG INDEXES ALL FOR TABLE employee ALLOW WRITE ACCESS; + +-- reorganize the indexes on the table allowing no access +REORG INDEXES ALL FOR TABLE employee ALLOW NO ACCESS; + +-- drop the index +DROP INDEX index1; + +----------------------------------------------------------------------------- +-- create index with large index key part on larger columns upto 8KB + +-- create bufferpool with 32K pagesize +CREATE BUFFERPOOL bupl32k SIZE 500 PAGESIZE 32K; + +-- create tablespace using above created bufferpool +CREATE TABLESPACE tbsp32k + PAGESIZE 32k + BUFFERPOOL bupl32k; + +-- create table with large coloumn size. +CREATE TABLE inventory_ident (dept INTEGER, + serial_numbers VARCHAR(8190) NOT NULL) + IN tbsp32k; + +-- create a system temporary table space with 32K pages. +-- When the INDEXSORT database configuration parameter is set to Yes +-- (which is the default), then that data is sorted before it is passed +-- to index manager. If sort heap is big enough for the amount of data +-- being sorted, the sort will occur entirely in memory. However, just +-- in case we need to spill to disk, DB2 will ensure that there is a +-- system temporary tablespace with a large enough page size to spill to. + +CREATE SYSTEM TEMPORARY TABLESPACE tmptbsp32k + PAGESIZE 32K + EXTENTSIZE 2 + BUFFERPOOL bupl32k; + +-- create an index on the serial_numbers column +-- The upper bound for an index key length is variable based on +-- page size. The maximum length of an index key part can be: +-- 1024 bytes for 1K page size, +-- 2048 bytes for 8K page size, +-- 4096 bytes for 16K page size, +-- 8192 bytes for 32K page size, +-- and, the index name can be upto 128 char +CREATE INDEX inventory_serial_number_index_ident + ON inventory_ident (serial_numbers); + +-- perform cleanup +DROP INDEX inventory_serial_number_index_ident; +DROP TABLE inventory_ident; +DROP TABLESPACE tmptbsp32k; +DROP TABLESPACE tbsp32k; +DROP BUFFERPOOL bupl32k; + +-- disconnect from the database +CONNECT RESET; +TERMINATE; diff --git a/admin_scripts/tbrowcompress.db2 b/admin_scripts/tbrowcompress.db2 new file mode 100644 index 0000000..72d52b4 --- /dev/null +++ b/admin_scripts/tbrowcompress.db2 @@ -0,0 +1,370 @@ +-- /************************************************************************* +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************* +-- +-- SAMPLE FILE NAME: tbrowcompress.db2 +-- +-- PURPOSE : To demonstrate row compression and automatic dictionary creation. +-- +-- Row Compression: +-- 1. How to enable the row compression after a table is created. +-- 2. How to enable the row compression during table creation. +-- 3. Usage of the options to REORG to use the exiting dictionary +-- or creating a new dictionary. +-- 4. How to estimate the effectiveness of the compression. +-- +-- Automatic Dictionary Creation: +-- 1. When the compression dictionary will automatically be created. +-- 2. Automatic dictionary creation with DML commands like INSERT, IMPORT and LOAD. +-- 3. How to determine whether a new dictionary should be built or not. +-- 4. Automatic dictionary creation for a data partitioned table. +-- +-- EXECUTION: db2 -td@ -vf tbrowcompress.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: successful creation of compression dictionary. +-- +-- OUTPUT FILE: tbrowcompress.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE ... COMPRESS YES +-- CREATE PROCEDURE +-- CALL +-- ALTER TABLE +-- DELETE +-- DROP TABLE +-- EXPORT +-- IMPORT +-- INSERT +-- INSPECT +-- LOAD +-- REORG +-- RUNSTATS +-- TERMINATE +-- UPDATE +-- +-- SQL ROUTINES USED: +-- SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO +-- +-- ************************************************************************* +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- ************************************************************************* +-- +-- SAMPLE DESCRIPTION +-- +-- ************************************************************************* +-- 1. ROW COMPRESSION +-- 2. AUTOMATIC DICTIONARY CREATION +-- *************************************************************************/ + + +-- ************************************************************************* +-- 1. ROW COMPRESSION +-- *************************************************************************/ + +-- Connect to sample database. +CONNECT TO sample@ + +-- Create a schema. +CREATE SCHEMA testschema@ + +-- Create a scratch table. +CREATE TABLE testschema.temp(empno INT, sal DOUBLE)@ + +-- Insert data into the table and export the data in order to obtain +-- dummy.del file in the required format for load. +-- Create a procedure to insert the sufficient data for ADC. +DROP PROCEDURE insertdata@ + +CREATE PROCEDURE insertdata(IN size INT) +LANGUAGE SQL +BEGIN + DECLARE count INTEGER DEFAULT 0; + while (count < size) + do + INSERT INTO testschema.temp VALUES(100, 20000); + INSERT INTO testschema.temp VALUES(200, 30000); + INSERT INTO testschema.temp VALUES(200, 30000); + SET count=count+1; + end while; +END@ + +-- Call the procedure to insert data into the table until table size threshold is breached. +CALL insertdata(1000)@ + +EXPORT TO dummy.del OF DEL SELECT * FROM testschema.temp@ + +-- Drop the table. +DROP TABLE testschema.temp@ + +-- Create a table without enabling row compression at the time of table creation. +CREATE TABLE testschema.empl (emp_no INT, salary DOUBLE)@ + +-- Perform a load operation to load three rows of data into empl. +LOAD FROM dummy.del OF DEL INSERT INTO testschema.empl@ + +-- Enable row compression. +ALTER TABLE testschema.empl COMPRESS YES@ + +-- Perform non-inplace reorg to compress rows. +REORG TABLE testschema.empl@ + +-- Drop the table. +DROP TABLE testschema.empl@ + +-- Create a table enabling compression initially. +CREATE TABLE testschema.empl (emp_no INT, salary DOUBLE) COMPRESS YES@ + +-- Load data into table. +LOAD FROM dummy.del OF DEL INSERT INTO testschema.empl@ + +-- Perform reorganization to compress rows. +REORG TABLE testschema.empl@ + +-- Perform modifications on table. +INSERT INTO testschema.empl VALUES(400, 30000)@ +UPDATE testschema.empl SET salary = salary + 1000@ +DELETE FROM testschema.empl WHERE emp_no = 200@ + +-- Disable row compression for the table. +ALTER TABLE testschema.empl COMPRESS NO@ + +-- Perform reorganization to remove existing dictionary. +-- New dictionary will be created and all the rows processed by the reorg +-- are decompressed. +REORG TABLE testschema.empl RESETDICTIONARY@ + +-- Drop the table. +DROP TABLE testschema.empl@ + +-- Create a table, load data, perform some modifications on the table. +-- All the rows will be in non-compressed state until reorganization is performed. +CREATE TABLE testschema.empl (emp_no INT, salary DOUBLE)@ + +IMPORT FROM dummy.del OF DEL INSERT INTO testschema.empl@ + +ALTER TABLE testschema.empl COMPRESS YES@ + +INSERT INTO testschema.empl VALUES(400, 30000)@ + +-- Perform inspect to estimate the effectiveness of compression. +-- INSPECT command has to be run before the REORG utility. +-- Inspect allows you to look over table spaces and tables for their +-- architectural integrity. +-- 'result' file contains percentage of bytes saved from compression, +-- Percentage of rows ineligible for compression due to small row size, +-- Compression dictionary size, Expansion dictionary size etc. +-- To view the contents of 'result' file perform +-- db2inspf result result.out@ +-- This formats the 'result' file to readable form. + +INSPECT ROWCOMPESTIMATE TABLE NAME empl SCHEMA testschema RESULTS KEEP result@ + +REORG TABLE testschema.empl@ + +-- All the rows will be compressed including the one inserted after reorg. +INSERT INTO testschema.empl VALUES(500, 40000)@ + +-- Disable row compression for the table. +-- Rows inserted after this will be non-compressed. +ALTER TABLE testschema.empl COMPRESS NO@ +INSERT INTO testschema.empl VALUES(600, 50000)@ + +-- Enable row compression again to compress the rows inserted later. +ALTER TABLE testschema.empl COMPRESS YES@ +INSERT INTO testschema.empl VALUES(700, 40600)@ + +-- Perform runstats to measure the effectiveness of compression using +-- compression related catalog fields. New columns will be updated to +-- catalog table after runstats is performed on a compressed table. +RUNSTATS ON TABLE testschema.empl@ + +-- Display the contents of 'empl' table. +SELECT count(*) FROM testschema.empl@ + +-- Display the contents of 'SYSCAT.TABLES' to measure effectiveness +-- of compression. +SELECT avgrowsize, avgcompressedrowsize, pctpagessaved, avgrowcompressionratio, + pctrowscompressed from SYSCAT.TABLES WHERE tabname = 'EMPL'@ + +-- Drop the table. +DROP TABLE testschema.empl@ + +-- Remove temporary file. +-- Delete the 'result1' file created by INSPECT command +! rm dummy.del@ +! rm -rf $HOME/sqllib/db2dump/result@ + + +-- ************************************************************************* +-- 2. AUTOMATIC DICTIONARY CREATION +-- ************************************************************************* + +-- Automatic Dictionary Creation(ADC) while populating table using INSERT command. + +-- Create a table with row compression turned on. +CREATE TABLE testschema.emptable(emp_no INT, name VARCHAR(120),joindate DATE) COMPRESS YES@ + +-- Create a procedure to insert the sufficient data for ADC. +DROP PROCEDURE insertdata@ + +CREATE PROCEDURE insertdata(IN size INT) +LANGUAGE SQL +BEGIN + DECLARE count INTEGER DEFAULT 0; + while (count < size) + do + INSERT INTO testschema.emptable VALUES(10, 'Padma Kota', '2001-12-02'); + INSERT INTO testschema.emptable VALUES(30, 'Doug Foulds', '1898-08-08'); + INSERT INTO testschema.emptable VALUES(50, 'Kathy Smith', '2006-12-02'); + INSERT INTO testschema.emptable VALUES(75, 'Brad Cassels', '1984-04-06'); + INSERT INTO testschema.emptable VALUES(90, 'Kelly Booch', '2003-12-02'); + SET count=count+1; + end while; +END@ + +-- Call the procedure to insert data into the table until table size threshold is breached. +CALL insertdata(8000)@ + +-- When the table size is reaches threshold, the compression dictionary +-- will be created automatically. Get the dictionary size using. +SELECT dict_builder, dict_build_timestamp, compress_dict_size, expand_dict_size, pages_saved_percent, bytes_saved_percent FROM table(sysproc.admin_get_tab_compress_info('TESTSCHEMA','EMPTABLE','REPORT')) as temp@ + +-- Export the data to a temporary file. +EXPORT TO dummy.del OF DEL SELECT * FROM testschema.emptable@ + +-- Drop the table. +DROP TABLE testschema.emptable@ + +-- Automatic Dictionary Creation(ADC) while populating table using IMPORT command. + +-- Create a table with row compression turned on. +CREATE TABLE testschema.emptable(emp_no INT, name VARCHAR(120),joindate DATE) COMPRESS YES@ + +-- IMPORT data into an existing table which is currently less in size than +-- the threshold for ADC. As data is inserted into the table, the threshold is breached and +-- a dictionary is built, inserted into the table and the remaining data to be loaded is +-- subject to compression. +IMPORT FROM dummy.del OF DEL INSERT INTO testschema.emptable@ + +-- When the table size is reaches threshold, the compression dictionary +-- will be created automatically. Get the dictionary size using. +SELECT dict_builder, dict_build_timestamp, compress_dict_size, expand_dict_size, pages_saved_percent, bytes_saved_percent FROM table(sysproc.admin_get_tab_compress_info('TESTSCHEMA','EMPTABLE','REPORT')) as temp@ + +-- Drop the table. +DROP TABLE testschema.emptable@ + +-- Automatic Dictionary Creation(ADC) while populating table using LOAD command. + +-- Create a table with row compression turned on. +CREATE TABLE testschema.emptable(emp_no INT, name VARCHAR(120),joindate DATE) COMPRESS YES@ + +-- LOAD INSERT into an existing table which is currently less in size than +-- the threshold for ADC. As data is inserted into the table, the threshold is breached and +-- a dictionary is built, inserted into the table and the remaining data to be loaded is +-- subject to compression. +LOAD FROM dummy.del OF DEL INSERT INTO testschema.emptable@ + +-- When the table size is reaches threshold, the compression dictionary +-- will be created automatically. Get the dictionary size using +SELECT dict_builder, dict_build_timestamp, compress_dict_size, expand_dict_size, pages_saved_percent, bytes_saved_percent FROM table(sysproc.admin_get_tab_compress_info('TESTSCHEMA','EMPTABLE','REPORT')) as temp@ + +-- Drop the table. +DROP TABLE testschema.emptable@ + +-- To confirm whether a new dictionary should be built in order re-establish +-- a more acceptable compression ratio for already existing dictionary +-- which is built using offline REORG. + +-- Create a table with compression attribute enabled. +CREATE TABLE testschema.emptable(empid int, dept int, name varchar(50), joindate date) COMPRESS YES@ + +-- Insert some data into the table. +INSERT INTO testschema.emptable VALUES(1, 720, 'Smith', '05/12/2006')@ +INSERT INTO testschema.emptable VALUES (3, 168, 'Jones', '05/13/2006')@ + +-- Do a offline REORG on the table. +REORG TABLE employee@ + +-- Insert some more data into the table. +INSERT INTO testschema.emptable VALUES(5, 720, 'Smith', '05/12/2006')@ +INSERT INTO testschema.emptable VALUES (6, 168, 'Jones', '05/13/2006')@ + +-- Reports compression information as of last generation. +SELECT pages_saved_percent, bytes_saved_percent FROM table(sysproc.admin_get_tab_compress_info('TESTSCHEMA','EMPTABLE','REPORT')) as temp@ + +-- Insert some more data into the table. +INSERT INTO testschema.emptable VALUES(7, 720, 'Smith', '05/12/2006')@ +INSERT INTO testschema.emptable VALUES (8, 168, 'Jones', '05/13/2006')@ + +-- Generates an estimate of new compression information based on current table data. +SELECT pages_saved_percent, bytes_saved_percent FROM table(sysproc.admin_get_tab_compress_info('TESTSCHEMA','EMPTABLE','ESTIMATE')) as temp@ + +-- Delete the table employee. +DROP TABLE testschema.emptable@ + +-- Automatic Dictionary Creation in a partitioned table. + +-- Create a data partitioned table, and load with an initial subset of data. +CREATE TABLESPACE tbsp1 MANAGED BY DATABASE USING (FILE 'conta' 1000)@ +CREATE TABLESPACE tbsp2 MANAGED BY DATABASE USING (FILE 'contb' 1000)@ +CREATE TABLESPACE tbsp3 MANAGED BY DATABASE USING (FILE 'contc' 1000)@ +CREATE TABLESPACE tbsp4 MANAGED BY DATABASE USING (FILE 'contd' 1000)@ +CREATE TABLESPACE tbsp5 MANAGED BY DATABASE USING (FILE 'conte' 1000)@ + +-- Create a data partitioned table with a condition and compress attribute set. +CREATE TABLE testschema.emp_dpart (id int, name varchar(120), joindate DATE) IN tbsp1, tbsp2, tbsp3, tbsp4, tbsp5 partition by range(id) (starting from (1) ending (100) every (20)) COMPRESS YES@ + +-- Load some records of data into table so that the partitions data size reaches +-- ADC threshold. +LOAD FROM dummy.del OF del MESSAGES load_ins.msg INSERT INTO testschema.emp_dpart@ + +-- Get the dictionary sizes for the partitions. +SELECT dict_builder, compress_dict_size+expand_dict_size, data_partition_id from table(sysproc.admin_get_tab_compress_info('TESTSCHEMA','EMP_DPART','REPORT')) as temp@ + +-- Get compression statistics via RUNSTATS command. +RUNSTATS ON TABLE testschema.emp_dpart@ +SELECT avgcompressedrowsize, pctrowscompressed, pctpagessaved FROM syscat.tables WHERE tabschema='TESTSCHEMA' and tabname='EMP_DPART'@ + +-- Delete the table. +DROP TABLE testschema.emp_dpart@ + +DROP TABLESPACE tbsp1@ +DROP TABLESPACE tbsp2@ +DROP TABLESPACE tbsp3@ +DROP TABLESPACE tbsp4@ +DROP TABLESPACE tbsp5@ + +-- Drop the schema. +DROP SCHEMA testschema RESTRICT@ + +-- Remove temporary file. +! rm dummy.del@ + +-- Disconnect from database. +CONNECT RESET@ + +TERMINATE@ diff --git a/admin_scripts/tbrunstats.db2 b/admin_scripts/tbrunstats.db2 new file mode 100644 index 0000000..720bb77 --- /dev/null +++ b/admin_scripts/tbrunstats.db2 @@ -0,0 +1,87 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: tbrunstats.db2 +-- +-- SAMPLE: How to perform runstats on a table +-- +-- SQL STATEMENT USED: +-- CREATE SCHEMA +-- CREATE TABLE +-- DROP SCHEMA +-- DROP TABLE +-- INSERT +-- SELECT +-- TERMINATE +-- +-- OUTPUT FILE: tbrunstats.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- create a schema +CREATE SCHEMA testschema; + +-- create a table +CREATE TABLE testschema.employee_temp LIKE employee; + +-- insert into the table employee_temp +INSERT INTO testschema.employee_temp (SELECT * FROM employee); + +-- perform Runstats on the table + +-- update statistics for the table employee_temp + +-- perform runstats on table employee_temp for column empno +-- with the following options: +-- +-- Distribution statistics for all partitions +-- Frequent values for table set to 30 +-- Quantiles for table set to -1 (NUM_QUANTILES as in DB Cfg) +-- Allow others to have read-only while gathering statistics + +RUNSTATS ON TABLE testschema.employee_temp + ON COLUMNS(empno LIKE STATISTICS) + WITH DISTRIBUTION ON KEY COLUMNS + DEFAULT + NUM_FREQVALUES 30 + NUM_QUANTILES -1 + ALLOW READ ACCESS; + +-- make sure to rebind all packages that use this table. + +-- drop the table employee_temp +DROP TABLE testschema.employee_temp; + +-- drop the schema +DROP SCHEMA testschema RESTRICT; + +-- disconnect from the database +CONNECT RESET; + +TERMINATE; diff --git a/admin_scripts/tbsreduce.db2 b/admin_scripts/tbsreduce.db2 new file mode 100644 index 0000000..38b8b08 --- /dev/null +++ b/admin_scripts/tbsreduce.db2 @@ -0,0 +1,393 @@ +-- **************************************************************************** +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- **************************************************************************** +-- +-- SAMPLE FILE NAME: tbsreduce.db2 +-- +-- PURPOSE : To demonstrate how unused storage at the end of a table +-- space can be freed up and reused. +-- +-- USAGE SCENARIO : Reclaim space from dropped tables. +-- User can drop old tables in the table space and reclaim +-- the space held by the dropped tables. User can perform +-- 'ALTER TABLESPACE REDUCE' on the table space to reclaim +-- the space of the dropped tables. +-- This sample shows how users can reuse this space for +-- the creation of new tables in the table space. +-- +-- PREREQUISITE : NONE +-- +-- EXECUTION : db2 -tvf tbsreduce.db2 +-- +-- INPUTS : NONE +-- +-- OUTPUTS : +-- +-- OUTPUT FILE : tbsreduce.out (available in the online documentation) +-- +-- DEPENDENCIES : NONE +-- +-- SQL STATEMENTS USED: +-- ALTER TABLESPACE +-- CREATE TABLE +-- CREATE TABLESPACE +-- DROP TABLE +-- DROP TABLESPACE +-- INSERT +-- SELECT +-- UPDATE +-- **************************************************************************** +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- **************************************************************************** +-- SAMPLE DESCRIPTION +-- **************************************************************************** +-- 1. How to utilize the unused space of a table space created with +-- AUTOMATIC STORAGE. +-- 2. How to utilize the unused space of a table space created with DATABASE +-- MANAGED SPACE. +-- **************************************************************************** +-- SETUP +-- **************************************************************************** +-- Set auto-commit of SQL statements to OFF. +UPDATE COMMAND OPTIONS USING c OFF; + +-- Create database. +!db2start; +CREATE DB testdb1; + +-- Connect to database. +CONNECT TO testdb1; + +-- **************************************************************************** +-- 1. How to utilize the unused space of a table space created with +-- AUTOMATIC STORAGE. +-- **************************************************************************** + +-- Create table space 'tbsp_auto' managed by AUTOMATIC STORAGE. +CREATE TABLESPACE tbsp_auto PAGESIZE 4096 MANAGED BY AUTOMATIC STORAGE + EXTENTSIZE 2 AUTORESIZE NO INITIALSIZE 107K; + +-- Create table 'tab_auto1' in table space 'tbsp_auto'. +CREATE TABLE tab_auto1 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_auto; + +-- Populate table 'tab_auto1' with the following data. +INSERT INTO tab_auto1 VALUES ('a', 'b', 'c', 'd', 'e', + 'f', 'g', 'h', 'i', 'j' ); + +-- Create table 'tab_auto2' in table space 'tbsp_auto'. +CREATE TABLE tab_auto2 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_auto; + +-- Populate table 'tab_auto2' with data so that the table space is full. +------------------------------------------------------------------------------- +-- Table space 'tbsp_auto' will be full after the five INSERT statements shown +-- below. Creation of new tables in table space 'tbsp_auto' will fail with an +-- error: "Unable to allocate new pages in table space". +------------------------------------------------------------------------------- +INSERT INTO tab_auto2 VALUES ('a', 'b', 'c', 'd', 'e', + 'f', 'g', 'h', 'i', 'j' ); +INSERT INTO tab_auto2 (SELECT * FROM tab_auto2); +INSERT INTO tab_auto2 (SELECT * FROM tab_auto2); +INSERT INTO tab_auto2 (SELECT * FROM tab_auto1); +INSERT INTO tab_auto2 (SELECT * FROM tab_auto2); + +-- Create table 'tab_auto3' in table space 'tbsp_auto'. Table creation +-- will fail with the following error: +-- "Unable to allocate new pages in table space". +CREATE TABLE tab_auto3 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_auto; + +! echo "Above error is expected !"; + +-- Take a snapshot of the table space. This will give details such as: +-- table space name, high water mark, extent size, used pages, free pages, +-- pending free pages for table space 'tbsp_auto'. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_AUTO', -1)) AS mon_get_tablespace ; + +-- Drop tables 'tab_auto1' and 'tab_auto2'. +-- Take a table space snapshot to show the HWM hasn't changed after performing a +-- drop. The above and below snapshots show the same value for the HWM. +DROP TABLE tab_auto2; +DROP TABLE tab_auto1; + +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_AUTO', -1)) AS mon_get_tablespace ; + +-- Try to create new table 'tab_auto3' in the table space 'tbsp_auto'. +-- This will fail with the error: +-- "Unable to allocate new pages in table space" because there isn't any +-- free space available to accomodate the new table. +CREATE TABLE tab_auto3 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_auto; + +! echo "Above error is expected !"; + +-- Perform REDUCE on 'tbsp_auto'. This will fail with an error: +-- "The table space could not be reduced in size". +-- Table space cannot be reduced in size until the transaction containing the +-- DROP TABLE statements is committed. +-- After the transaction is committed, the space can be reused and new +-- tables can be created. +ALTER TABLESPACE tbsp_auto REDUCE; + +! echo "Above error is expected !"; + +-- Perform a COMMIT to permanently free extents used by the dropped tables and +-- allow the table space to be reduced in size. +-- The COMMIT will not reduce the HWM. The HWM will remain the same until a +-- REDUCE is performed on the table space. +COMMIT; + +-- Take a table space snapshot to show the HWM hasn't changed after +-- performing COMMIT. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_AUTO', -1)) AS mon_get_tablespace ; + +-- Perform REDUCE on table space 'tbsp_auto' to reduce HWM. +ALTER TABLESPACE tbsp_auto REDUCE; + +-- Take a table space snapshot to show the HWM has been reduced after +-- performing REDUCE on table space 'tbsp_auto'. +-- Pending free pages will be freed after REDUCE. After this is done, +-- creation of a new table in the table space will be successful. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_AUTO', -1)) AS mon_get_tablespace ; + +-- New tables can now be created in the table space 'tbsp_auto' since +-- space has been reclaimed by the REDUCE operation. +-- Create table 'tab_auto3'. The size of the new table should be either +-- less than, or almost the same size as, the dropped tables. +-- Table creation will now be successful. +CREATE TABLE tab_auto3 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_auto; + +-- Take a table space snapshot to show that the HWM has changed after +-- the new table was created. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_AUTO', -1)) AS mon_get_tablespace ; + +-- Drop table 'tab_auto3'. +DROP TABLE tab_auto3; + +-- Drop table space 'tbsp_auto'. +DROP TABLESPACE tbsp_auto; + +-- **************************************************************************** +-- 2. How to utilize the unused space of a table space created with DATABASE +-- MANAGED SPACE. +-- **************************************************************************** + +-- Create table space 'tbsp_dms' managed by database. +CREATE TABLESPACE tbsp_dms PAGESIZE 4096 + MANAGED BY database using (file 'mycontainer' 28) EXTENTSIZE 2 AUTORESIZE NO; + +-- Create table 'tab_1' in the table space 'tbsp_dms'. +CREATE TABLE tab_1 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_dms; + +-- Populate the table 'tab_1' with the following data. +INSERT INTO tab_1 VALUES ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' ); +INSERT INTO tab_1 (SELECT * FROM tab_1); +INSERT INTO tab_1 (SELECT * FROM tab_1); +INSERT INTO tab_1 (SELECT * FROM tab_1); + +-- Create table 'tab_2' in table space 'tbsp_auto'. +CREATE TABLE tab_2 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_dms; + +-- Populate the table with data so that the container is full. Creation of new +-- tables in the table space will fail with the error: +-- "Unable to allocate new pages in table space". +INSERT INTO tab_2 (select * from tab_1); + +-- Try creating new table 'tab_3'. It will fail with the error: +-- "Unable to allocate new pages in table space". +CREATE TABLE tab_3 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_dms; + +! echo "Above error is expected !"; + +-- Commit the transaction. +COMMIT; + +-- Take a snapshot of the table space. This gives details such as: +-- table space name, high water mark, extent size, used pages, free pages, +-- pending free pages for table space 'tbsp_dms'. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_DMS', -1)) AS mon_get_tablespace ; + +-- Drop table 'tab_2' and take a table space snapshot to show that the HWM +-- hasn't changed after dropping the table. The above and below snapshots show +-- the same value for HWM. +DROP TABLE tab_2; + +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_DMS', -1)) AS mon_get_tablespace ; + +-- Try creating new table 'tab_3'. It will fail with the error: +-- "Unable to allocate new pages in table space". +CREATE TABLE tab_3 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_dms; + +! echo "Above error is expected !"; + +-- Perform REDUCE on table space 'tbsp_dms'. This will result in the error: +-- "There is no enough space in the table space "TBSP_DMS". The amount of +-- space being removed is greater than the amount of space above the +-- high-water mark". The error occurs because the transaction has not been +-- committed and there isn't any free space on which to perform a REDUCE +-- statement. +ALTER TABLESPACE tbsp_dms REDUCE (FILE 'mycontainer' 3); + +! echo "Above error is expected !"; + +-- Perform COMMIT to make the free space available and allow the table +-- space to be reduced in size. +-- COMMIT will not reduce the HWM. The HWM will remain the same until a +-- REDUCE is performed on the table space. +COMMIT; + +-- Take a table space snapshot to show the HWM hasn't changed after +-- performing COMMIT. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_DMS', -1)) AS mon_get_tablespace ; + +-- Perform REDUCE on the table space 'tbsp_dms' to reduce the HWM and +-- to free pending pages. +ALTER TABLESPACE tbsp_dms REDUCE (FILE 'mycontainer' 3); + +-- Take a table space snapshot to show the HWM has been reduceed after +-- performing a REDUCE on table space 'tbsp_dms'. +-- Pending free pages will be freed after a REDUCE. After this is done, +-- creation of a new table in the table space will be successful. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_DMS', -1)) AS mon_get_tablespace ; + +-- Create table 'tab_3'. The size of the table should be either +-- less than, or almost the same size as, the dropped table. +-- Table creation will now be successful. +CREATE TABLE tab_3 ( c1 char( 250 ),c2 char( 250 ),c3 char( 250 ), + c4 char( 250 ),c5 char( 250 ),c6 char( 250 ), + c7 char( 250 ),c8 char( 250 ),c9 char( 250 ), + c10 char( 250 ) ) + IN tbsp_dms; + +-- Take a table space snapshot to show that the HWM has changed after +-- the new table was created. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_DMS', -1)) AS mon_get_tablespace ; + +-- Drop table 'tab_1' +DROP TABLE tab_1; + +-- Commit the transaction. +COMMIT; + +-- Perform REDUCE on table space 'tbsp_dms'. +ALTER TABLESPACE tbsp_dms REDUCE (FILE 'mycontainer' 3); + +-- Take a table space snapshot to show that the HWM has not been reduced and +-- is the same as in the previous table space snapshot. The HWM will not be +-- reduced because it is held static by table 'tab_3'. So before table 'tab_1' +-- is dropped, table 'tab_3' needs to be dropped. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_DMS', -1)) AS mon_get_tablespace ; + +-- Drop table 'tab_3'. +DROP TABLE tab_3; + +-- Commit the transaction. +COMMIT; + +-- Perform REDUCE on table space 'tbsp_dms'. +ALTER TABLESPACE tbsp_dms REDUCE (FILE 'mycontainer' 3); + +-- Take a table space snapshot to show that the HWM has been reduced after table +-- 'tab_3' was dropped. +SELECT SUBSTR (tbsp_name, 1, 10) AS TBSP_NAME, + tbsp_page_top, tbsp_extent_size, tbsp_used_pages, + tbsp_free_pages, tbsp_pending_free_pages + FROM TABLE (mon_get_tablespace ('TBSP_DMS', -1)) AS mon_get_tablespace ; + +-- Drop table space 'tbsp_dms'. +DROP TABLESPACE tbsp_dms; + +-- Disconnect from database. +CONNECT RESET; + +-- Drop database. +DROP DB testdb1; +TERMINATE; diff --git a/admin_scripts/wlmtiersdefault.db2 b/admin_scripts/wlmtiersdefault.db2 new file mode 100644 index 0000000..94a484e --- /dev/null +++ b/admin_scripts/wlmtiersdefault.db2 @@ -0,0 +1,240 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: wlmtiersdefault.db2 +-- +-- SAMPLE: This script sets up a DB2 Workload Manager (WLM) tiered service +-- class configuration for a database. Use this tiered service class +-- configuration to implement priority aging to help improve database +-- throughput. Priority aging decreases the priority of incoming +-- activities in response to the processing time used (CPU). +-- This script also demonstrates the use of service classes, workloads +-- and thresholds. +-- +-- ************************************************************************* +-- NOTE: This script enables WLM Dispatcher and CPU Shares for the instance. +-- ************************************************************************* +-- +-- Actions performed by this script: +-- +-- 1. Create the service superclass WLM_TIERS and three service subclasses +-- within it, WLM_SHORT, WLM_MEDIUM and WLM_LONG. +-- +-- 2. Create the threshold WLM_TIERS_REMAP_SHORT_TO_MEDIUM to remap +-- activities from service subclass WLM_SHORT to WLM_MEDIUM after +-- activities consume a certain amount of processor time in WLM_SHORT. +-- Create threshold WLM_TIERS_REMAP_MEDIUM_TO_LONG to remap +-- activities from service subclass WLM_MEDIUM to WLM_LONG as +-- activities consume a certain amount of processor time in WLM_MEDIUM. +-- For activities that cannot be remapped using a CPUTIMEINSC threshold +-- are mapped to the WLM_MEDIUM service subclass. These activities +-- will stay in the WLM_MEDIUM service subclass and will not get +-- remapped. +-- +-- 3. Set the service class properties for the service classes created. +-- For service class properties and instructions on how to modify these +-- properties to suit your environment, see the next section. +-- +-- 4. Set the threshold properties for the thresholds created. For +-- threshold properties and instructions on how to modify these +-- properties to suit your environment, see the next section. +-- +-- 5. Alter the default user workload SYSDEFAULTUSERWORKLOAD to map +-- incoming connections to the service subclass WLM_SHORT. Any +-- connection that does not belong to a user defined workload is placed +-- in SYSDEFAULTUSERWORKLOAD. +-- +-- How the tiered service class configuration works: Service class WLM_SHORT has +-- higher resource priority settings than WLM_MEDIUM, which has higher resource +-- priority settings than WLM_LONG. All activities enter service class WLM_SHORT +-- where they will complete unless they exceed the maximum amount of processor +-- time specified with the threshold WLM_TIERS_REMAP_SHORT_TO_MEDIUM. Longer +-- running activities are remapped to WLM_MEDIUM where they will complete unless +-- they exceed the maximum amount of processor time specified with the threshold +-- WLM_TIERS_REMAP_MEDIUM_TO_LONG. The longest running activities are remapped +-- to WLM_LONG, where they will execute until they complete. +----------------------------------------------------------------------------- +-- +-- WLM TIERS SERVICE CLASS AND THRESHOLD PROPERTIES +-- +-- Following are the service class and threshold properties set by this script. +-- You can modify the service class and threshold properties to suit your +-- environment; search for the '#PROPERTY#' tag in this script to identify where +-- service class and threshold properties are set. Update the properties and +-- rerun this script for your new properties to take effect. +-- +-- Note: Repeat runs of this script will result in the SQL0601N message for the +-- CREATE SERVICE CLASS and CREATE THRESHOLD DDL statements. This is expected +-- since the service classes and thresholds have already been created. +-- +-- Service class properties: +-- +-- Service Class CPU Shares Prefetch Priority +-- (hard) +-- ----------------------------------------------- +-- WLM_SHORT 6000 High +-- WLM_MEDIUM 3000 Medium +-- WLM_LONG 1000 Low +-- Default System default High +-- Default Maint. default Low +-- +-- Threshold properties: +-- +-- Threshold CPU Time Used in Service +-- Class Before Remap +-- ---------------------------------------------------------- +-- WLM_TIERS_REMAP_SHORT_TO_MEDIUM 10 seconds +-- WLM_TIERS_REMAP_MEDIUM_TO_LONG 10 seconds +-- +----------------------------------------------------------------------------- +-- +-- USAGE +-- +-- 1. Connect to your database at the catalog partition. You must connect +-- at the catalog partition for this script to run successfully. +-- You must have DBADM or WLMADM authority. +-- +-- 2. In order to capture threshold violation events, create WLM event +-- monitors using the wlmevmon.ddl script in sqllib/misc directory. +-- +-- 3. Use the following command to execute this script. This sample uses +-- @ as the delimiting character. +-- +-- db2 -td@ -vf wlmtiersdefault.db2 +-- +-- 4. Reset the connection. +-- +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on the SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Enable WLM Dispatcher and CPU Shares +UPDATE DBM CFG USING WLM_DISPATCHER YES WLM_DISP_CPU_SHARES YES@ + + +-- Create service superclass WLM_TIERS +CREATE SERVICE CLASS WLM_TIERS@ + + +-- Create service subclasses WLM_SHORT, WLM_MEDIUM, WLM_LONG +CREATE SERVICE CLASS WLM_SHORT UNDER WLM_TIERS@ + +CREATE SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS@ + +CREATE SERVICE CLASS WLM_LONG UNDER WLM_TIERS@ + + +-- Create thresholds to remap activities from WLM_SHORT to WLM_MEDIUM +-- to WLM_LONG service subclasses based on processor time used in service class +CREATE THRESHOLD WLM_TIERS_REMAP_SHORT_TO_MEDIUM FOR + SERVICE CLASS WLM_SHORT UNDER WLM_TIERS ACTIVITIES + ENFORCEMENT DATABASE PARTITION WHEN + CPUTIMEINSC > 10 SECONDS CHECKING EVERY 5 SECONDS + REMAP ACTIVITY TO WLM_MEDIUM@ + +CREATE THRESHOLD WLM_TIERS_REMAP_MEDIUM_TO_LONG FOR + SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS ACTIVITIES + ENFORCEMENT DATABASE PARTITION WHEN + CPUTIMEINSC > 10 SECONDS CHECKING EVERY 5 SECONDS + REMAP ACTIVITY TO WLM_LONG@ + + +-- Create work class set WLM_TIERS_WCS to identify activities +-- that can be remapped by CPUTIMEINSC threshold. +CREATE WORK CLASS SET WLM_TIERS_WCS + ( WORK CLASS WLM_DML_WC WORK TYPE DML, + WORK CLASS WLM_CALL_WC WORK TYPE CALL, + WORK CLASS WLM_OTHER_WC WORK TYPE ALL )@ + +-- Create work action set WLM_TIERS_WAS to map activities that +-- can be remapped by CPUTIMEINSC threshold to service subclass +-- WLM_SHORT. All other activities are mapped to service subclass +-- WLM_MEDIUM and will not get remapped. +CREATE WORK ACTION SET WLM_TIERS_WAS FOR SERVICE CLASS WLM_TIERS + USING WORK CLASS SET WLM_TIERS_WCS + ( WORK ACTION WLM_DML_WA ON WORK CLASS WLM_DML_WC + MAP ACTIVITY TO WLM_SHORT, + WORK ACTION WLM_CALL_WA ON WORK CLASS WLM_CALL_WC + MAP ACTIVITY TO WLM_SHORT, + WORK ACTION WLM_OTHER_WC ON WORK CLASS WLM_OTHER_WC + MAP ACTIVITY TO WLM_MEDIUM )@ + + +-- #PROPERTY# Set CPU shares for service classes. +ALTER SERVICE CLASS WLM_SHORT UNDER WLM_TIERS CPU SHARES 6000@ + +ALTER SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS CPU SHARES 3000@ + +ALTER SERVICE CLASS WLM_LONG UNDER WLM_TIERS CPU SHARES 1000@ + + +-- #PROPERTY# Set prefetch priority for service classes. Valid values for +-- prefetch priority are HIGH, MEDIUM, LOW or DEFAULT (MEDIUM). +ALTER SERVICE CLASS SYSDEFAULTSYSTEMCLASS PREFETCH PRIORITY HIGH@ + +ALTER SERVICE CLASS SYSDEFAULTMAINTENANCECLASS PREFETCH PRIORITY LOW@ + +ALTER SERVICE CLASS WLM_SHORT UNDER WLM_TIERS PREFETCH PRIORITY HIGH@ + +ALTER SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS PREFETCH PRIORITY MEDIUM@ + +ALTER SERVICE CLASS WLM_LONG UNDER WLM_TIERS PREFETCH PRIORITY LOW@ + + +-- #PROPERTY# Set the maximum in service class processor time before +-- remapping and the checking period. The maximum in service class processor +-- time determines how much processor time an activity can consume in +-- a service class before being remapped to the target service class. +-- For example, if you want an activity to remain in service class +-- WLM_SHORT for a shorter period before being remapped to WLM_MEDIUM, +-- decrease the CPUTIMEINSC threshold value for WLM_TIERS_REMAP_SHORT_TO_MEDIUM. +-- The checking period determines how long to wait between checks for threshold +-- violation. For serial ESE instances, set the checking period to be +-- the same as the processor time before remap. For DPF or SMP instances, +-- set a lower value for the checking period than the processor time +-- before remap. +-- +-- When one of these thresholds is violated and an activity is remapped +-- to the next service subclass, an event monitor record is written to +-- the threshold violations event monitor. This way, you can see +-- how many activities are moved between the tiers service subclasses. +-- Logging an event monitor record incurs a small performance cost. Once +-- the system is tuned and the threshold violation event monitor records +-- are no longer needed, simply remove the 'LOG EVENT MONITOR RECORD' +-- clause from the ALTER THRESHOLD statements. +ALTER THRESHOLD WLM_TIERS_REMAP_SHORT_TO_MEDIUM WHEN + CPUTIMEINSC > 10 SECONDS CHECKING EVERY 5 SECONDS + REMAP ACTIVITY TO WLM_MEDIUM LOG EVENT MONITOR RECORD@ + +ALTER THRESHOLD WLM_TIERS_REMAP_MEDIUM_TO_LONG WHEN + CPUTIMEINSC > 10 SECONDS CHECKING EVERY 5 SECONDS + REMAP ACTIVITY TO WLM_LONG LOG EVENT MONITOR RECORD@ + + +-- Alter SYSDEFAULTUSERWORKLOAD to map workload to WLM_TIERS service class +ALTER WORKLOAD SYSDEFAULTUSERWORKLOAD SERVICE CLASS WLM_TIERS@ diff --git a/admin_scripts/wlmtiersdrop.db2 b/admin_scripts/wlmtiersdrop.db2 new file mode 100644 index 0000000..1c0b747 --- /dev/null +++ b/admin_scripts/wlmtiersdrop.db2 @@ -0,0 +1,119 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: wlmtiersdrop.db2 +-- +-- SAMPLE: This script drops all DB2 Workload Manager (WLM) service classes, +-- thresholds, workloads, work class sets and work action sets that are +-- created by wlmtiersdefault.db2 or wlmtierstimerons.db2. +-- +-- Actions performed by this script: +-- +-- 1. Alter workload SYSDEFAULTUSERWORKLOAD to map to service +-- class SYSDEFAULTUSERCLASS. +-- +-- 2. Disable service classes WLM_SHORT, WLM_MEDIUM, WLM_LONG and +-- WLM_TIERS. +-- +-- 3. Alter service class properties of SYSDEFAULTSYSTEMCLASS, +-- SYSDEFAULTMAINTENANCECLASS and SYSDEFAULTUSERCLASS back to default. +-- +-- 4. Drop work action set WLM_TIERS_WAS. +-- +-- 5. Drop work class set WLM_TIERS_WCS. +-- +-- 6. Drop all CPUTIMEINSC thresholds. +-- +-- 7. Drop service classes WLM_SHORT, WLM_MEDIUM, WLM_LONG and +-- WLM_TIERS. +-- +----------------------------------------------------------------------------- +-- +-- USAGE +-- +-- 1. Connect to your database. You must have DBADM or WLMADM authority. +-- +-- 2. Use the following command to execute this script. This sample uses +-- @ as the delimiting character. +-- +-- db2 -td@ -vf wlmtiersdrop.db2 +-- +-- 3. Reset the connection. +-- +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on the SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Map workload SYSDEFAULTUSERWORKLOAD back to service class +-- SYSDEFAULTUSERCLASS +ALTER WORKLOAD SYSDEFAULTUSERWORKLOAD SERVICE CLASS SYSDEFAULTUSERCLASS@ + + +-- Disable service classes WLM_SHORT, WLM_MEDIUM, WLM_LONG and WLM_TIERS +ALTER SERVICE CLASS WLM_SHORT UNDER WLM_TIERS DISABLE@ + +ALTER SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS DISABLE@ + +ALTER SERVICE CLASS WLM_LONG UNDER WLM_TIERS DISABLE@ + +ALTER SERVICE CLASS WLM_TIERS DISABLE@ + + +-- Drop work action set WLM_TIERS_WAS +DROP WORK ACTION SET WLM_TIERS_WAS@ + + +-- Drop work class set WLM_TIERS_WCS +DROP WORK CLASS SET WLM_TIERS_WCS@ + + +-- Drop remapping thresholds WLM_TIERS_REMAP_SHORT_TO_MEDIUM and +-- WLM_TIERS_REMAP_MEDIUM_TO_LONG. +DROP THRESHOLD WLM_TIERS_REMAP_SHORT_TO_MEDIUM@ + +DROP THRESHOLD WLM_TIERS_REMAP_MEDIUM_TO_LONG@ + + +-- Drop service classes WLM_SHORT, WLM_MEDIUM, WLM_LONG and +-- WLM_TIERS. +DROP SERVICE CLASS WLM_SHORT UNDER WLM_TIERS@ + +DROP SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS@ + +DROP SERVICE CLASS WLM_LONG UNDER WLM_TIERS@ + +DROP SERVICE CLASS WLM_TIERS@ + + +-- Reset prefetch priority for default service superclasses. + +ALTER SERVICE CLASS SYSDEFAULTSYSTEMCLASS + PREFETCH PRIORITY DEFAULT@ + +ALTER SERVICE CLASS SYSDEFAULTMAINTENANCECLASS + PREFETCH PRIORITY DEFAULT@ diff --git a/admin_scripts/wlmtierstimerons.db2 b/admin_scripts/wlmtierstimerons.db2 new file mode 100644 index 0000000..3087caa --- /dev/null +++ b/admin_scripts/wlmtierstimerons.db2 @@ -0,0 +1,293 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: wlmtierstimerons.db2 +-- +-- SAMPLE: This script sets up a DB2 Workload Manager (WLM) tiered service +-- class configuration for a database. Use this tiered service class +-- configuration to implement priority aging to help improve database +-- throughput. Priority aging decreases the priority of incoming +-- activities in response to the processing time used (CPU). +-- This script also demonstrates the use of service classes, workloads, +-- work action sets and thresholds. This script differs from +-- wlmtiersdefault.db2 in that the estimated cost is taken into account +-- when initially mapping DML activities to service classes. +-- +-- ************************************************************************* +-- NOTE: This script enables WLM Dispatcher and CPU Shares for the instance. +-- ************************************************************************* +-- +-- Actions performed by this script: +-- +-- 1. Create the service superclass WLM_TIERS and three service subclasses +-- within it, WLM_SHORT, WLM_MEDIUM and WLM_LONG. +-- +-- 2. Create threshold WLM_TIERS_REMAP_SHORT_TO_MEDIUM to remap +-- activities from service subclass WLM_SHORT to WLM_MEDIUM after +-- activities consume a certain amount of processor time in WLM_SHORT. +-- Create threshold WLM_TIERS_REMAP_MEDIUM_TO_LONG to remap +-- activities from service subclass WLM_MEDIUM to WLM_LONG after +-- activities consume a certain amount of processor time in WLM_MEDIUM. +-- For activities that cannot be remapped using a CPUTIMEINSC threshold +-- are mapped to the WLM_MEDIUM service subclass. These activities +-- will stay in the WLM_MEDIUM service subclass and will not get +-- remapped. +-- +-- 3. Create work class set WLM_TIERS_WCS to differentiate DML activities +-- with small, medium and large estimated costs in timerons. +-- +-- 4. Create work action set WLM_TIERS_WAS to map the work classes in +-- WLM_TIERS_WCS to service classes WLM_SHORT, WLM_MEDIUM and +-- WLM_LONG. +-- +-- 5. Set the service class properties for the service classes created. +-- For service class properties and instructions on how to modify these +-- properties to suit your environment, see the next section. +-- +-- 6. Set the threshold properties for the thresholds created. For +-- threshold properties and instructions on how to modify these +-- properties to suit your environment, see the next section. +-- +-- 7. Set work class properties for the work class set created. For +-- work class set properties and instructions on how to customize the +-- threshold properties to suit your environment, see the next section. +-- +-- 8. Alter the the default user workload SYSDEFAULTUSERWORKLOAD to map +-- incoming connections to service class WLM_TIERS. Any connection that +-- does not belong to a user defined workload is placed in +-- SYSDEFAULTUSERWORKLOAD. +-- +-- With this configuration, DML activities are evaluated based on their +-- estimated cost and placed into service class WLM_SHORT, WLM_MEDIUM or +-- WLM_LONG accordingly. Service class WLM_SHORT has higher resource priority +-- settings than WLM_MEDIUM, which has higher resource priority settings than +-- WLM_LONG. Non-DML activities enter service class WLM_SHORT. Short activities +-- will complete in WLM_SHORT unless they exceed the maximum amount of processor +-- time specified in threshold WLM_TIERS_REMAP_SHORT_TO_MEDIUM. Longer +-- activities are remapped to WLM_MEDIUM where they will complete unless they +-- exceed the maximum amount of CPU time specified in threshold +-- WLM_TIERS_REMAP_MEDIUM_TO_LONG. The longest running activities are remapped +-- to WLM_LONG, where they will execute until they complete. +----------------------------------------------------------------------------- +-- +-- WLM TIERS SERVICE CLASS, THRESHOLD AND WORK CLASS SET PROPERTIES +-- +-- Following are the service class, threshold and work class set properties set +-- by this script. You can customize these properties to better fit your +-- environment; search for the '#PROPERTY#' tag in this script to identify where +-- service class, threshold and work class set properties are set. Update the +-- properties and rerun this script for your new properties to take effect. +-- +-- Note: Repeat runs of this script will return the SQL0601N message for the +-- CREATE SERVICE CLASS, CREATE THRESHOLD and CREATE WORK CLASS SET DDL +-- statements. Repeat runs will also return the SQL4704N message for the CREATE +-- WORK ACTION SET statement. This is expected because these WLM objects are +-- already created. +-- +-- Service class properties: +-- +-- Service Class CPU Shares Prefetch Priority +-- (hard) +-- ----------------------------------------------- +-- WLM_SHORT 6000 High +-- WLM_MEDIUM 3000 Medium +-- WLM_LONG 1000 Low +-- Default System default High +-- Default Maint. default Low +-- +-- Threshold properties: +-- +-- Threshold CPU Time Used in Service +-- Class Before Remap +-- ---------------------------------------------------------- +-- WLM_TIERS_REMAP_SHORT_TO_MEDIUM 10 seconds +-- WLM_TIERS_REMAP_MEDIUM_TO_LONG 10 seconds +-- +-- Work class set properties: +-- +-- Work Class Estimated Cost in +-- Timerons (From/To) +-- ------------------------------------ +-- WLM_SHORT_DML_WC 0/1000 +-- WLM_MEDIUM_DML_WC >1000/100000 +-- WLM_LONG_DML_WC >100000/infinity +-- WLM_CALL_WC *see note below* +-- WLM_OTHER_WC *see note below* +-- +-- Note: +-- Work classes WLM_CALL_WC and WLM_OTHER_WC contain CALL activities and other +-- activities that do not have cost estimates. Estimated cost is available +-- only for DML statements. Non-DML activities such as DDL and LOAD will fall +-- under the WLM_OTHER_WC work class. Activities grouped under WLM_CALL_WC are +-- mapped to service class WLM_SHORT initially. Activities grouped under +-- WLM_OTHER_WC are mapped to service class WLM_MEDIUM and will not get +-- remapped. +----------------------------------------------------------------------------- +-- +-- USAGE +-- +-- 1. Connect to your database at the catalog partition. You must connect +-- at the catalog partition for this script to run successfully. +-- You must have DBADM or WLMADM authority. +-- +-- 2. In order to capture threshold violation events, create WLM event +-- monitors using the wlmevmon.ddl script in sqllib/misc directory. +-- +-- 3. Use the following command to execute this script. This sample uses +-- @ as the delimiting character. +-- +-- db2 -td@ -vf wlmtierstimerons.db2 +-- +-- 4. Reset the connection. +-- +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on the SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Enable WLM Dispatcher and CPU Shares +UPDATE DBM CFG USING WLM_DISPATCHER YES WLM_DISP_CPU_SHARES YES@ + + +-- Create service superclass WLM_TIERS +CREATE SERVICE CLASS WLM_TIERS@ + + +-- Create service subclasses WLM_SHORT, WLM_MEDIUM, WLM_LONG +CREATE SERVICE CLASS WLM_SHORT UNDER WLM_TIERS@ + +CREATE SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS@ + +CREATE SERVICE CLASS WLM_LONG UNDER WLM_TIERS@ + + +-- Create thresholds to remap activities from WLM_SHORT to WLM_MEDIUM +-- to WLM_LONG service subclasses based on processor time used in service class +CREATE THRESHOLD WLM_TIERS_REMAP_SHORT_TO_MEDIUM FOR + SERVICE CLASS WLM_SHORT UNDER WLM_TIERS ACTIVITIES + ENFORCEMENT DATABASE PARTITION WHEN + CPUTIMEINSC > 10 SECONDS CHECKING EVERY 5 SECONDS + REMAP ACTIVITY TO WLM_MEDIUM@ + +CREATE THRESHOLD WLM_TIERS_REMAP_MEDIUM_TO_LONG FOR + SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS ACTIVITIES + ENFORCEMENT DATABASE PARTITION WHEN + CPUTIMEINSC > 10 SECONDS CHECKING EVERY 5 SECONDS + REMAP ACTIVITY TO WLM_LONG@ + + +-- Create work class set WLM_TIERS_WCS +CREATE WORK CLASS SET WLM_TIERS_WCS + ( WORK CLASS WLM_SHORT_DML_WC WORK TYPE DML, + WORK CLASS WLM_MEDIUM_DML_WC WORK TYPE DML, + WORK CLASS WLM_LONG_DML_WC WORK TYPE DML, + WORK CLASS WLM_CALL_WC WORK TYPE CALL, + WORK CLASS WLM_OTHER_WC WORK TYPE ALL)@ + + +-- Create work action set WLM_TIERS_WAS to map activities grouped under +-- each work class in work class set WLM_TIERS_WCS to the corresponding +-- service subclass. +CREATE WORK ACTION SET WLM_TIERS_WAS FOR SERVICE CLASS WLM_TIERS + USING WORK CLASS SET WLM_TIERS_WCS + ( WORK ACTION WLM_SHORT_DML_WA ON WORK CLASS WLM_SHORT_DML_WC + MAP ACTIVITY TO WLM_SHORT, + WORK ACTION WLM_MEDIUM_DML_WA ON WORK CLASS WLM_MEDIUM_DML_WC + MAP ACTIVITY TO WLM_MEDIUM, + WORK ACTION WLM_LONG_DML_WA ON WORK CLASS WLM_LONG_DML_WC + MAP ACTIVITY TO WLM_LONG, + WORK ACTION WLM_CALL_WA ON WORK CLASS WLM_CALL_WC + MAP ACTIVITY TO WLM_SHORT, + WORK ACTION WLM_OTHER_WA ON WORK CLASS WLM_OTHER_WC + MAP ACTIVITY TO WLM_MEDIUM )@ + + +-- #PROPERTY# Set CPU shares for service classes. +ALTER SERVICE CLASS WLM_SHORT UNDER WLM_TIERS CPU SHARES 6000@ + +ALTER SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS CPU SHARES 3000@ + +ALTER SERVICE CLASS WLM_LONG UNDER WLM_TIERS CPU SHARES 1000@ + + +-- #PROPERTY# Set prefetch priority for service classes. Valid values for +-- prefetch priority are HIGH, MEDIUM, LOW or DEFAULT (MEDIUM). +ALTER SERVICE CLASS SYSDEFAULTSYSTEMCLASS PREFETCH PRIORITY HIGH@ + +ALTER SERVICE CLASS SYSDEFAULTMAINTENANCECLASS PREFETCH PRIORITY LOW@ + +ALTER SERVICE CLASS WLM_SHORT UNDER WLM_TIERS PREFETCH PRIORITY HIGH@ + +ALTER SERVICE CLASS WLM_MEDIUM UNDER WLM_TIERS PREFETCH PRIORITY MEDIUM@ + +ALTER SERVICE CLASS WLM_LONG UNDER WLM_TIERS PREFETCH PRIORITY LOW@ + + +-- #PROPERTY# Set the maximum in service class processor time before +-- remapping and the checking period. The maximum in service class processor +-- time determines how much processor time an activity can consume in +-- a service class before being remapped to the target service class. +-- For example, if you want an activity to remain in service class +-- WLM_SHORT for a shorter period before being remapped to WLM_MEDIUM, +-- decrease the CPUTIMEINSC threshold value for WLM_TIERS_REMAP_SHORT_TO_MEDIUM. +-- The checking period determines how long to wait between checks for threshold +-- violation. For serial ESE instances, set the checking period to be +-- the same as the processor time before remap. For DPF or SMP instances, +-- set a lower value for the checking period than the processor time +-- before remap. +-- +-- When one of these thresholds is violated and an activity is remapped +-- to the next service subclass, an event monitor record is written to +-- the threshold violations event monitor. This way, you can see +-- how many activities are moved between the tiers service subclasses. +-- Logging an event monitor record incurs a small performance cost. Once +-- the system is tuned and the threshold violation event monitor records +-- are no longer needed, simply remove the 'LOG EVENT MONITOR RECORD' +-- clause from the ALTER THRESHOLD statements. +ALTER THRESHOLD WLM_TIERS_REMAP_SHORT_TO_MEDIUM WHEN + CPUTIMEINSC > 10 SECONDS CHECKING EVERY 5 SECONDS + REMAP ACTIVITY TO WLM_MEDIUM LOG EVENT MONITOR RECORD@ + +ALTER THRESHOLD WLM_TIERS_REMAP_MEDIUM_TO_LONG WHEN + CPUTIMEINSC > 10 SECONDS CHECKING EVERY 5 SECONDS + REMAP ACTIVITY TO WLM_LONG LOG EVENT MONITOR RECORD@ + + +-- #PROPERTY# Set work class properties for work class set WLM_TIERS_WCS. +-- This setting determines the initial mapping of DML activites to the +-- service subclasses based on estimated cost. For example, if you want +-- DML activities with a higher estimated cost to map to service class +-- WLM_SHORT instead of WLM_MEDIUM initially, increase the TO value of +-- WLM_SHORT_DML_WC and decrease the corresponding FROM value of WLM_MEDIUM_DML_WC. +ALTER WORK CLASS SET WLM_TIERS_WCS + ALTER WORK CLASS WLM_SHORT_DML_WC FOR TIMERONCOST FROM 0 TO 1000 + ALTER WORK CLASS WLM_MEDIUM_DML_WC FOR TIMERONCOST FROM 1000 TO 100000 + ALTER WORK CLASS WLM_LONG_DML_WC FOR TIMERONCOST FROM 100000 TO UNBOUNDED@ + + +-- Alter SYSDEFAULTUSERWORKLOAD to map workload to WLM_TIERS service class +ALTER WORKLOAD SYSDEFAULTUSERWORKLOAD SERVICE CLASS WLM_TIERS@ diff --git a/autoloader/loadFtpFtc.pl b/autoloader/loadFtpFtc.pl new file mode 100644 index 0000000..e8bc65c --- /dev/null +++ b/autoloader/loadFtpFtc.pl @@ -0,0 +1,329 @@ +: # -*-Perl-*- +eval 'exec perl -S $0 ${1+"$@"}' +if 0; + +################################################################################ +# +# Description: DPF LOAD sample driver for remote file transfer. +# +# (C) COPYRIGHT International Business Machines Corp. 2005 +# All Rights Reserved +# Licensed Materials - Property of IBM +# +# US Government Users Restricted Rights - Use, duplication or +# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# +# +# DISCLAIMER : +# This sample DPF LOAD utility file transfer command is distributed as is, +# it is not officially supported by IBM, and it may have to be modified +# to work in all environments supported by DB2 UDB. +# +# +# PLEASE NOTE : The load file transfer command is executed from the +# database partition that is coordinating the load. It should also be +# noted that it is executed under the instance owner's user id. +# Therefore, the .netrc file required must exist under the instance +# owner's home directory. This also means that only environment +# variables set for the instance owner can be inherited by the load +# file transfer command. +# +# +# NOTE TO WINDOWS USERS : Some Windows FTP clients do not support the +# .netrc file. In that case ftp->login() command in the ftp subroutine +# has to be modified to include the correct user ID and password. +# +# +# This script expects the following input: +# +# +# +# Where: +# +# A writable log path for generating any diagnostics. +# +# +# The name of the remote host where the remote media (files) reside. +# +# +# A base pipename representing a location where the contents of +# each source file should be written. It is expected that there is a +# pipe for each source media (file), and that each pipe has a name +# of the form .nnn where "nnn" is the index of the +# source media. "nnn" must always be 3 characters, and is 0 indexed, +# such that the pipe names for the first 3 files would have the +# following form: +# .000 +# .001 +# .002 +# +# +# The number of remote media (files) to be transfered. +# +# +# The actual names of the remote media (files), fully qualified. +# +################################################################################ + +use Net::FTP; + +use POSIX ":sys_wait_h"; + +# Some control variables +# +# Set '$binary = 0' to perform ASCII FTP, binary FTP is the default. +# Set '$mvsdataset = 1' if the source data is a zOS dataset. +# Set '$parallel = 0' to disable parallel FTP for multiple input sources +# + +$binary = 1; +$mvsdataset = 0; +$parallel = 1; + +$logpath = ""; + +if (scalar(@ARGV) >= 1) +{ + $logpath = $ARGV[0] . "/"; +} + +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + +$logfile = $logpath . "loadFtpFtc." . ($year + 1900) . $mon . $day . $hour . $min . $sec . ".log"; + +open(LOGFILE, ">$logfile") || exit(-1); + +if (scalar(@ARGV) < 4) +{ + &log("$0 wrong number args\n"); + + for ($i = 0; $i < scalar(@ARGV); ++$i) + { + &log("$0 \$ARGV[" . $i . "] = '" . $ARGV[$i] . "'\n"); + } + + exit -1; +} + +# Input variables +# +$logpath = $ARGV[0]; +$hostname = $ARGV[1]; +$basepipename = $ARGV[2]; +$nummedia = $ARGV[3]; + +&log("\$binary($binary) \$mvsdataset($mvsdataset) \$parallel($parallel)\n"); + +for ($i = 0; $i < scalar(@ARGV); ++$i) +{ + &log("\$ARGV[$i]($ARGV[$i])\n"); +} + +# Advance the argument list so it points to the begining of the media +# +shift(@ARGV); +shift(@ARGV); +shift(@ARGV); +shift(@ARGV); + +# Collect the file and pipenames +# +for ($i = 0; $i < $nummedia; $i++) +{ + $pipename[$i] = $basepipename . '.' . substr(1000+$i,1,3); + + $data[$i] = $ARGV[0]; + + if ($mvsdataset) + { + $data[$i] = &basename($data[$i]); + + $data[$i] = "'" . $data[$i] . "'"; + } + + &log("\$data[$i]($data[$i])\n"); + &log("\$pipename[$i]($pipename[$i])\n"); + + shift(@ARGV); +} + +for ($i = 0; $i < $nummedia; $i++) +{ + if ($parallel) + { + if ($pid = fork()) + { + # This is parent code. Not much to do but + # store the pid so we can wait for it later. + # + $pidlist[$i] = $pid; + } + elsif (defined $pid) + { + # This is child code. + # + if (!&ftp($data[$i], $pipename[$i])) + { + exit 0; + } + + exit 1; + } + else + { + # Fork error. + # + &log("fork error for data($data[$i]) and pipe($pipename[$i])\n"); + + &log("Failure\n"); + + exit -1; + } + } + else + { + if (!&ftp($data[$i], $pipename[$i])) + { + &log("Failure\n"); + + exit -1; + } + } +} + +# Wait for the children. +# +if ($parallel) +{ + $rc = 1; + + for ($i = 0; $i < $nummedia; $i++) + { + $pid = waitpid($pidlist[$i], 0); + + $rc = $?; + + if ($pid == -1) + { + &log("wait(ftp($pidlist[$i])) returned -1\n"); + + $rc = 0; + } + else + { + if ($pid != $pidlist[$i]) + { + &log("wait(ftp($pidlist[$i])) returned \$pid($pid)\n"); + } + + $rc >>= 8; + + &log("ftp($pidlist[$i]) rc($rc)\n"); + } + } + + if (!$rc) + { + &log("Failure\n"); + + exit -1; + } +} + +&log("Success\n"); + +exit 0; + +# Do the ftp +# +sub ftp +{ + my ($data, $pipename) = @_; + + &log("ftp: ftping $data into $pipename on $hostname\n"); + + $rc = 1; + + if ($ftp = Net::FTP->new($hostname)) + { + if (!$ftp->login()) + { + $msg = "$hostname: ".$ftp->message(); + + chop($msg); + + &log("ftp: Cannot login to $msg\n"); + + $rc = 0; + } + else + { + if ($binary) + { + $ftp->binary(); + } + + if (!$ftp->get($data, $pipename)) + { + $msg = $ftp->message(); + + chop($msg); + + &log("ftp: get failed($msg)\n"); + + $rc = 0; + } + else + { + &log("ftp: get succeeded($data)\n"); + } + } + $ftp->quit(); + } + else + { + if (defined($ftp)) + { + $msg = $ftp->message(); + + chop($msg); + + &log("ftp: Cannot connect to $hostname($msg)\n"); + } + else + { + &log("ftp: Cannot connect to $hostname($@)\n"); + } + + $rc = 0; + } + + if ($parallel) + { + exit $rc; + } + else + { + return $rc; + } +} + +sub log +{ + my ($str) = @_; + + flock(LOGFILE, 2); + + print(LOGFILE $str); + + flock(LOGFILE, 8); +} + +sub basename +{ + my ($path) = @_; + + @parts = split(/[\\\/]/, $path); + + return $parts[scalar(@parts) - 1]; +} diff --git a/automaintcfg/DB2AutoBackupPolicySample.xml b/automaintcfg/DB2AutoBackupPolicySample.xml new file mode 100644 index 0000000..c0ae0e8 --- /dev/null +++ b/automaintcfg/DB2AutoBackupPolicySample.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automaintcfg/DB2AutoReorgPolicySample.xml b/automaintcfg/DB2AutoReorgPolicySample.xml new file mode 100644 index 0000000..33025c3 --- /dev/null +++ b/automaintcfg/DB2AutoReorgPolicySample.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/automaintcfg/DB2AutoRunstatsPolicySample.xml b/automaintcfg/DB2AutoRunstatsPolicySample.xml new file mode 100644 index 0000000..c3e54da --- /dev/null +++ b/automaintcfg/DB2AutoRunstatsPolicySample.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + diff --git a/automaintcfg/DB2MaintenanceWindowPolicySample.xml b/automaintcfg/DB2MaintenanceWindowPolicySample.xml new file mode 100644 index 0000000..a2a6c5e --- /dev/null +++ b/automaintcfg/DB2MaintenanceWindowPolicySample.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + All + All + All + + + + + + + + + + diff --git a/c/README b/c/README new file mode 100644 index 0000000..6197906 --- /dev/null +++ b/c/README @@ -0,0 +1,420 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for C Samples on Linux +* +* The /sqllib/samples/c directory contains this README file +* where is the location of DB2 9.7 on your hard drive. +* The default location for for Linux is $HOME. +* This README describes how to build and run C sample code for DB2 9.7. +* +* The DB2 9.7 sample code for C is located in the following directory: +* /sqllib/samples/c +* +* It is recommended that you copy the files from this directory to your +* working directory prior to building the sample programs. The sample +* programs directory is typically read-only on most platforms and some +* samples generate temporary files. +* +* WARNING: Some of these samples may change your database or database manager +* configuration. Execute the samples against a 'test' database only, +* such as the DB2 SAMPLE database. +* +* NOTE: These samples are tested on sample database created using db2sampl. +* +****************************************************************************** +* +* Prepare your DB2 sample development environment +* +* 1) Copy the files from /sqllib/samples/c to your working +* directory and ensure that directory has write permission. +* +* 2) Start the Database Manager with the following command: +* db2start +* +* 3) Create the sample database with the following command: +* db2sampl +* +* 4) Connect to the database with the following command: +* db2 connect to sample +* +* 5) To build Stored Procedures and User Defined Functions, ensure +* that you have write permission on the /sqllib/function +* directory. +* +* 6) cd to the directory containing the files copied in Step 1. +* +****************************************************************************** +* +* Building DB2 Samples +* +* There are two ways to build DB2 samples: using a make utility or using the +* build files that are included with the DB2 sample programs. +* o To build samples using the make utility see 'BUILDING SAMPLES USING +* make UTILITY'. +* o To build samples using the build files or when you do not have a +* compatible make utility see 'BUILDING SAMPLES USING BUILD FILES'. +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING make UTILITY *** +* +* If you have a compatible make utility on your system, you can use the +* makefile provided. Such a make utility may be provided by another language +* compiler. Modify the PATH variable to include the directory containing the +* make utility. +* +* Depending on your environment, the makefile might have to be modified. +* For more details refer to the 'VARIABLES' section in the makefile. +* +* Execute the appropriate 'make' command in your working directory: +* o make - builds the sample identified by . Do not include the file extension +* for the program name. E.g. make DbAuth +* For any dependencies refer to the +* individual sample. +* o make srv - builds only samples that can be run on the +* server, including routines (stored +* procedures and User Defined Functions). +* o make rtn - builds only routines. +* o make call_rtn - builds only client programs that call +* routines. +* o make client_run - builds only programs that run completely on +* the client (not ones that call routines). +* o make all_client - builds all client samples (all programs in +* the 'call_rtn' and 'client_run' categories). +* o make all - builds all supplied sample programs +* +* NOTE: Create a database with name SAMPLE2 before running 'make all' as some +* of the samples require two databases. Create second database with the +* following commands: +* db2 connect reset -- To disconnect from sample database. +* db2 create database sample2 -- Create second database. +* db2 connect to sample -- Reconnect to sample database. +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING BUILD FILES *** +* +* As an alternative to the makefile, the build files included with the DB2 +* samples can be used to build the C sample programs. +* +* Building Standalone Samples: +* o bldapp +* - the name of the sample program without any +* extension. +* For any additional dependencies refer to the individual sample. +* +* Building and Executing Stored Procedures: +* o Build stored procedure server and copy the resulting binary file to +* the sqllib/function directory with the following command: +* bldrtn +* - Name of the sample program without any +* extension. +* o Catalog stored procedures with the following command: +* spcat +* o Build stored procedure client with the following command: +* bldapp +* - Name of the sample program without any +* extension. +* +* Building and Executing User Defined Functions: +* o Build UDF server and copy the resulting binary file to the +* sqllib/function directory with the following command: +* bldrtn +* - Name of the sample program without any +* extension. +* o Catalog User Defined Functions with the following command: +* udfcat +* o Build UDF client with the following command: +* bldapp +* - Name of the sample program without any +* extension. +* +****************************************************************************** +* +* Common file Descriptions +* +* The following are the common files for C samples. For more +* information on these files, refer to the program source files. +* +****************************************************************************** +* +* Common files +* +* README - this file! +* makefile - Makefile for all files +* +****************************************************************************** +* +* Common Utility Function files +* +* utilapi.c - Error-checking utility file for DB2 API programs. +* utilapi.h - Header file for utilapi.c. +* utilemb.sqc - Error-checking utility file for embedded SQL programs. +* utilemb.h - Header file for utilemb.sqc. +* utilsnap.c - Utility file for snapshot monitor programs: apsnap, dbsnap, +* dbsnapnew, insnap, insnapnew. +* +****************************************************************************** +* +* Shell Scripts +* +* bldapp - Builds an application program. +* bldevm - Builds the Event Monitor program. +* bldmc - Builds a multi-connection application program. +* bldmt - Builds a multi-threaded program. +* bldrtn - Builds a routine (stored procedure and UDF) program. +* embprep - Precompiles and binds embedded SQL programs. +* +****************************************************************************** +* +* Samples Design +* +* The C sample programs form an object-based design reflecting the +* component nature of DB2. Related samples demonstrate a specific level of +* database programming. Each level is identified by the first two characters +* of the sample name. Here are the levels: +* +* Identifier DB2 Level +* +* cl Client Level. +* in Instance Level. +* db Database Level. +* tb Table Level. +* ts Tablespace Level. +* dt Data Type Level. +* +****************************************************************************** +* +* Other Samples +* +* Besides the samples organized in the DB2 Level design, other samples show +* specific kinds of application methods: +* +* Identifier Application Method +* +* fn SQL functions. +* sp Stored Procedures. +* ud User Defined Functions. +* +****************************************************************************** +* +* C Sample Descriptions +* +* The following are the C sample files included with DB2. For more +* information on the sample programs, refer to the program source +* files. +* +****************************************************************************** +* +* Client Level (program files that deal with the client level of DB2) +* +* cli_info.c - How to get and set client level information. +* clisnap.c - How to get a snapshot at the client level. +* clisnapnew.c - How to get a snapshot at the client level (using API). +* +****************************************************************************** +* +* Instance Level (program files that deal with the instance level of DB2) +* +* inattach.c - How to attach to and detach from an instance. +* inauth.sqc - How to display authorities at instance level. +* ininfo.c - How to get and set instance level information. +* insnap.c - How to get a snapshot at instance level. +* insnapnew.c - How to get a snapshot at instance level (using API). +* instart.c - How to stop and start the current local instance. +* +****************************************************************************** +* +* Database Level (program files that deal with database objects in DB2) +* +* autostore.c - How to use automatic storage capability for a database. +* dbauth.sqc - How to grant/display/revoke authorities at database +* level. +* dbcfg.sqc - How to configure database and database manager +* parameters. +* dbconn.sqc - How to connect and disconnect from a database. +* dbcreate.c - How to create and drop databases. +* dbhistfile.sqc - How to read and update a database recovery file entry. +* dbinfo.c - How to get and set information at a database level. +* dbinline.sqc - How to use inline SQL Procedure Language +* dbinspec.sqc - How to check architectural integrity with the +* DB2 API db2Inspect +* dblogconn.sqc - How to read database log files asynchronously with a +* database connection for compressed and uncompressed +* tables +* dblognoconnlogmerge.c - How to read database log files asynchronously with +* no database connection and merge log streams in +* pureScale +* dbupgrade.c - How to upgrade a database. +* dbpkg.sqc - How to work with packages. +* dbredirect.sqc - How to perform Redirected Restore of a database. +* dbrestore.sqc - How to restore a database from a backup. +* dbrollfwd.sqc - How to perform rollforward after restore of a +* database. +* dbsample.sqc - How to create a sample database. +* dbsnap.c - How to get a snapshot at database level. +* dbsnapnew.c - How to get a snapshot at database level (using API). +* dbstat.c - Provide database statistics about DB2 performance. +* dbthrds.sqc - How to use threads. +* dbuse.sqc - How to use database objects. +* getlogs.sqc - How to get customer view of diagnostic log file +* entries. +* ssv_backup_db.c - How to take database backup in an MPP environment. +* ssv_backup_tbsp.sqc - How to take tablespace in an MPP environment. +* ssv_db_cfg.c - How to update db cfg parameters in an MPP environment. +* +****************************************************************************** +* +* Table Level (program files that deal with table objects in DB2) +* +* getmessage.sqc - How to get error message in the required locale with +* token replacement. The tokens can be programatically +* obtained by invoking Sqlaintp using JNI. +* globvarsupport.sqc - How to use global variables with DB2. +* implicitcasting.sqc- To demonstrate use of implicit casting. +* largerid.sqc - How to enable Large RIDs support on both new tables/ +* tablespaces and existing tables/tablespaces. +* setintegrity.sqc - How to perform online SET INTEGRITY on a table. +* tbast.sqc - How to use staging table for updating deferred AST. +* tbcompress.sqc - How to create tables with null and default value +* compression option. +* tbconstr.sqc - How to work with table constraints. +* tbselcreate.db2 - CLP script to create tables +* tbseldrop.db2 - CLP script to drop tables +* tbselinit - Script that first calls tbseldrop.db2 and then calls +* tbselcreate.db2. +* tbcreate.sqc - How to create, alter, and drop tables. +* tbident.sqc - How to use identity columns. +* tbinfo.sqc - How to get and set information at a table level. +* tbintrig.sqc - How to use INSTEAD OF triggers. +* tbload.sqc - How to load into a partitioned database. +* tbloadcursor.sqc - How to load data returned from a SELECT statement into +* a table using CURSOR method or REMOTEFETCH media method. +* tbmerge.sqc - How to use the MERGE statement. +* tbmod.sqc - How to modify information in a table. +* tbmove.sqc - How to move a table. +* tbonlineinx.sqc - How to create and reorg indexes on a table. +* tbpriv.sqc - How to grant/display/revoke privileges at a table level. +* tbread.sqc - How to read information in a table. +* tbreorg.sqc - How to reorganize a table. +* tbrowcompress.sqc - How to perform row compression on a table. +* tbrunstats.sqc - How to perform runstats on a table. +* tbsavept.sqc - How to use external savepoints +* tbsel.sqc - How to select from each of: insert, update, delete. +* tbtemp.sqc - How to use a declared temporary table +* tbtrig.sqc - How to use a trigger on a table. +* tbumqt.sqc - How to use user materialized query tables +* (summary tables). +* tbunion.sqc - How to insert through a UNION ALL view +* +****************************************************************************** +* +* Tablespace Level (program files that deal with tablespace objects in DB2) +* +* tscreate.sqc - How to create/drop bufferpools and tablespaces. +* +****************************************************************************** +* +* Data Type Level (programs that deal with data types) +* +* dtformat.sqc - How to load and import data format extensions. +* dtlob.sqc - How to read and write LOB data. +* dtudt.sqc - How to create/use/drop user defined distinct types. +* +****************************************************************************** +* +* Function Level (program files that demonstrate SQL functions) +* +* fnuse.sqc - How to use SQL functions. +* +****************************************************************************** +* +* Stored Procedure Level (program files that demonstrate stored procedures) +* +* spcreate.db2 - CLP script to issue CREATE PROCEDURE statements +* spcreate_gv.db2 - CLP script to issue CREATE GLOBAL VARIABLE and +* CREATE PROCEDURE statements. +* spdrop.db2 - CLP script to drop stored procedures from the catalog +* spcat - CLP script that first calls spdrop.db2 and then calls +* spcreate.db2. +* spclient.sqc - Client application that calls the stored procedures in +* spserver.sqc. +* spserver.sqc - Stored procedure functions built and run on the server +* spserver.exp - export file for spserver. +* +****************************************************************************** +* +* UDF Level (program files that demonstrate user defined functions) +* +* udfcli.sqc - Client application which calls the user defined function +* in udfsrv.c. +* udfemcli.sqc - Call a variety of types of embedded SQL user-defined +* functions in udfemsrv.sqc. +* udfemsrv.sqc - Embedded SQL user-defined functions called by udfemcli.sqc. +* udfemsrv.exp - Export file for udfemsrv. +* udfsrv.c - User defined function ScalarUDF called by udfcli.sqc. +* udfsrv.exp - Export file for udfsrv. +* +****************************************************************************** +* +* Log Management User Exit samples +* +* db2uext2.cdisk - uses the platform system copy command to archive and +* retrieve database log files. +* db2uext2.ctape - uses system tape commands to archive and retrieve +* database log files. +* db2uext2.ctsm - uses Tivoli Storage Manager (TSM) APIs to archive and +* retrieve database log files. +* db2uext2.cxbsa - uses XBSA APIs to archive and retrieve database log +* files. +* +****************************************************************************** +* +* Event Monitor samples +* +* evm.sqc - Demonstrates file, pipe, and table event monitors +* +****************************************************************************** +* +* Other +* +* largevol.sqc - Extract large volumes of data from several queries +* udfingesttcpip.sqc - Embedded SQL user-defined function. It is a sample +* client for INGEST utility's TCP/IP support. +* udfingesttcpip.exp - Export file for udfingesttcpip. +* +****************************************************************************** +****************************************************************************** +* Support for these samples will be provided in subsequent releases +****************************************************************************** +* dblognoconn.sqc - How to read database log files asynchronously +* with no database connection +* dbmcon.sqc - How to connect and disconnect from multiple databases. +* dbmcon1.h - Header file for dbmcon1.sqc +* dbmcon1.sqc - Functions used in the multiple databases program +* dbmcon. +* dbmcon2.h - Header file for dbmcon2.sqc +* dbmcon2.sqc - Functions used in the multiple databases program +* dbmcon. +****************************************************************************** + diff --git a/c/autostore.c b/c/autostore.c new file mode 100644 index 0000000..513ce9c --- /dev/null +++ b/c/autostore.c @@ -0,0 +1,588 @@ +/***************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: autostore.c +** +** SAMPLE: How to use automatic storage capability for a database. +** +** This sample demonstrates: +** +** 1. How to create an automatic storage database with two +** storage paths +** 2. How to backup the above database +** 3. How to restore an automatic storage database into a different +** set of storage paths +** +** DB2 API USED: +** db2Backup -- BACKUP DATABASE +** db2Restore -- RESTORE DATABASE +** db2CfgSet -- SET DATABASE CONFIGURATION +** db2CfgGet -- GET DATABASE CONFIGURATION +** sqlecrea -- CREATE DATABASE +** sqledrpd -- DROP DATABASE +** +** OUTPUT FILE: autostore.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +/* function declarations */ +int CreateDatabase(char *, char *, char *, char *); +int BackupDatabase(char *, char *, char *, char *); +int DropDatabase(char *); +int RestoreDatabase(char *, char *, char *, char *, char *, + char *, char *, char *, char *); +int ServerWorkingPathGet(char *, char *); +int DbBackup(char *, char *, char *, char *, db2BackupStruct *); + +char backupTimestamp[SQLU_TIME_STAMP_LEN + 1] = { 0 }; + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1] = { 0 }; + char restoredDbAlias[SQL_ALIAS_SZ + 1] = { 0 }; + char user[USERID_SZ + 1] = { 0 }; + char pswd[PSWD_SZ + 1] = { 0 }; + char storPath1[SQL_PATH_SZ + 1] = { 0 }; + char storPath2[SQL_PATH_SZ + 1] = { 0 }; + char storPath3[SQL_PATH_SZ + 1] = { 0 }; + char storPath4[SQL_PATH_SZ + 1] = { 0 }; + char serverWorkingPath[SQL_PATH_SZ + 1] = { 0 }; + + /* check and assign the values for the respective variables as + passed from the command line arguments */ + switch (argc) + { + case 5: + strcpy(storPath1, argv[1]); + strcpy(storPath2, argv[2]); + strcpy(storPath3, argv[3]); + strcpy(storPath4, argv[4]); + strcpy(dbAlias, "AUTODB"); + strcpy(restoredDbAlias, "RESTDB"); + strcpy(user, ""); + strcpy(pswd, ""); + break; + + case 7: + strcpy(storPath1, argv[3]); + strcpy(storPath2, argv[4]); + strcpy(storPath3, argv[5]); + strcpy(storPath4, argv[6]); + strcpy(dbAlias, argv[1]); + strcpy(restoredDbAlias, argv[2]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + + case 9: + strcpy(storPath1, argv[5]); + strcpy(storPath2, argv[6]); + strcpy(storPath3, argv[7]); + strcpy(storPath4, argv[8]); + strcpy(dbAlias, argv[1]); + strcpy(restoredDbAlias, argv[2]); + strcpy(user, argv[3]); + strcpy(pswd, argv[4]); + break; + + default: + printf("\nUSAGE: %s " + "[dbAlias restoredDbAlias [user pswd]] " + "storPath1 storPath2 storPath3 storPath4\n", + argv[0]); + printf(" The storage paths mentioned above have to be absolute\n"); + rc = 1; + break; + } + if (rc != 0) + { + return rc; + } + + /* call the function to create the database */ + rc = CreateDatabase(dbAlias, storPath1, storPath2, storPath3); + if (rc != 0) + { + printf("There is an ERROR while creating the database %s\n", dbAlias); + exit (1); + } + + /* get the server working path */ + rc = ServerWorkingPathGet(dbAlias, serverWorkingPath); + if (rc != 0) + { + printf("There is an ERROR while getting the server working path.\n"); + exit (1); + } + + /* call the function to Backup the database */ + rc = BackupDatabase(dbAlias, user, pswd, serverWorkingPath); + if (rc != 0) + { + printf("There is an ERROR while backing up the database %s\n", dbAlias); + exit (1); + } + + /* call the function to Drop the database */ + rc = DropDatabase(dbAlias); + if (rc != 0) + { + printf("There is an ERROR while dropping the database %s\n", dbAlias); + exit (1); + } + + /* call the function to restore the database */ + rc = RestoreDatabase(dbAlias, + user, + pswd, + restoredDbAlias, + serverWorkingPath, + backupTimestamp, + storPath2, + storPath3, + storPath4); + if (rc != 0) + { + printf("There is an ERROR while restoring the database %s\n", dbAlias); + exit (1); + } + + return (0); + } /* main */ + +/***************************************************************************/ +/* CreateDatabase */ +/* Create an automatic storage database with two specified storage */ +/* paths, namely, storPath1, storPath2) and database path on storPath3 */ +/* This function executes the following CLP command: */ +/* CREATE DB ON storPath1, storPath2 DBPATH ON storPath3 */ +/***************************************************************************/ +int CreateDatabase(char dbName[], + char storPath1[], + char storPath2[], + char storPath3[]) +{ + int rc = 0; + struct sqlca sqlca; + char dbLocalAlias[SQL_ALIAS_SZ + 1]; + char dbPath[SQL_PATH_SZ + 1]; + struct sqleAutoStorageCfg storageCfg; + struct sqledbdesc dbDesc; + struct sqledbdescext dbDescExt; + char * storagePaths[2]; + SQLEDBTERRITORYINFO territoryInfo; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" sqlecrea -- CREATE DATABASE\n"); + printf("TO CREATE A NEW DATABASE:\n"); + + /* setup storage paths and automatic storage information */ + storagePaths[0]= (char *) malloc(sizeof(char)*(SQL_PATH_SZ + 1)); + storagePaths[1]= (char *) malloc(sizeof(char)*(SQL_PATH_SZ + 1)); + + if (storagePaths[0] == NULL || storagePaths[1] == NULL) + { + printf("ERROR: Unable to allocate memory for the storage paths.\n\n"); + return (1); + } + + /* storPath1 and storPath2 points to the storage paths that will be used + for automatic storage. */ + strcpy(storagePaths[0], storPath1); + strcpy(storagePaths[1], storPath2); + + storageCfg.sqlNumStoragePaths = 2; + storageCfg.sqlStoragePaths = storagePaths; + storageCfg.sqlEnableAutoStorage = SQL_AUTOMATIC_STORAGE_YES; + /* This parameter enables the Automatic Storage capalility */ + + /* initialize sqledbdesc structure */ + strcpy(dbDesc.sqldbdid, SQLE_DBDESC_2); + dbDesc.sqldbccp = 0; + dbDesc.sqldbcss = SQL_CS_NONE; + + strcpy(dbDesc.sqldbcmt, ""); + dbDesc.sqldbsgp = 0; + dbDesc.sqldbnsg = 10; + dbDesc.sqltsext = -1; + dbDesc.sqlcatts = NULL; + dbDesc.sqlusrts = NULL; + dbDesc.sqltmpts = NULL; + + /* initialize sqledbdescext structure */ + dbDescExt.sqlPageSize = SQL_PAGESIZE_4K; + dbDescExt.sqlAutoStorage = &storageCfg; + dbDescExt.sqlcattsext = NULL; + dbDescExt.sqlusrtsext = NULL; + dbDescExt.sqltmptsext = NULL; + dbDescExt.reserved = NULL; + + strcpy(territoryInfo.sqldbcodeset, "ISO8859-1"); + strcpy(territoryInfo.sqldblocale, "C"); + + strcpy(dbLocalAlias, dbName); + + /* specify the database path */ + strcpy(dbPath, storPath3); + + /* create database */ + sqlecrea(dbName, + dbLocalAlias, + dbPath, + &dbDesc, + &territoryInfo, + '\0', + (void *)&dbDescExt, + &sqlca ); + + DB2_API_CHECK("Create Database"); + return rc; +} /* CreateDatabase */ + +/***************************************************************************/ +/* BackupDatabase */ +/* Backup the specified database */ +/***************************************************************************/ +int BackupDatabase(char dbAlias[], + char user[], + char pswd[], + char serverWorkingPath[]) +{ + int rc = 0; + struct sqlca sqlca = { 0 }; + db2CfgParam cfgParameters[1] = { 0 }; + db2Cfg cfgStruct = { 0 }; + db2BackupStruct backupStruct = { 0 }; + + printf("\n****************************\n"); + printf("*** BACK UP THE DATABASE ***\n"); + printf("****************************\n"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" db2CfgSet -- Set Configuration\n"); + printf(" db2Backup -- Backup Database\n"); + printf("TO BACK UP THE DATABASE.\n"); + + printf("\n Update \'%s\' database configuration:\n", dbAlias); + printf(" - Disable the database configuration parameter LOGARCHMETH1\n"); + printf(" i.e., set LOGARCHMETH1 = OFF\n"); + + /* initialize cfgParameters */ + cfgParameters[0].flags = 0; + cfgParameters[0].token = SQLF_DBTN_LOGARCHMETH1; + cfgParameters[0].ptrvalue = "OFF"; + + /* initialize cfgStruct */ + cfgStruct.numItems = 1; + cfgStruct.paramArray = cfgParameters; + cfgStruct.flags = db2CfgDatabase | db2CfgDelayed; + cfgStruct.dbname = dbAlias; + + /* set database configuration */ + db2CfgSet(db2Version1010, (void *)&cfgStruct, &sqlca); + DB2_API_CHECK("Db Log Retain -- Disable"); + + /******************************/ + /* BACKUP THE DATABASE */ + /******************************/ + + rc = DbBackup(dbAlias, user, pswd, serverWorkingPath, &backupStruct); + + strcpy(backupTimestamp, backupStruct.oTimestamp); + return rc; + +} /* BackupDatabase */ + +/***************************************************************************/ +/* DbBackup */ +/* Performs the database backup */ +/***************************************************************************/ +int DbBackup(char dbAlias[], + char user[], + char pswd[], + char serverWorkingPath[], + db2BackupStruct *backupStruct) +{ + struct sqlca sqlca = { 0 }; + db2TablespaceStruct tablespaceStruct = { 0 }; + db2MediaListStruct mediaListStruct = { 0 }; + + /*******************************/ + /* BACK UP THE DATABASE */ + /*******************************/ + printf("\n Backing up the '%s' database...\n", dbAlias); + + tablespaceStruct.tablespaces = NULL; + tablespaceStruct.numTablespaces = 0; + + mediaListStruct.locations = &serverWorkingPath; + mediaListStruct.numLocations = 1; + mediaListStruct.locationType = SQLU_LOCAL_MEDIA; + + backupStruct->piDBAlias = dbAlias; + backupStruct->piTablespaceList = &tablespaceStruct; + backupStruct->piMediaList = &mediaListStruct; + backupStruct->piUsername = NULL; + backupStruct->piPassword = NULL; + backupStruct->piVendorOptions = NULL; + backupStruct->iVendorOptionsSize = 0; + backupStruct->iCallerAction = DB2BACKUP_BACKUP; + backupStruct->iBufferSize = 16; /* 16 x 4KB */ + backupStruct->iNumBuffers = 2; + backupStruct->iParallelism = 1; + backupStruct->iOptions = DB2BACKUP_OFFLINE | DB2BACKUP_DB; + + /* The API db2Backup creates a backup copy of a database. + This API automatically establishes a connection to the specified + database. (This API can also be used to create a backup copy of a + table space). */ + db2Backup(db2Version1010, backupStruct, &sqlca); + DB2_API_CHECK("Database -- Backup"); + + while (sqlca.sqlcode != 0) + { + /* continue the backup operation */ + + /* depending on the sqlca.sqlcode value, user action may be */ + /* required, such as mounting a new tape */ + + printf("\n Continuing the backup operation...\n"); + + backupStruct->iCallerAction = DB2BACKUP_CONTINUE; + + db2Backup(db2Version1010, backupStruct, &sqlca); + + DB2_API_CHECK("Database -- Backup"); + } + + printf(" Backup finished.\n"); + printf(" - backup image size : %d MB\n", backupStruct->oBackupSize); + printf(" - backup image path : %s\n", + mediaListStruct.locations[0]); + + printf(" - backup image time stamp: %s\n", backupStruct->oTimestamp); + return 0; +} /* DbBackup */ + +/***************************************************************************/ +/* RestoreDatabase */ +/* Restore an automatic storage database to a set of specified storage */ +/* paths: storPath3, storPath4 */ +/* This function executes the following CLP command: */ +/* RESTORE DB ON storPath3, storPath4 */ +/***************************************************************************/ +int RestoreDatabase(char dbAlias[], + char user[], + char pswd[], + char restoredDbAlias[], + char serverWorkingPath[], + char restoreTimestamp[], + char storPath2[], + char storPath3[], + char storPath4[]) +{ + int rc = 0; + struct sqlca sqlca = { 0 }; + char * storagePaths[2]; + db2RestoreStruct restoreStruct = { 0 }; + db2TablespaceStruct rtablespaceStruct = { 0 }; + db2MediaListStruct rmediaListStruct = { 0 }; + db2StoragePathsStruct storagePathsStruct = { 0 }; + + /******************************/ + /* RESTORE THE DATABASE */ + /******************************/ + storagePaths[0]= (char *) malloc (sizeof(char)* (SQL_PATH_SZ + 1)); + storagePaths[1]= (char *) malloc (sizeof(char)* (SQL_PATH_SZ + 1)); + + if (storagePaths[0] == NULL || storagePaths[1] == NULL) + { + printf("ERROR: Unable to allocate memory for storage paths.\n\n"); + return (1); + } + + printf("\n****************************\n"); + printf("*** RESTORE THE DATABASE ***\n"); + printf("******************************\n"); + printf("\nUSE THE DB2 API:\n"); + printf(" db2Restore -- Restore Database\n"); + printf("TO RESTORE THE DATABASE.\n"); + + printf("\n Restoring a database ...\n"); + printf(" - source image alias : %s\n", dbAlias); + printf(" - source image time stamp: %s\n", restoreTimestamp); + printf(" - target database : %s\n", restoredDbAlias); + + rtablespaceStruct.tablespaces = NULL; + rtablespaceStruct.numTablespaces = 0; + rmediaListStruct.locations = &serverWorkingPath; + rmediaListStruct.numLocations = 1; + rmediaListStruct.locationType = SQLU_LOCAL_MEDIA; + restoreStruct.piSourceDBAlias = dbAlias; + restoreStruct.piTargetDBAlias = restoredDbAlias; + restoreStruct.piTimestamp = restoreTimestamp; + restoreStruct.piTargetDBPath = NULL; + restoreStruct.piReportFile = NULL; + restoreStruct.piTablespaceList = &rtablespaceStruct; + restoreStruct.piMediaList = &rmediaListStruct; + restoreStruct.piUsername = user; + restoreStruct.piPassword = pswd; + restoreStruct.piNewLogPath = NULL; + restoreStruct.piVendorOptions = NULL; + restoreStruct.iVendorOptionsSize = 0; + restoreStruct.iParallelism = 1; + restoreStruct.iBufferSize = 1024; /* 1024 x 4KB */ + restoreStruct.iNumBuffers = 2; + restoreStruct.piTargetDBPath = storPath4 ; + + /* The database is will be restored on new storage paths 'storPath3' + and 'storPath4'. */ + strcpy( storagePaths[0], storPath3 ); + strcpy( storagePaths[1], storPath4 ); + + storagePathsStruct.numStoragePaths = 2; + storagePathsStruct.storagePaths = storagePaths; + + restoreStruct.piStoragePaths = &storagePathsStruct; + restoreStruct.iCallerAction = DB2RESTORE_RESTORE; + restoreStruct.iOptions = + DB2RESTORE_OFFLINE | DB2RESTORE_DB | DB2RESTORE_NODATALINK | + DB2RESTORE_NOROLLFWD; + + /* The API db2Restore is used to restore a database that has been backed + up using the API db2Backup. */ + db2Restore(db2Version1010, &restoreStruct, &sqlca); + DB2_API_CHECK("database restore -- start"); + + while (sqlca.sqlcode != 0) + { + /* continue the restore operation */ + printf("\n Continuing the restore operation...\n"); + + /* depending on the sqlca.sqlcode value, user action may be + required, such as mounting a new tape */ + + restoreStruct.iCallerAction = DB2RESTORE_CONTINUE; + + /* restore the database */ + db2Restore(db2Version1010, &restoreStruct, &sqlca); + DB2_API_CHECK("database restore -- continue"); + } + + printf("\n Restore finished.\n"); + return 0; +} /* RestoreDatabase */ + +/***************************************************************************/ +/* DropDatabase */ +/* Drop the specified database */ +/***************************************************************************/ +int DropDatabase(char dbLocalAlias[]) +{ + struct sqlca sqlca; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" sqledrpd -- DROP DATABASE\n"); + printf("TO DROP A DATABASE:\n"); + + /* drop a database */ + printf("\n Drop a [remote] database and uncatalog it locally.\n"); + printf(" local database alias: %s\n", dbLocalAlias); + + /* drop the database */ + sqledrpd(dbLocalAlias, &sqlca); + DB2_API_CHECK("Database -- Drop"); + + return 0; +} /* DropDatabase */ + +/***************************************************************************/ +/* ServerWorkingPathGet */ +/* Get the server working directory path where the backup images are kept */ +/***************************************************************************/ +int ServerWorkingPathGet(char dbAlias[], char serverWorkingPath[]) +{ + int rc = 0; + struct sqlca sqlca; + db2CfgParam cfgParameters[1]; + db2Cfg cfgStruct; + char serverLogPath[SQL_PATH_SZ + 1]; + char dbAlias_upper[SQL_ALIAS_SZ + 1] = { 0 }; + int len = 0; + int ctr = 0; + + /* initialize cfgParameters */ + cfgParameters[0].flags = 0; + cfgParameters[0].token = SQLF_DBTN_LOGPATH; + cfgParameters[0].ptrvalue = + (char *)malloc((SQL_PATH_SZ + 1) * sizeof(char)); + + /* initialize cfgStruct */ + cfgStruct.numItems = 1; + cfgStruct.paramArray = cfgParameters; + cfgStruct.flags = db2CfgDatabase; + cfgStruct.dbname = dbAlias; + + /* get database configuration */ + db2CfgGet(db2Version1010, (void *)&cfgStruct, &sqlca); + DB2_API_CHECK("server log path -- get"); + + strcpy(serverLogPath, cfgParameters[0].ptrvalue); + free(cfgParameters[0].ptrvalue); + + /* get server working path */ + /* for example, if the serverLogPath = "C:\DB2\NODE0001\....". */ + /* keep for serverWorkingPath "C:\DB2" only. */ + + for (ctr = 0; ctr < strlen (dbAlias); ctr++) + { + dbAlias_upper[ctr] = toupper (dbAlias[ctr]); + } + dbAlias_upper[ctr] = '\0'; /* terminate the constructed string */ + + len = (int)(strstr(serverLogPath, "NODE") - serverLogPath - 1); + memcpy( serverWorkingPath, serverLogPath, len ); + serverWorkingPath[len] = '\0'; + + return 0; +} /* ServerWorkingPathGet */ diff --git a/c/bldapp b/c/bldapp new file mode 100755 index 0000000..07d698a --- /dev/null +++ b/c/bldapp @@ -0,0 +1,111 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldapp +# Builds C applications for Linux +# Usage: bldapp [ [ ]] + +# Select a compiler to use +CC=gcc +#CC=xlc_r + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then + BITWIDTH=64 +else + # x86 is the only native 32-bit platform + BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] +then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +# Note: some .sqc files contain no SQL but link in +# utilemb.sqc, so if you get this warning, ignore it: +# SQL0053W No SQL statements were found in the program. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 $3 $4 + # Compile the utilemb.c error-checking utility. + $CC $EXTRA_C_FLAGS -I$DB2PATH/include -c utilemb.c +else + # Compile the utilapi.c error-checking utility. + $CC $EXTRA_C_FLAGS -I$DB2PATH/include -c utilapi.c +fi + +# Compile the program. +$CC $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c + +if [ -f $1".sqc" ] +then + # Link the program with utilemb.o. + $CC $EXTRA_C_FLAGS -o $1 $1.o utilemb.o $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 +else + # Link the program with utilapi.o. + $CC $EXTRA_C_FLAGS -o $1 $1.o utilapi.o $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 +fi diff --git a/c/bldmc b/c/bldmc new file mode 100755 index 0000000..14c80a0 --- /dev/null +++ b/c/bldmc @@ -0,0 +1,107 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldmc +# Builds C multi-connection applications for Linux +# Requires a second database: . Suggested name: sample2 +# Also requires three program source files: and +# to be bound to the first database; to be bound to the +# second database. + +if (($# < 3)) +then + echo "Usage: bldmc [ ]" + exit +fi + +# Select the compiler to use +CC=gcc +#CC=xlc_r + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# To specify a runtime path for shared libraries, uncomment the +# following line (usually only needed for setuid applications). +# RUNTIME=true + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then + BITWIDTH=64 +else + # x86 is the only native 32-bit platform + BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] +then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# Precompile and bind the program files +./embprep $1 $2 $4 $5 +./embprep $11 $2 $4 $5 +./embprep $12 $3 $6 $7 + +# Compile the program files +$CC $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c $11.c $12.c utilemb.c + +# Link the program +$CC $EXTRA_C_FLAGS -o $1 $1.o $11.o $12.o utilemb.o $EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2 diff --git a/c/bldmt b/c/bldmt new file mode 100755 index 0000000..86c3bc6 --- /dev/null +++ b/c/bldmt @@ -0,0 +1,95 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldmt +# Builds C multi-threaded applications for Linux +# Usage: bldmt [ [ ]] + +# Select the compiler to use +CC=gcc +#CC=xlc_r + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then + BITWIDTH=64 +else + # x86 is the only native 32-bit platform + BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] +then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 $3 $4 +fi + +# Compile the program. +$CC $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c -D_REENTRANT + +# Link the program. +$CC $EXTRA_C_FLAGS -o $1 $1.o $EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2 -lpthread diff --git a/c/bldrtn b/c/bldrtn new file mode 100755 index 0000000..9451c68 --- /dev/null +++ b/c/bldrtn @@ -0,0 +1,111 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldrtn +# Builds C routines (stored procedures or UDFs) for Linux +# Usage: bldrtn [ ] + +# Select the compiler to use +CC=gcc +#CC=xlc_r + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default compiler/linker settings +EXTRA_C_FLAGS="" +SHARED_LIB_FLAG="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then + BITWIDTH=64 +else + # x86 is the only native 32-bit platform + BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] +then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +if [ "$CC" = "xlc_r" ] +then + SHARED_LIB_FLAG="-qmkshrobj" +else + SHARED_LIB_FLAG="-shared" + EXTRA_C_FLAGS="$EXTRA_C_FLAGS -fpic" +fi + +LINK_FLAGS="$EXTRA_C_FLAGS $SHARED_LIB_FLAG" + +# Set the runtime path. +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 +fi + +# Compile the program. +$CC $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c -D_REENTRANT + +# Link the program and create a shared library +$CC $LINK_FLAGS -o $1 $1.o $EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2 -lpthread + +# Copy the shared library to the function subdirectory. +# The user must have write permission to this directory. +rm -f $DB2PATH/function/$1 +cp $1 $DB2PATH/function diff --git a/c/cli_info.c b/c/cli_info.c new file mode 100644 index 0000000..afe2337 --- /dev/null +++ b/c/cli_info.c @@ -0,0 +1,419 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: cli_info.c +** +** SAMPLE: Set and get information at the client level +** +** DB2 APIs USED: +** sqlesetc -- SET CLIENT +** sqleseti -- SET CLIENT INFORMATION +** sqleqryc -- QUERY CLIENT +** sqleqryi -- QUERY CLIENT INFORMATION +** +** STRUCTURES USED: +** sqlca +** sqle_client_info +** sqle_conn_setting +** +** OUTPUT FILE: cli_info.out (available in the online documentation) +***************************************************************************** +* +* For information on developing C applications, see the Application +* Development Guide. +* +* For more information on DB2 APIs, see the Administrative API Reference. +* +* For the latest information on programming, compiling, and running DB2 +* applications, visit the DB2 application development website: +* http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilapi.h" + +int ClientAppNameSetGet(void); +int ClientUseridSetGet(void); +int ClientWorkstationSetGet(void); +int ClientSuffixForAccountingStringSetGet(void); +int ClientConnectionAttrsSetGet(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + + /* check command line arguments */ + if (argc != 1) + { + printf("\nUSAGE: %s \n", argv[0]); + return 1; + } + + printf("\nHOW TO SET AND GET INFOMATION AT THE CLIENT LEVEL.\n"); + + rc = ClientAppNameSetGet(); + rc = ClientUseridSetGet(); + rc = ClientWorkstationSetGet(); + rc = ClientSuffixForAccountingStringSetGet(); + rc = ClientConnectionAttrsSetGet(); + + return 0; +} /* end main */ + +int ClientAppNameSetGet(void) +{ + struct sqlca sqlca; + struct sqle_client_info clientAppInfo[1]; + + unsigned short dbAliasLen; + char dbAlias[SQL_ALIAS_SZ + 1]; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" sqleseti -- SET CLIENT INFORMATION\n"); + printf(" sqleqryi -- QUERY CLIENT INFORMATION\n"); + printf("TO SET/GET THE CLIENT APPL. NAME:\n"); + + /* specify all the connections */ + dbAliasLen = 0; + strcpy(dbAlias, ""); + + /* initialize clientAppInfo */ + clientAppInfo[0].type = SQLE_CLIENT_INFO_APPLNAME; + clientAppInfo[0].pValue = + (char *)malloc(sizeof(char) *(SQLE_CLIENT_APPLNAME_MAX_LEN + 1)); + + /* set client app. name */ + strcpy(clientAppInfo[0].pValue, "ClientApplicationName"); + clientAppInfo[0].length = strlen((char *)clientAppInfo[0].pValue); + printf("\n Set the Client App. Name to the value:\n"); + printf(" %s\n", clientAppInfo[0].pValue); + + /* set client information */ + sqleseti(dbAliasLen, dbAlias, 1, &clientAppInfo[0], &sqlca); + DB2_API_CHECK("Client App. Name -- set"); + + /* get client app. name */ + strcpy(clientAppInfo[0].pValue, ""); + printf(" Get the Client App. Name.\n"); + + /* query client information */ + sqleqryi(dbAliasLen, dbAlias, 1, &clientAppInfo[0], &sqlca); + DB2_API_CHECK("Client App. Name -- get"); + + printf(" The Client App. Name is:\n"); + printf(" %s\n", clientAppInfo[0].pValue); + + /* free the memory allocated */ + free(clientAppInfo[0].pValue); + + return 0; +} /* ClientAppNameSetGet */ + +int ClientUseridSetGet(void) +{ + struct sqlca sqlca; + struct sqle_client_info clientAppInfo[1]; + + unsigned short dbAliasLen; + char dbAlias[SQL_ALIAS_SZ + 1]; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" sqleseti -- SET CLIENT INFORMATION\n"); + printf(" sqleqryi -- QUERY CLIENT INFORMATION\n"); + printf("TO SET/GET THE CLIENT USERID:\n"); + + /* specify all the connections */ + dbAliasLen = 0; + strcpy(dbAlias, ""); + + /* initialize clientAppInfo */ + clientAppInfo[0].type = (unsigned short)SQLE_CLIENT_INFO_USERID; + clientAppInfo[0].pValue = (char *)malloc(SQLE_CLIENT_USERID_MAX_LEN + 1); + + /* set client user ID */ + strcpy(clientAppInfo[0].pValue, "ClientUserid"); + clientAppInfo[0].length = strlen((char *)clientAppInfo[0].pValue); + printf("\n Set the Client User ID to the value:\n"); + printf(" %s\n", clientAppInfo[0].pValue); + + /* set client information */ + sqleseti(dbAliasLen, dbAlias, 1, &clientAppInfo[0], &sqlca); + DB2_API_CHECK("Client User ID -- set"); + + /* get client user ID */ + strcpy(clientAppInfo[0].pValue, ""); + printf(" Get the Client User ID.\n"); + + /* query client information */ + sqleqryi(dbAliasLen, dbAlias, 1, &clientAppInfo[0], &sqlca); + DB2_API_CHECK("Client User ID -- get"); + + printf(" The Client User ID is:\n"); + printf(" %s\n", clientAppInfo[0].pValue); + + /* free the memory allocated */ + free(clientAppInfo[0].pValue); + + return 0; +} /* ClientUseridSetGet */ + +int ClientWorkstationSetGet(void) +{ + struct sqlca sqlca; + struct sqle_client_info clientAppInfo[1]; + + unsigned short dbAliasLen; + char dbAlias[SQL_ALIAS_SZ + 1]; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" sqleseti -- SET CLIENT INFORMATION\n"); + printf(" sqleqryi -- QUERY CLIENT INFORMATION\n"); + printf("TO SET/GET THE CLIENT WORKSTATION NAME:\n"); + + /* specify all the connections */ + dbAliasLen = 0; + strcpy(dbAlias, ""); + + /* initialize clientAppInfo */ + clientAppInfo[0].type = SQLE_CLIENT_INFO_WRKSTNNAME; + clientAppInfo[0].pValue = + (char *)malloc(sizeof(char) *(SQLE_CLIENT_WRKSTNNAME_MAX_LEN + 1)); + + /* set client workstation name*/ + strcpy(clientAppInfo[0].pValue, "ClientWorkstation"); + clientAppInfo[0].length = strlen((char *)clientAppInfo[0].pValue); + printf("\n Set the Client Workstation Name to the value:\n"); + printf(" %s\n", clientAppInfo[0].pValue); + + /* set client information */ + sqleseti(dbAliasLen, dbAlias, 1, &clientAppInfo[0], &sqlca); + DB2_API_CHECK("Client Workstation Name -- set"); + + /* get client workstation name */ + strcpy(clientAppInfo[0].pValue, ""); + printf(" Get the Client Workstation Name.\n"); + + /* query client information */ + sqleqryi(dbAliasLen, dbAlias, 1, &clientAppInfo[0], &sqlca); + DB2_API_CHECK("Client Workstation Name -- get"); + + printf(" The Client Workstation Name is:\n"); + printf(" %s\n", clientAppInfo[0].pValue); + + /* free the memory allocated */ + free(clientAppInfo[0].pValue); + + return 0; +} /* ClientWorkstationSetGet */ + +int ClientSuffixForAccountingStringSetGet(void) +{ + struct sqlca sqlca; + struct sqle_client_info clientAppInfo[1]; + + char clientAccStrSuffix[] = "ClientSuffixForAccountingString"; + unsigned short dbAliasLen; + char dbAlias[SQL_ALIAS_SZ + 1]; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" sqleseti -- SET CLIENT INFORMATION\n"); + printf(" sqleqryi -- QUERY CLIENT INFORMATION\n"); + printf("TO SET/GET THE CLIENT SUFFIX FOR THE ACCOUNTING STRING:\n"); + + /* specify all the connections */ + dbAliasLen = 0; + strcpy(dbAlias, ""); + + /* initialize clientAppInfo */ + clientAppInfo[0].type = SQLE_CLIENT_INFO_ACCTSTR; + clientAppInfo[0].pValue = + (char *)malloc(sizeof(char) *(SQLE_CLIENT_APPLNAME_MAX_LEN + 1)); + + /* set client suffix for accounting string */ + strcpy(clientAppInfo[0].pValue, "ClientSuffixForAccountingString"); + clientAppInfo[0].length = strlen((char *)clientAppInfo[0].pValue); + printf("\n Use the DB2 API sqleseti to set\n"); + printf(" the Client Suffix for Accounting String to the value:\n"); + printf(" %s\n", clientAppInfo[0].pValue); + + /* set client information */ + sqleseti(dbAliasLen, dbAlias, 1, &clientAppInfo[0], &sqlca); + DB2_API_CHECK("Client Suffix for Accounting String -- set"); + + /* get client suffix for accounting string */ + strcpy(clientAppInfo[0].pValue, ""); + printf(" Get the Client Suffix for Accounting String.\n"); + + /* query client information */ + sqleqryi(dbAliasLen, dbAlias, 1, &clientAppInfo[0], &sqlca); + DB2_API_CHECK("Client Suffix for Accounting String -- get"); + + printf(" The Client Suffix for Accounting String is:\n"); + printf(" %s\n", clientAppInfo[0].pValue); + + /* free the memory allocated */ + free(clientAppInfo[0].pValue); + + return 0; +} /* ClientSuffixForAccountingStringSetGet */ + +int ClientConnectionAttrsSetGet(void) +{ + struct sqlca sqlca; + struct sqle_conn_setting clientAppInfo[8]; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" sqlesetc -- SET CLIENT\n"); + printf(" sqleqryc -- QUERY CLIENT\n"); + printf("TO SET/GET THE CLIENT CONNECTION ATTRIBUTES:\n"); + + /* initialize clientAppInfo */ + clientAppInfo[0].type = SQL_CONNECT_TYPE; + clientAppInfo[1].type = SQL_RULES; + clientAppInfo[2].type = SQL_DISCONNECT; + clientAppInfo[3].type = SQL_SYNCPOINT; + clientAppInfo[4].type = SQL_MAX_NETBIOS_CONNECTIONS; + clientAppInfo[5].type = SQL_DEFERRED_PREPARE; + clientAppInfo[6].type = SQL_CONNECT_NODE; + clientAppInfo[7].type = SQL_ATTACH_NODE; + + clientAppInfo[0].value = SQL_CONNECT_2; + clientAppInfo[1].value = SQL_RULES_STD; + clientAppInfo[2].value = SQL_DISCONNECT_COND; + clientAppInfo[3].value = SQL_SYNC_ONEPHASE; + clientAppInfo[4].value = 16; + clientAppInfo[5].value = SQL_DEFERRED_PREPARE_YES; + clientAppInfo[6].value = 3; + clientAppInfo[7].value = 3; + + /* set client connection attributes */ + printf("\n Set the Client Connection Attributes to the values:\n"); + printf(" SQL_CONNECT_TYPE = SQL_CONNECT_2\n"); + printf(" SQL_RULES = SQL_RULES_STD\n"); + printf(" SQL_DISCONNECT = SQL_DISCONNECT_COND\n"); + printf(" SQL_SYNCPOINT = SQL_SYNC_ONEPHASE\n"); + printf(" SQL_MAX_NETBIOS_CONNECTIONS = 16\n"); + printf(" SQL_DEFERRED_PREPARE = SQL_DEFERRED_PREPARE_YES\n"); + printf(" SQL_CONNECT_NODE = 3\n"); + printf(" SQL_ATTACH_NODE = 3\n"); + + /* set client */ + sqlesetc(&clientAppInfo[0], 8, &sqlca); + DB2_API_CHECK("Client Connection Attributes -- set"); + + /* get client connection attributes */ + + /* reset clientAppInfo */ + clientAppInfo[0].value = SQL_CONNECT_1; + clientAppInfo[1].value = SQL_RULES_DB2; + clientAppInfo[2].value = SQL_DISCONNECT_EXPL; + clientAppInfo[3].value = SQL_SYNC_TWOPHASE; + clientAppInfo[4].value = 1; + clientAppInfo[5].value = SQL_DEFERRED_PREPARE_NO; + clientAppInfo[6].value = 1; + clientAppInfo[7].value = 1; + + printf(" Get the Client Connection Attributes.\n"); + + /* query client */ + sqleqryc(&clientAppInfo[0], 8, &sqlca); + DB2_API_CHECK("Client Conn. Attrs. -- get"); + + printf(" The Client Connection Attributes are:\n"); + switch (clientAppInfo[0].value) + { + case SQL_CONNECT_1: + printf(" SQL_CONNECT_TYPE = SQL_CONNECT_1\n"); + break; + case SQL_CONNECT_2: + printf(" SQL_CONNECT_TYPE = SQL_CONNECT_2\n"); + break; + default: + break; + } + switch (clientAppInfo[1].value) + { + case SQL_RULES_DB2: + printf(" SQL_RULES = SQL_RULES_DB2\n"); + break; + case SQL_RULES_STD: + printf(" SQL_RULES = SQL_RULES_STD\n"); + break; + default: + break; + } + switch (clientAppInfo[2].value) + { + case SQL_DISCONNECT_EXPL: + printf(" SQL_DISCONNECT = SQL_DISCONNECT_EXPL\n"); + break; + case SQL_DISCONNECT_COND: + printf(" SQL_DISCONNECT = SQL_DISCONNECT_COND\n"); + break; + case SQL_DISCONNECT_AUTO: + printf(" SQL_DISCONNECT = SQL_DISCONNECT_EXPL\n"); + break; + default: + break; + } + switch (clientAppInfo[3].value) + { + case SQL_SYNC_TWOPHASE: + printf(" SQL_SYNCPOINT = SQL_SYNC_TWOPHASE\n"); + break; + case SQL_SYNC_ONEPHASE: + printf(" SQL_SYNCPOINT = SQL_SYNC_ONEPHASE\n"); + break; + case SQL_SYNC_NONE: + printf(" SQL_SYNCPOINT = SQL_SYNC_NONE\n"); + break; + default: + break; + } + printf(" SQL_MAX_NETBIOS_CONNECTIONS = %d\n", + clientAppInfo[4].value); + switch (clientAppInfo[5].value) + { + case SQL_DEFERRED_PREPARE_NO: + printf(" SQL_DEFERRED_PREPARE = SQL_DEFERRED_PREPARE_NO\n"); + break; + case SQL_DEFERRED_PREPARE_YES: + printf(" SQL_DEFERRED_PREPARE = SQL_DEFERRED_PREPARE_YES\n"); + break; + case SQL_DEFERRED_PREPARE_ALL: + printf(" SQL_DEFERRED_PREPARE = SQL_DEFERRED_PREPARE_ALL\n"); + break; + default: + break; + } + printf(" SQL_CONNECT_NODE = %d\n", clientAppInfo[6].value); + printf(" SQL_ATTACH_NODE = %d\n", clientAppInfo[7].value); + + return 0; +} /* ClientConnectionAttrsSetGet */ + diff --git a/c/clisnap.c b/c/clisnap.c new file mode 100644 index 0000000..deb4717 --- /dev/null +++ b/c/clisnap.c @@ -0,0 +1,123 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: clisnap.c +** +** SAMPLE: Capture a snapshot at the client level +** +** This sample creates an instance attachment, and calls functions +** in utilsnap.c to capture an application-level snapshot and print +** the monitor data. Monitor data from the application-level +** logical data groups is unavailable if no applications are +** connected to the database being monitored. +** +** In order to access application-level monitor data, you must +** connect to the relevant database before you run this sample. +** +** DB2 APIs USED: +** db2GetSnapshot -- Get Snapshot +** +** STRUCTURES USED: +** sqlma +** +** OUTPUT FILE: clisnap.out (available in the online documentation) +***************************************************************************** +* +* For information on developing C applications, see the Application +* Development Guide. +* +* For more information on DB2 APIs, see the Administrative API Reference. +* +* For the latest information on programming, compiling, and running DB2 +* applications, visit the DB2 application development website: +* http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include "utilsnap.c" + +int GetClientSnapshot(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char nodeName[SQL_INSTNAME_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck2(argc, argv, nodeName, user, pswd); + if (rc != 0) return rc; + + printf("\nTHIS SAMPLE SHOWS HOW TO GET A CLIENT LEVEL SNAPSHOT.\n"); + + /* attach to a local or remote instance */ + rc = InstanceAttach(nodeName, user, pswd); + if (rc != 0) return rc; + + /* turn on all the monitor switches */ + rc = TurnOnAllMonitorSwitches(); + if (rc != 0) return rc; + + /* capture a snapshot at the client level and print the monitor data */ + rc = GetClientSnapshot(); + + /* detach from the local or remote instance */ + rc = InstanceDetach(nodeName); + + return rc; +} /* main */ + +/***************************************************************************/ +/* GetClientSnapshot */ +/* Initialize the sqlma with values that tell the db2GetSnapshot API to */ +/* capture a client level snapshot. Then pass the sqlma to the */ +/* GetSnapshot function in utilsnap.c, which captures the snapshot (using */ +/* the db2GetSnapshot API) and prints the monitor data. */ +/***************************************************************************/ +int GetClientSnapshot(void) +{ + int rc = 0; /* return code */ + unsigned int obj_num = 3; /* # of objects to monitor */ + struct sqlma *ma_ptr = NULL; /* sqlma structure pointer */ + unsigned int ma_sz; /* size of sqlma structure */ + + /* determine and allocate the required memory for sqlma structure */ + /* the memory allocated to ma_ptr is freed in the GetSnapshot function */ + ma_sz = SQLMASIZE(obj_num); + ma_ptr = (struct sqlma *) malloc(ma_sz); + if ( ma_ptr == NULL) + { + printf("error allocating sqlma. Exiting.\n"); + return(99); + } + + /* initialize sqlma structure -- of significant importance here is the */ + /* "obj_type" parameter, which indicates the categories of monitor data */ + /* that will be collected */ + memset(ma_ptr, '\0', ma_sz); + ma_ptr->obj_num = obj_num; + ma_ptr->obj_var[0].obj_type = SQLMA_APPLINFO_ALL; + ma_ptr->obj_var[1].obj_type = SQLMA_APPL_ALL; + ma_ptr->obj_var[2].obj_type = SQLMA_APPL_REMOTE_ALL; + + rc = GetSnapshot(ma_ptr); + + return rc; +} /* GetClientSnapshot */ diff --git a/c/clisnapnew.c b/c/clisnapnew.c new file mode 100644 index 0000000..b497f6c --- /dev/null +++ b/c/clisnapnew.c @@ -0,0 +1,121 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: clisnapnew.c +** +** SAMPLE: Capture a snapshot at the client level +** +** This sample creates an instance attachment, and calls functions +** in utilsnap.c to capture an application-level snapshot and print +** the monitor data. Monitor data from the application-level +** logical data groups is unavailable if no applications are +** connected to the database being monitored. +** +** In order to access application-level monitor data, you must +** connect to the relevant database before you run this sample. +** +** DB2 APIs USED: +** db2GetSnapshot -- Get Snapshot +** +** STRUCTURES USED: +** sqlma +** +** OUTPUT FILE: clisnap.out (available in the online documentation) +***************************************************************************** +* +* For information on developing C applications, see the Application +* Development Guide. +* +* For more information on DB2 APIs, see the Administrative API Reference. +* +* For the latest information on programming, compiling, and running DB2 +* applications, visit the DB2 application development website: +* http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include "utilsnap.c" + +int GetClientSnapshot(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char nodeName[SQL_INSTNAME_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck2(argc, argv, nodeName, user, pswd); + if (rc != 0) return rc; + + printf("\nTHIS SAMPLE SHOWS HOW TO GET A CLIENT LEVEL SNAPSHOT.\n"); + + /* attach to a local or remote instance */ + rc = InstanceAttach(nodeName, user, pswd); + if (rc != 0) return rc; + + /* turn on all the monitor switches */ + rc = TurnOnAllMonitorSwitches(); + if (rc != 0) return rc; + + /* capture a snapshot at the client level and print the monitor data */ + rc = GetClientSnapshot(); + + /* detach from the local or remote instance */ + rc = InstanceDetach(nodeName); + + return rc; +} /* main */ + +/***************************************************************************/ +/* GetClientSnapshot */ +/* Construct new request stream with values that tell the db2GetSnapshot */ +/* API capture a client level snapshot. Then pass the sqlma to the */ +/* GetSnapshot function in utilsnap.c, which captures the snapshot (using */ +/* the db2GetSnapshot API) and prints the monitor data. */ +/***************************************************************************/ +int GetClientSnapshot(void) +{ + db2AddSnapshotRqstData snapReq; + int rc = 0; /* return code */ + struct sqlca sqlca; + + memset(&snapReq, 0, sizeof(snapReq)); + memset(&sqlca , 0, sizeof(sqlca)); + + snapReq.pioRequestData= NULL; + snapReq.iRequestType = SQLMA_APPLINFO_ALL; + rc = db2AddSnapshotRequest(db2Version970, &snapReq, &sqlca); + sqlmCheckRC(rc); + + snapReq.iRequestType = SQLMA_APPL_ALL; + rc = db2AddSnapshotRequest(db2Version970, &snapReq, &sqlca); + sqlmCheckRC(rc); + + snapReq.iRequestType = SQLMA_APPL_REMOTE_ALL; + rc = db2AddSnapshotRequest(db2Version970, &snapReq, &sqlca); + sqlmCheckRC(rc); + + GetSnapshotNew(&snapReq); + +exit: + + return rc; +} /* GetClientSnapshot */ diff --git a/c/db2uext2.cdisk b/c/db2uext2.cdisk new file mode 100644 index 0000000..45afa26 --- /dev/null +++ b/c/db2uext2.cdisk @@ -0,0 +1,1624 @@ +/****************************************************************************** + * + * Source File Name = db2uext2.cdisk + * + * Licensed Materials - Property of IBM + * + * (C) COPYRIGHT International Business Machines Corp. 1996. + * All Rights Reserved + * + * US Government Users Restricted Rights - Use, duplication or + * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + * + * Function = Sample Log Management User Exit C Source Code + * + *****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* Sample Name: db2uext2.cdisk */ +/* */ +/* */ +/* Purpose: This is a sample User Exit utilizing the AIX system copy */ +/* command to Archive and Retrieve database log files. */ +/* */ +/* */ +/* Options: 1. This sample provides an audit trail of calls ( stored in a */ +/* separate file for each option ) including a timestamp and */ +/* parameters received. This option can be disabled. */ +/* */ +/* 2. This sample provides an error trail of calls in error */ +/* including a timestamp and an error isolation string for */ +/* problem determination. This option can be disabled. */ +/* */ +/* */ +/* Usage: 1. Copy "db2uext2.cdisk" to "db2uext2.c" and place this file */ +/* into a working directory. */ +/* */ +/* 2. Modify the "Installation Defined Variables" to suit your */ +/* environment. Two example scenarios have been provided */ +/* below for illustrative purposes. */ +/* */ +/* 3. Modify the program logic to suit your environment. If */ +/* there are situations where the user exit program fails on */ +/* archive request and you want DB2 to retry the request, set */ +/* the return code to RC_OPATTN. */ +/* */ +/* *** NOTE *** User Exit must COPY log files from active log */ +/* path to archive log path. Do not use MOVE */ +/* operation that will remove log file from the */ +/* active log path. */ +/* */ +/* 4. Compile and link "db2uext2.c" with the following command */ +/* or a functional equivalent: */ +/* cc -o db2uext2 db2uext2.c */ +/* */ +/* Place the resultant "db2uext2" named executable */ +/* into sqllib/adm. */ +/* */ +/* *** NOTE *** Code/command modification may be required */ +/* depending on compiler options used and */ +/* header file location */ +/* */ +/* *** NOTE *** On HP compile as follows: */ +/* cc -D_INCLUDE_POSIX_SOURCE -Aa db2uext2.c */ +/* -o db2uext2 */ +/* */ +/* *** NOTE *** On SCO UnixWare or Linux compile as follows: */ +/* cc -D_INCLUDE_POSIX_SOURCE db2uext2.c */ +/* -o db2uext2 */ +/* */ +/* *** NOTE *** On Sequent (PTX) compile as follows: */ +/* c++ -o db2uext2 db2uext2.c -ansi -lseq */ +/* */ +/* */ +/* 5. DB2 calls "db2uext2" in the following format - */ +/* */ +/* db2uext2 -OS -RL -RQ -DB */ +/* -NN -LP -LN */ +/* [-LSlogsize -SPstartingpage] */ +/* [-AP] */ +/* */ +/* where: os = operating system */ +/* release = DB2 release */ +/* request = 'ARCHIVE' or 'RETRIEVE' */ +/* dbname = database name */ +/* nodenumber = node number */ +/* logpath = log file path */ +/* logname = log file name */ +/* logsize = log file size (optional) */ +/* startingpage = starting offset in 4K page unit */ +/* (optional) */ +/* adsmpasswd = ADSM password (optional) */ +/* */ +/* Note: logsize and startingpage are only used when */ +/* logpath is a raw device. */ +/* */ +/* 6. Log files are archived and retrieved from disk with the */ +/* following naming convention: */ +/* */ +/* archive: archive path + database name + */ +/* node number + log file name */ +/* retrieve: retrieve path + database name + */ +/* node number + log file name */ +/* */ +/* For example: */ +/* If the archive path was "/u/usrX/archPath/", the */ +/* retrieve path was "/u/usrX/retrPath/", the database */ +/* name was "SAMPLE", the node number was NODE0000 and */ +/* the log file name was "S0000001.LOG", the log file */ +/* would be: */ +/* archived to - */ +/* "/u/usrX/archPath/SAMPLE/NODE0000/S0000001.LOG" */ +/* */ +/* retrieved from - */ +/* "/u/usrX/retrPath/SAMPLE/NODE0000/S0000001.LOG" */ +/* */ +/* Note: The subdirectory /u/usrX/archPath/SAMPLE/NODE0000/ */ +/* need to exist for the user exit sample program to */ +/* work. Please create it before turning USEREXIT */ +/* on. */ +/* */ +/* Logic Flow: 1. install signal handlers */ +/* 2. verify the number of parameters passed */ +/* 3. verify the action requested */ +/* 4. start the audit trail ( if requested ) */ +/* 5. if the requested action is to archive a file: */ +/* . copy the log file from the log path to the archive path */ +/* . if the log file is not found proceed to point 6 */ +/* if the requested action is to retrieve a file: */ +/* . copy the log file from the retrieve path to the log path */ +/* . if the log file is not found proceed to point 6 */ +/* 6. log errors ( if requested and required ) */ +/* 7. end the audit trail ( if requested ) */ +/* 8. exit with the appropriate return code */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* HP does not define llseek and offset_t */ +#ifdef _INCLUDE_POSIX_SOURCE +# define llseek lseek + typedef unsigned long offset_t; +#endif + +/*===========================================================================*/ +/*== ==*/ +/*== ------------------ INSTALLATION DEFINED VARIABLES ------------------- ==*/ +/*== ==*/ +/*== -------------------- REQUIRES USER MODIFICATION --------------------- ==*/ +/*== ==*/ +/*===========================================================================*/ +/*== ARCHIVE_PATH: Path where log files will be archived to ==*/ +/*== Notes: 1. the path is concatenated with the database ==*/ +/*== name ( the database name will be UPPERCASE ) ==*/ +/*== and the node number ( the node number will ==*/ +/*== be in UPPERCASE ) to form the physical ==*/ +/*== archive path ==*/ +/*== 2. the physical archive path must exist ( the ==*/ +/*== user exit will not create the path ) ==*/ +/*== 3. the path must end with a back slash ==*/ +/*== 4. the default path is "/u/" ==*/ +/*== ==*/ +/*== RETRIEVE_PATH: Path where log files will be retrieved from ==*/ +/*== Notes: 1. the path is concatenated with the database ==*/ +/*== name ( the database name will be UPPERCASE ) ==*/ +/*== and the node number ( the node number will ==*/ +/*== be in UPPERCASE ) to form the physical ==*/ +/*== retrieve path ==*/ +/*== 2. the physical retrieve path must exist ( the ==*/ +/*== user exit will not create the path ) ==*/ +/*== 3. the path must end with a back slash ==*/ +/*== 4. the default path is "/u/" ==*/ +/*== ==*/ +/*== AUDIT_ACTIVE: The user may wish an audit trail of the user exit run. ==*/ +/*== Sample audit functions have been provided ==*/ +/*== ( AuditLogStart() and AuditLogEnd() ) ==*/ +/*== Notes: 1. enable audit logging by setting AUDIT_ACTIVE ==*/ +/*== to 1 ==*/ +/*== 2. disable audit logging by setting ==*/ +/*== AUDIT_ACTIVE to 0 ==*/ +/*== 3. archive requests will be traced in a file ==*/ +/*== named "ARCHIVE.LOG" located in the audit and ==*/ +/*== error file path ==*/ +/*== 4. retrieve requests will be traced in a file ==*/ +/*== named "RETRIEVE.LOG" located in the audit ==*/ +/*== and error file path ==*/ +/*== 5. the default setting is enable audit ==*/ +/*== logging ==*/ +/*== ==*/ +/*== ERROR_ACTIVE: The user may wish an error trail of the user exit run. ==*/ +/*== A sample error log function has been provided ==*/ +/*== ( ErrorLog() ) ==*/ +/*== Notes: 1. enable error logging by setting ERROR_ACTIVE ==*/ +/*== to 1 ==*/ +/*== 2. disable error logging by setting ==*/ +/*== ERROR_ACTIVE to 0 ==*/ +/*== 3. errors will be traced in a file named ==*/ +/*== "USEREXIT.ERR" located in the audit and ==*/ +/*== error file path ==*/ +/*== 4. the default setting is enable error ==*/ +/*== logging ==*/ +/*== ==*/ +/*== AUDIT_ERROR_PATH: Path where Audit and Error logs will reside ==*/ +/*== Notes: 1. the path must exist ( the user exit will ==*/ +/*== not create the path ) ==*/ +/*== 2. the path must end with a back slash ==*/ +/*== 3. the default is "/u/" ==*/ +/*== ==*/ +/*== AUDIT_ERROR_ATTR: Standard C file open attributes for the Audit and ==*/ +/*== Error logs ==*/ +/*== Notes: 1. the default is "a" (text append) ==*/ +/*== ==*/ +/*== BUFFER_SIZE: This is only used if raw device is used for logging.==*/ +/*== It defines the size of the buffer used to read the ==*/ +/*== device and write to the target file. It is in ==*/ +/*== unit of 4K pages. ==*/ +/*== ==*/ + + +#define ARCHIVE_PATH "/u/" /* path must end with a slash */ +#define RETRIEVE_PATH "/u/" /* path must end with a slash */ +#define AUDIT_ACTIVE 1 /* enable audit trail logging */ +#define ERROR_ACTIVE 1 /* enable error trail logging */ +#define AUDIT_ERROR_PATH "/u/" /* path must end with a slash */ +#define AUDIT_ERROR_ATTR "a" /* append to text file */ +#define BUFFER_SIZE 32 /* # of 4K pages for output buffer */ + +/*===========================================================================*/ +/*== ==*/ +/*== ------------------------ EXAMPLE SCENARIOS -------------------------- ==*/ +/*== ( FOR ILLUSTRATIVE PURPOSES ONLY ) ==*/ +/*== ==*/ +/*===========================================================================*/ +/*== ==*/ +/*== 1) Given that we are "userid1", are working with a database ==*/ +/*== named "SAMPLE1" on node NODE0001 and have modified the ==*/ +/*== installation defined variables to the following values: ==*/ +/*== ==*/ +/*== ARCHIVE_PATH "/u/userid1/LogDirectory/" ==*/ +/*== RETRIEVE_PATH "/u/userid1/LogDirectory/" ==*/ +/*== AUDIT_ACTIVE 1 ==*/ +/*== ERROR_ACTIVE 1 ==*/ +/*== AUDIT_ERROR_PATH "/u/userid1/UserExits/" ==*/ +/*== AUDIT_ERROR_ATTR "a" ==*/ +/*== ==*/ +/*== If a request is received to archive log S0000000.LOG: ==*/ +/*== ==*/ +/*== . the audit log would be opened in append text mode and be named: ==*/ +/*== ==> "/u/userid1/UserExits/ARCHIVE.LOG" ==*/ +/*== ( AUDIT_ERROR_PATH + archive audit log file name ) ==*/ +/*== ==*/ +/*== . the log file "S0000000.LOG" in the log path directory for ==*/ +/*== node NODE0000 of database "SAMPLE1" would be archived to: ==*/ +/*== ==> "/u/userid1/LogDirectory/SAMPLE1/NODE0001/S0000000.LOG" ==*/ +/*== ( ARCHIVE_PATH + database name + node number + log file name ) ==*/ +/*== ==*/ +/*== . the error log would be opened in append text mode and be named: ==*/ +/*== ==> "/u/userid1/UserExits/USEREXIT.ERR" ==*/ +/*== ( AUDIT_ERROR_PATH + error log file name ( defined below ) ) ==*/ +/*== ==*/ +/*== ==*/ +/*== 2) Given that we are "userid2", are working with a database ==*/ +/*== named "SAMPLE2" on node NODE0002 and have modified the ==*/ +/*== installation defined variables to the following values: ==*/ +/*== ==*/ +/*== ARCHIVE_PATH "/u/userid2/LogDirectory1/New/" ==*/ +/*== RETRIEVE_PATH "/u/userid2/LogDirectory2/Old/" ==*/ +/*== AUDIT_ACTIVE 1 ==*/ +/*== ERROR_ACTIVE 0 ==*/ +/*== AUDIT_ERROR_PATH "/u/userid2/AuditLogs/" ==*/ +/*== AUDIT_ERROR_ATTR "w" ==*/ +/*== ==*/ +/*== If a request is received to retrieve log S0000001.LOG: ==*/ +/*== ==*/ +/*== . the audit log would be opened in write text mode and be named: ==*/ +/*== ==> "/u/userid2/AuditLogs/RETRIEVE.LOG" ==*/ +/*== ( AUDIT_ERROR_PATH + retrieve audit log file name ) ==*/ +/*== ==*/ +/*== . the log file would be retrieved from: ==*/ +/*== ==> "/u/userid2/LogDirectory2/Old/SAMPLE2/NODE0002/S0000001.LOG" ==*/ +/*== ( RETRIEVE_PATH + database name + node number + log file name ) ==*/ +/*== and copied into the log path directory for database "SAMPLE2" ==*/ +/*== as: ==*/ +/*== ==> "S0000001.LOG" ==*/ +/*== ( log file name ) ==*/ +/*== ==*/ +/*== . error logging is disabled ==*/ +/*== ==*/ +/*===========================================================================*/ + + +/* ----------------------------------------------------------------- */ +/* User Exit Supported Return Codes */ +/* NOTE: DB2 will reinvoke the user exit for the same request */ +/* after 5 minutes if return code is 4 or 8. */ +/* */ +/* For other non-zero return codes, DB2 will not invoke */ +/* user exit for the database for at least 5 minutes. */ +/* If this request is to archive a log file, DB2 will not */ +/* make another archive request for this file, or other */ +/* log files produced during the 5 minute time period. */ +/* These log files will only be archived when all */ +/* applications disconnect from and the database, and the */ +/* database is reopenned. */ +/* ----------------------------------------------------------------- */ +#define RC_OK 0 /* ok */ +#define RC_RES 4 /* resource allocation error */ +#define RC_OPATTN 8 /* operator/user attention required*/ +#define RC_HARDWARE 12 /* hardware error */ +#define RC_DEFECT 16 /* software error */ +#define RC_PARM 20 /* invalid parameters */ +#define RC_NOTFOUND 24 /* db2uext2() / file not found */ +#define RC_UNKNOWN 28 /* unknown error */ +#define RC_OPCAN 32 /* operator/user terminated */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Constants */ +/* ----------------------------------------------------------------- */ +#define NUM_VALID_PARMS 5 /* number of valid parameters */ +#define SLASH "/" /* default slash character */ +#define NEW_LINE "\n" /* new line character */ +#define NULL_TERM "\0" /* null terminator */ +#define FILE_EXT ".LOG" /* audit log file extension/type */ +#define COPY "cp" /* disk copy command */ +#define REMOVE "rm -f" /* disk remove command */ +#define MEDIA_TYPE "disk" /* media type used */ +#define AUDIT_IO_ERROR 99 /* audit log I/O error */ +#define SYSTEM_CALL_LEN 550 /* system call string length */ +#define OUTPUT_LINE_LEN 550 /* output line length */ +#define FILE_NAME_LEN 255 /* file name length */ +#define HELP_STRING_LEN 80 /* error help string length */ +#define DELIMITER_LEN 80 /* delimiter length */ +#define ERROR_FILE_NAME "USEREXIT.ERR" + /* error log file name */ + + +/* There is no O_RSHARE on SUN */ +#ifndef O_RSHARE +#define O_RSHARE 0 +#endif + +/* ----------------------------------------------------------------- */ +/* Define TRUE and FALSE if required */ +/* ----------------------------------------------------------------- */ +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +/* ----------------------------------------------------------------- */ +/* Define structure for input parameters */ +/* ----------------------------------------------------------------- */ +typedef struct input_parms +{ + int argc; + char* adsmPasswd; + char* dbName; + char* logFile; + char* label; + char* logFilePath; + char* logSize; + char* mode; + char* nodeNumber; + char* operatingSys; + char* redFile; + char* responseFile; + char* release; + char* request; + char* startingPage; +} INPUT_PARMS; + +/* ----------------------------------------------------------------- */ +/* Print error to Error Log macro */ +/* ----------------------------------------------------------------- */ +#define PrintErr { if ( ERROR_ACTIVE ) \ + { \ + ErrorLog( inputParms, auditFileName, \ + systemCallParms, userExitRc, \ + errorHelpString) ; \ + } \ + } + + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototypes for Archive and Retrieve */ +/* ----------------------------------------------------------------- */ +unsigned int + ArchiveFile( INPUT_PARMS *, /* input parameter structure */ + char *, /* system call parameter string */ + char * ) ; /* error isolation string */ + +unsigned int + RetrieveFile( INPUT_PARMS *, /* input parameter structure */ + char *, /* system call parameter string */ + char * ) ; /* error isolation string */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototype for Signal Handler */ +/* ----------------------------------------------------------------- */ +void SignalEnd( int ) ; /* signal type */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototypes for Audit and Error Logs */ +/* ----------------------------------------------------------------- */ +unsigned int + AuditLogStart( INPUT_PARMS *, /* input parameter structure */ + char *, /* audit file name (with path) */ + char *); /* error isolation string */ + +unsigned int + AuditLogEnd( char *, /* audit file name (with path) */ + unsigned int, /* user exit return code */ + char * ); /* error isolation string */ + +void ErrorLog( INPUT_PARMS *, /* input parameter structure */ + char *, /* audit file name (with path) */ + char *, /* system call parameter string */ + unsigned int, /* user exit return code */ + char * ) ; /* error isolation string */ + +unsigned int + ParseArguments( int , /* input parameter count */ + char * [] , /* input paramter list */ + INPUT_PARMS * , /* input parameter structure */ + char * ) ; /* error help string */ + +unsigned int + PrintArguments( FILE* fp, /* output file pointer */ + INPUT_PARMS * ) ; /* input parameter structure */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Global variables */ +/* ----------------------------------------------------------------- */ +unsigned int archiveRequested ; /* archive requested flag */ +unsigned int retrieveRequested ; /* retrieve requested flag */ + + +/*********************************************************************/ +/* User Exit Mainline */ +/*********************************************************************/ +int main( int argc, char *argv[] ) +{ + unsigned int userExitRc ; /* user exit return code */ + unsigned int auditLogRc ; /* return call from audit */ + + INPUT_PARMS inputParmsStruct; + INPUT_PARMS *inputParms = &inputParmsStruct; + + char systemCallParms[ SYSTEM_CALL_LEN ] ; + /* system call parm string */ + char auditFileName[ FILE_NAME_LEN ] ; + /* audit log file name */ + char errorHelpString[ HELP_STRING_LEN ] ; + /* error help string */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + archiveRequested = FALSE ; + retrieveRequested = FALSE ; + userExitRc = RC_OK ; + auditLogRc = RC_OK ; + memset( inputParms, '\0', sizeof(INPUT_PARMS) ); + memset( systemCallParms, '\0', SYSTEM_CALL_LEN ) ; + memset( auditFileName, '\0', FILE_NAME_LEN ) ; + memset( errorHelpString, '\0', HELP_STRING_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Install signal handlers for terminate and interrupt */ + /* -------------------------------------------------------------- */ + if (( signal( SIGTERM, SignalEnd ) == SIG_ERR ) || + ( signal( SIGINT, SignalEnd ) == SIG_ERR )) + { + userExitRc = RC_DEFECT ; /* handler not installed */ + + sprintf( errorHelpString, "%s%s", + "Unable to install signal handler(s)", NEW_LINE ) ; + + PrintErr ; + } + + /* -------------------------------------------------------------- */ + /* Set the local variables to the passed parameters and create */ + /* the system call string depending on the indicated action */ + /* -------------------------------------------------------------- */ + if ( userExitRc == RC_OK ) + { + userExitRc = ParseArguments( argc, argv, inputParms, + errorHelpString ) ; + + /* ----------------------------------------------------------- */ + /* Determine the user exit action */ + /* ----------------------------------------------------------- */ + if ( (inputParms->request != NULL) && + (strcmp( inputParms->request, "ARCHIVE" ) == 0 ) ) + { + archiveRequested = TRUE ; /* action is ARCHIVE */ + } + else + { + if ( (inputParms->request != NULL) && + (strcmp( inputParms->request, "RETRIEVE" ) == 0 )) + { + retrieveRequested = TRUE ; /* action is RETRIEVE */ + } + else + { + userExitRc = RC_PARM ; /* invalid action */ + + sprintf( errorHelpString, "%s %s %s%s", "Action", + inputParms->request, "is not valid", NEW_LINE ) ; + + PrintErr ; + } + } + } + if ( userExitRc == RC_OK ) + { + /* ----------------------------------------------------------- */ + /* Trace the start of execution if the user has asked for an */ + /* audit log */ + /* ----------------------------------------------------------- */ + if ( AUDIT_ACTIVE ) + { + sprintf( auditFileName, /* audit log file name */ + "%s%s%s", /* format of the name */ + AUDIT_ERROR_PATH, /* audit log file path */ + inputParms->request, /* ARCHIVE or RETRIEVE */ + FILE_EXT ) ; /* file extension/type */ + + auditLogRc = AuditLogStart( + inputParms, + auditFileName, + errorHelpString );/* error isolation string*/ + + if ( auditLogRc == AUDIT_IO_ERROR )/* IO error on audit log */ + { + PrintErr ; + } + } + + /* ----------------------------------------------------------- */ + /* Archive or retrieve the specified log file */ + /* ----------------------------------------------------------- */ + if ( archiveRequested ) + { + userExitRc = ArchiveFile( + inputParms, /* input param structure */ + systemCallParms, /* system call string */ + errorHelpString ) ; /* error isolation string*/ + } + else + { + userExitRc = RetrieveFile( + inputParms, /* input param structure */ + systemCallParms, /* system call string */ + errorHelpString ) ; /* error isolation string*/ + } + + /* ----------------------------------------------------------- */ + /* Trace any errors */ + /* ----------------------------------------------------------- */ + if ( userExitRc != RC_OK ) + { + PrintErr ; + } + + /* ----------------------------------------------------------- */ + /* Trace the end of execution if the user has asked for an */ + /* audit log and no error was received from the audit log */ + /* start */ + /* ----------------------------------------------------------- */ + if (( AUDIT_ACTIVE ) && + ( auditLogRc != AUDIT_IO_ERROR )) + { + auditLogRc = AuditLogEnd ( + auditFileName, /* audit log file name */ + userExitRc, /* user exit return code */ + errorHelpString ) ; /* error isolation string*/ + + if ( auditLogRc == AUDIT_IO_ERROR )/* IO error on audit log */ + { + PrintErr ; + } + } + } + + /* -------------------------------------------------------------- */ + /* Return the specified value to the caller */ + /* -------------------------------------------------------------- */ + exit(userExitRc); +} + + +/*********************************************************************/ +/* ArchiveFile() - Archive a log file to disk */ +/*********************************************************************/ +unsigned int ArchiveFile(INPUT_PARMS *inputParms, + char *systemCallParms, + char *errorHelpString) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + unsigned int rc = RC_OK ; /* function return code */ + signed int systemCallRc = RC_OK ; /* system call rc */ + char archiveTargetName[FILE_NAME_LEN];/* qualified target name */ + char *bufptr = NULL; + char *alignedbufptr; + struct stat stStatBuf; + + if (stat(inputParms->logFilePath, &stStatBuf) == -1) + { + sprintf(errorHelpString, "stat() call failed, errno = %d%s", + errno, NEW_LINE); + + rc = RC_UNKNOWN; + goto exit; + } + + /* -------------------------------------------------------------- */ + /* Construct the archive name */ + /* -------------------------------------------------------------- */ + sprintf(archiveTargetName, /* qualified target name */ + "%s%s%s%s%s%s", /* format of parm string */ + ARCHIVE_PATH, /* user ARCHIVE path */ + inputParms->dbName, /* database name */ + SLASH, /* slash character */ + inputParms->nodeNumber, /* node number */ + SLASH, /* slash character */ + inputParms->logFile); /* log file name */ + + if (S_ISDIR(stStatBuf.st_mode)) + { + FILE *tempFp = NULL; /* temporary file pointer*/ + char fileToArchive[FILE_NAME_LEN]; /* file to be archived */ + + memset( fileToArchive, '\0', FILE_NAME_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Construct the file to archive */ + /* -------------------------------------------------------------- */ + sprintf( fileToArchive, /* file to be archived */ + "%s%s", /* format of parm string */ + inputParms->logFilePath, /* log file path */ + inputParms->logFile ) ; /* log file name */ + + /* -------------------------------------------------------------- */ + /* Construct the archive system call string */ + /* -------------------------------------------------------------- */ + sprintf( systemCallParms, /* parameter string */ + "%s %s %s", + COPY, /* system copy command */ + fileToArchive, /* file to archive */ + archiveTargetName ) ; /* qualified target name */ + + systemCallRc = system( systemCallParms ) ; + + if ( systemCallRc != RC_OK ) + { + /* ----------------------------------------------------------- */ + /* Check to see if the file exists */ + /* ----------------------------------------------------------- */ + if (( tempFp = fopen( fileToArchive, "rb" )) == NULL ) + { + if (errno == ENOENT) + { + rc = RC_OK; + strcpy(errorHelpString, + "File does not exist, assume it is already archived."); + } + else + { + rc = RC_UNKNOWN; + sprintf(errorHelpString, + "Fail to open the log file %s, errno = %d%s", + fileToArchive, errno, NEW_LINE); + } + } + else + { + ( void ) fclose( tempFp ) ; /* close the file */ + + sprintf( errorHelpString, "%s %d %s%s", + "Error archiving file. Return code", systemCallRc, + "received from the system call", NEW_LINE ) ; + + /* -------------------------------------------------------------- */ + /* Remove the archive target if archive fails. If not removed, */ + /* it is possible that the partial archived target file that */ + /* left over might cause future confusion. */ + /* -------------------------------------------------------------- */ + sprintf( systemCallParms, /* parameter string */ + "%s %s", + REMOVE, /* system remove command */ + archiveTargetName ) ; /* qualified target name */ + + systemCallRc = system( systemCallParms ) ; + + rc = RC_UNKNOWN; /* copy failed */ + } + } + else + { + rc = RC_OK; /* successful archive */ + } + } + else /* logFilePath is not a directory, assume it is a raw device */ + { + int fhSource; + int fhTarget; + int logSize; + int startingPage; + int numBytes; + offset_t offsetll; + mode_t targetCreateMode; + + if (inputParms->logSize == NULL || + inputParms->startingPage == NULL) + { + sprintf(errorHelpString, + "logSize and startingPage parameters must be specified " + "for raw device.%s", + NEW_LINE); + + rc = RC_UNKNOWN; + goto exit; + } + + fhSource = open(inputParms->logFilePath, O_RDONLY | O_RSHARE); + if (fhSource == -1) + { + sprintf(errorHelpString, "open log file path failed, errno = %d%s", + errno, NEW_LINE); + + rc = RC_UNKNOWN; + goto exit; + } + + targetCreateMode = S_IRUSR + S_IWUSR + S_IRGRP + S_IROTH; + fhTarget = open(archiveTargetName, O_WRONLY | O_CREAT | O_TRUNC, + targetCreateMode); + if (fhTarget == -1) + { + if (errno == ENOENT) + { + char subDir[FILE_NAME_LEN]; + int len; + + /* In case that subdirectories are not created */ + sprintf(subDir, "%s%s", + ARCHIVE_PATH, inputParms->dbName); + len = strlen(subDir); + mkdir(subDir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + sprintf(&subDir[len], "%s%s", + SLASH, + inputParms->nodeNumber); + mkdir(subDir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + + fhTarget = open(archiveTargetName, O_WRONLY | O_CREAT | O_TRUNC, + targetCreateMode); + } + + if (fhTarget == -1) + { + sprintf(errorHelpString, "open archive target failed, errno = %d%s", + errno, NEW_LINE); + + rc = RC_UNKNOWN; + goto exit; + } + } + + /* -------------------------------------------------------------- */ + /* The following lines of code are used to sector-align the */ + /* the memory buffer that the log file will be placed in */ + /* before being flushed to disk. The reason this alignment is */ + /* necessary is that IO on a raw device MUST be aligned. */ + /* -------------------------------------------------------------- */ + bufptr = (char *)malloc(BUFFER_SIZE * 4096 + 511); + alignedbufptr = (char*)(((((long)bufptr + 511) << 9) >> 9) & ~((long)0x1ff)); + alignedbufptr = (char*)(bufptr - (char*)(((long)bufptr << 9)>>9) + alignedbufptr); + + logSize = atoi(inputParms->logSize); + startingPage = atoi(inputParms->startingPage); + + offsetll = (offset_t)startingPage * 4096; + if (llseek(fhSource, offsetll, SEEK_SET) == -1) + { + sprintf(errorHelpString, "llseek() failed, errno = %d%s", + errno, NEW_LINE); + + rc = RC_UNKNOWN; + goto exit; + } + + while (logSize > 0) + { + if (logSize > BUFFER_SIZE) + { + numBytes = BUFFER_SIZE * 4096; + logSize -= BUFFER_SIZE; + } + else + { + numBytes = logSize * 4096; + logSize = 0; + } + + rc = read(fhSource, alignedbufptr, numBytes); + if (rc != numBytes) + { + sprintf(errorHelpString, + "read %d bytes failed, rc = %d, errno = %d%s", + numBytes, rc, errno, NEW_LINE); + + rc = RC_UNKNOWN; + goto exit; + } + + rc = write(fhTarget, alignedbufptr, numBytes); + if (rc != numBytes) + { + sprintf(errorHelpString, + "write %d bytes failed, rc = %d, errno = %d%s", + numBytes, rc, errno, NEW_LINE); + + rc = RC_UNKNOWN; + goto exit; + } + } + + rc = RC_OK; + close(fhTarget); + close(fhSource); + } + +exit: + if (bufptr != NULL) + free(bufptr); + + return( rc ); +} + + +/*********************************************************************/ +/* RetrieveFile() - Retrieve a log file from disk */ +/*********************************************************************/ +unsigned int + RetrieveFile( INPUT_PARMS *inputParms, + char *systemCallParms, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + FILE *tempFp = NULL ; /* temporary file pointer*/ + unsigned int rc = RC_OK ; /* function return code */ + signed int systemCallRc = RC_OK ; /* system call rc */ + char fileToRetrieve[ FILE_NAME_LEN ] ; + /* file to be retrieved */ + char tempFile[FILE_NAME_LEN]; + + memset( fileToRetrieve, '\0', FILE_NAME_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Construct the file to retrieve */ + /* -------------------------------------------------------------- */ + sprintf( fileToRetrieve, /* file to be retrieved */ + "%s%s%s%s%s%s%s", /* format of parm string */ + RETRIEVE_PATH, /* user RETRIEVE path */ + inputParms->dbName, /* database name */ + SLASH, /* slash character */ + inputParms->nodeNumber, /* node number */ + SLASH, /* slash character */ + inputParms->logFile, /* log file name */ + NULL_TERM ) ; /* NULL terminator */ + + strcpy(tempFile, inputParms->logFilePath); + strcat(tempFile, inputParms->logFile); + strcpy(&tempFile[strlen(tempFile) - 3], "TMP"); + + /* -------------------------------------------------------------- */ + /* Construct the retrieve system call string */ + /* -------------------------------------------------------------- */ + sprintf( systemCallParms, /* parameter string */ + "%s %s %s%s", /* format of parm string */ + COPY, /* system copy command */ + fileToRetrieve, /* file to retrieve */ + tempFile, /* target file name */ + NULL_TERM ) ; /* NULL terminator */ + + systemCallRc = system( systemCallParms ) ; + + if ( systemCallRc != RC_OK ) + { + /* ----------------------------------------------------------- */ + /* Check to see if the file exists */ + /* ----------------------------------------------------------- */ + if (( tempFp = fopen( fileToRetrieve, "rb" )) == NULL ) + { + /* File not in RETRIEVE_PATH, return OK to DB2 */ + rc = RC_OK; + } + else + { + ( void ) fclose( tempFp ) ; /* close the file */ + + sprintf( errorHelpString, "%s %d %s%s", + "Error retrieving file. Return code", systemCallRc, + "received from the system call", NEW_LINE ) ; + + rc = RC_UNKNOWN ; /* copy failed */ + } + } + else + { + /* rename the .TMP file to .LOG file */ + sprintf(systemCallParms, "mv %s %s%s", + tempFile, inputParms->logFilePath, + inputParms->logFile); + rc = system(systemCallParms); + if (rc != RC_OK) + { + sprintf(errorHelpString,"Filed to rename temp file, rc = %d", + rc); + rc = RC_UNKNOWN; + } + } + + return( rc ) ; +} + + +/*********************************************************************/ +/* SignalEnd() - If a signal has been raised for which we have */ +/* installed a handler, perform the following: */ +/* . trace the signal in the error log (if enabled) */ +/* . exit the user exit with a RC_OPCAN return code */ +/*********************************************************************/ +void SignalEnd( int sigNum ) +{ + unsigned int userExitRc ; /* user exit return code */ + char errorHelpString[ HELP_STRING_LEN ] ; + /* error help string */ + + /* -------------------------------------------------------------- */ + /* Set the user exit return code to operator cancelled */ + /* -------------------------------------------------------------- */ + userExitRc = RC_OPCAN ; + + /* -------------------------------------------------------------- */ + /* Log the error if the error log has been requested */ + /* -------------------------------------------------------------- */ + if ( ERROR_ACTIVE ) + { + memset( errorHelpString, '\0', HELP_STRING_LEN ) ; + + sprintf( errorHelpString, "%s %d %s %s%s", "Signal", sigNum, + ( sigNum == SIGTERM ) ? "(SIGTERM)" : "(SIGINT)", + "has been raised", NEW_LINE ) ; + + ErrorLog( NULL, NULL, NULL, userExitRc, errorHelpString ) ; + } + + /* -------------------------------------------------------------- */ + /* Exit the user exit with the appropriate return code */ + /* -------------------------------------------------------------- */ + exit( userExitRc ) ; +} + + +/*********************************************************************/ +/* AuditLogStart() - Log the following at user exit entrance: */ +/* 1. time system call was made */ +/* 2. parameters passed to the user exit */ +/* 3. system action */ +/* 4. media type */ +/*********************************************************************/ +unsigned int + AuditLogStart( INPUT_PARMS *inputParms, + char *auditFileName, + char *errorHelpString ) +{ + FILE *auditLogFp ; /* pointer to audit log file */ + unsigned int auditLogRc ; /* AuditLogStart() return code*/ + time_t actionTime ; /* date and time of exit start*/ + char outputLine[ OUTPUT_LINE_LEN ] ; + /* line to be written to log */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + auditLogFp = NULL ; + auditLogRc = RC_OK ; + memset( &actionTime, 0, sizeof( actionTime )) ; + memset( outputLine, '\0', OUTPUT_LINE_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Open the audit log file using the appropriate file name and */ + /* user defined file attributes */ + /* -------------------------------------------------------------- */ + auditLogFp = fopen( auditFileName, AUDIT_ERROR_ATTR ) ; + + /* -------------------------------------------------------------- */ + /* If the audit log file opened successfully, write the data to */ + /* the file */ + /* -------------------------------------------------------------- */ + if ( auditLogFp != NULL ) + { + memset( outputLine, '*', DELIMITER_LEN ) ; + outputLine[ DELIMITER_LEN ] = '\n' ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + time( &actionTime ) ; /* time user exit started */ + sprintf( outputLine, + "%s%s%s", + "Time Started: ", + ctime( &actionTime ), + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + if ( PrintArguments( auditLogFp, inputParms ) != RC_OK ) + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( outputLine, /* system action */ + "%s %s %s %s file %s %s %s%s%s", + "System Action: ", + inputParms->request, + ( archiveRequested ) ? "from" : "to", + inputParms->logFilePath, + inputParms->logFile, + ( archiveRequested ) ? "to" : "from", + ( archiveRequested ) ? ARCHIVE_PATH : RETRIEVE_PATH, + inputParms->dbName, + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( outputLine, /* user defined media type */ + "%s %s%s", + "Media Type: ", + MEDIA_TYPE, + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + /* ----------------------------------------------------------- */ + /* If an error was encountered during the audit log write */ + /* ----------------------------------------------------------- */ + if ( auditLogRc == AUDIT_IO_ERROR ) + { + sprintf( errorHelpString,"%s%s", + "Error writing to the Audit Log file", NEW_LINE ) ; + + ( void ) fclose( auditLogFp ) ; + } + else + { + if ( fclose( auditLogFp ) ) + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString, "%s%s", + "Error closing Audit Log file", NEW_LINE ) ; + } + } + } + else /* error opening file */ + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString,"%s%s", + "Error opening Audit Log file",NEW_LINE ) ; + } + + return( auditLogRc ) ; +} + + +/*********************************************************************/ +/* AuditLogEnd() - Log the following at user exit end: */ +/* 1. time system call returned */ +/* 2. user exit return code */ +/*********************************************************************/ +unsigned int + AuditLogEnd( char *auditFileName, + unsigned int userExitRc, + char *errorHelpString ) +{ + FILE *auditLogFp ; /* pointer to audit log file */ + unsigned int auditLogRc ; /* AuditLogEnd() return code */ + time_t actionTime ; /* date and time of exit end */ + char outputLine[OUTPUT_LINE_LEN]; + /* line to be written to log */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + auditLogFp = NULL ; + auditLogRc = RC_OK ; + memset( &actionTime, 0, sizeof( actionTime )) ; + memset( outputLine, '\0', OUTPUT_LINE_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Open the audit log file using the appropriate file name and */ + /* user defined file attributes */ + /* -------------------------------------------------------------- */ + auditLogFp = fopen( auditFileName, AUDIT_ERROR_ATTR ) ; + + /* -------------------------------------------------------------- */ + /* If the audit log file opened successfully, write the data to */ + /* the file */ + /* -------------------------------------------------------------- */ + if ( auditLogFp != NULL ) + { + sprintf( outputLine, /* user exit return code */ + "%s %d %s%s", + "User Exit RC: ", + userExitRc, + ( userExitRc ) ? "|||> ERROR <|||" : errorHelpString, + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + time( &actionTime ) ; /* time user exit completed */ + sprintf( outputLine, + "%s %s%s", + "Time Completed: ", + ctime( &actionTime ), + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + /* ----------------------------------------------------------- */ + /* If an error was encountered during the audit log write */ + /* ----------------------------------------------------------- */ + if ( auditLogRc == AUDIT_IO_ERROR ) + { + sprintf( errorHelpString,"%s%s", + "Error writing to the Audit Log file", NEW_LINE ) ; + + ( void ) fclose( auditLogFp ) ; + } + else + { + if ( fclose( auditLogFp ) ) + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString,"%s%s", + "Error closing Audit Log file", NEW_LINE ) ; + } + } + } + else /* error opening file */ + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString, "%s%s", + "Error opening Audit Log file", NEW_LINE ) ; + } + + return( auditLogRc ) ; +} + + +/*********************************************************************/ +/* ErrorLog() - Log the following if an error has occurred: */ +/* . time the error occurred */ +/* . values of parameters passed to the user exit */ +/* . media type */ +/* . audit log file name */ +/* . system call string */ +/* . user exit return code */ +/* . error isolation help string */ +/*********************************************************************/ +void ErrorLog( INPUT_PARMS *inputParms, + char *auditFileName, + char *systemCallParms, + unsigned int userExitRc, + char *errorHelpString ) +{ + FILE *errorLogFp ; /* pointer to error log file */ + time_t actionTime ; /* date and time of error */ + char outputLine[ OUTPUT_LINE_LEN ] ; + /* line to be written to log */ + char errorFileName[ FILE_NAME_LEN ] ; + /* error log file name */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + errorLogFp = NULL ; + memset( &actionTime, 0, sizeof( actionTime )) ; + memset( outputLine, '\0', OUTPUT_LINE_LEN ) ; + memset( errorFileName, '\0', FILE_NAME_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Open the error log file using the user defined name and file */ + /* attributes */ + /* -------------------------------------------------------------- */ + sprintf( errorFileName, + "%s%s", + AUDIT_ERROR_PATH, /* error log path */ + ERROR_FILE_NAME ) ; /* error log file name */ + + errorLogFp = fopen( errorFileName, AUDIT_ERROR_ATTR ) ; + + /* -------------------------------------------------------------- */ + /* If the error log file opened successfully, write the available */ + /* data to the file */ + /* -------------------------------------------------------------- */ + if ( errorLogFp != NULL ) + { + memset( outputLine, '*', DELIMITER_LEN ) ; + outputLine[ DELIMITER_LEN ] = '\n' ; + fprintf( errorLogFp, outputLine ) ; + + time( &actionTime ) ; /* time error occurred */ + sprintf( outputLine, + "%s %s%s", + "Time of Error: ", + ctime( &actionTime ), + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + + if ( inputParms != NULL ) /* parmeters passed to user */ + { /* exit */ + (void) PrintArguments( errorLogFp, inputParms ) ; + } + + sprintf( outputLine, /* audit log file name */ + "%s %s%s", + "Audit Log File: ", + auditFileName, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* system call string */ + "%s %s%s", + "System Call Parms:", + systemCallParms, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* user defined media type */ + "%s %s%s", + "Media Type: ", + MEDIA_TYPE, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* user exit return code */ + "%s %d %s%s", + "User Exit RC: ", + userExitRc, + NEW_LINE, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* error isolation string */ + "%s %s%s%s", + "> Error isolation:", + errorHelpString, + NEW_LINE, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + /* ----------------------------------------------------------- */ + /* Close the error log file */ + /* ----------------------------------------------------------- */ + fclose( errorLogFp ) ; + } + + return ; +} + + +unsigned int + ParseArguments( int argc , + char *argv[] , + INPUT_PARMS *inputParms , + char *errorHelpString ) +{ + int parseRc; /* ParseArguments() return code */ + int count; /* index for for loop */ + char *argument; /* pointer to argument */ + int parmLen; /* length of parameter */ + int parmIden; /* parameter identifier */ + char *parmValue; /* parameter value */ + + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + parseRc = RC_OK ; + count = 1 ; + + /* -------------------------------------------------------------- */ + /* Copy values into inputParms structure. */ + /* -------------------------------------------------------------- */ + inputParms->argc = argc; + + while ( ( count < argc ) && ( parseRc == RC_OK) ) + { + argument = argv[count]; + + parmLen = strlen(argument); + if (parmLen < 4) + { + parseRc = RC_PARM; + break; + } + + parmIden = ((argument[2]) | (argument[1] << 8) | (argument[0] << 16)); + parmValue = &argument[3]; + +#define INPUT_PARM_AP 0x2d4150 /* -AP */ +#define INPUT_PARM_DB 0x2d4442 /* -DB */ +#define INPUT_PARM_LN 0x2d4c4e /* -LN */ +#define INPUT_PARM_LB 0x2d4c42 /* -LB */ +#define INPUT_PARM_LP 0x2d4c50 /* -LP */ +#define INPUT_PARM_LS 0x2d4c53 /* -LS */ +#define INPUT_PARM_MD 0x2d4d44 /* -MD */ +#define INPUT_PARM_NN 0x2d4e4e /* -NN */ +#define INPUT_PARM_OS 0x2d4f53 /* -OS */ +#define INPUT_PARM_RD 0x2d5244 /* -RD */ +#define INPUT_PARM_RF 0x2d5246 /* -RF */ +#define INPUT_PARM_RL 0x2d524c /* -RL */ +#define INPUT_PARM_RQ 0x2d5251 /* -RQ */ +#define INPUT_PARM_SP 0x2d5350 /* -SP */ + + switch(parmIden) + { + case INPUT_PARM_AP: /* ADSM password */ + inputParms->adsmPasswd = parmValue; + break; + case INPUT_PARM_DB: /* database name */ + inputParms->dbName = parmValue; + break; + case INPUT_PARM_LN: /* log file name */ + inputParms->logFile = parmValue; + break; + case INPUT_PARM_LB: /* label */ + inputParms->label = parmValue; + break; + case INPUT_PARM_LP: /* log file path */ + inputParms->logFilePath = parmValue; + break; + case INPUT_PARM_LS: /* log file size */ + inputParms->logSize = parmValue; + break; + case INPUT_PARM_MD: /* mode */ + inputParms->mode = parmValue; + break; + case INPUT_PARM_NN: /* node number */ + inputParms->nodeNumber = parmValue; + break; + case INPUT_PARM_OS: /* operating system */ + inputParms->operatingSys = parmValue; + break; + case INPUT_PARM_RD: /* redirection file */ + inputParms->redFile = parmValue; + break; + case INPUT_PARM_RF: /* response file */ + inputParms->responseFile = parmValue; + break; + case INPUT_PARM_RL: /* DB2 release */ + inputParms->release = parmValue; + break; + case INPUT_PARM_RQ: /* user exit request */ + inputParms->request = parmValue; + break; + case INPUT_PARM_SP: /* starting page offset */ + inputParms->startingPage = parmValue; + break; + default: /* log unrecognized parameter */ + if ( ERROR_ACTIVE ) + { + memset( errorHelpString, '\0', HELP_STRING_LEN ) ; + + sprintf( errorHelpString, + "%s %s%s%s%s", + "Unrecognized parameter :", + argument, + NEW_LINE, + "Parameter has been ignored.", + NEW_LINE ) ; + + ErrorLog( NULL, NULL, NULL, RC_OK, errorHelpString ) ; + } + break; + } + + count ++ ; /* increment count */ + } + + return(parseRc); +} + + + +unsigned int + PrintArguments(FILE *fp, INPUT_PARMS *inputParms) +{ + char outputLine[ OUTPUT_LINE_LEN ] ; + int printRc = RC_OK ; + + sprintf( outputLine, + "%s %d%s", + "Parameter Count: ", + inputParms->argc, + NEW_LINE ) ; + + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR ; + + if ( printRc == RC_OK ) + { + sprintf( outputLine, + "%s %s", + "Parameters Passed:", + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->adsmPasswd != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "ADSM password: ", + inputParms->adsmPasswd, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->dbName != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Database name: ", + inputParms->dbName, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->logFile != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Logfile name: ", + inputParms->logFile, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->label != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Label: ", + inputParms->label, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->logFilePath != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Logfile path: ", + inputParms->logFilePath, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->logSize != NULL ) ) + { + sprintf(outputLine, + "%s%s 4K pages%s", + "Logfile size: ", + inputParms->logSize, + NEW_LINE); + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->mode != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Mode: ", + inputParms->mode, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->nodeNumber != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Node number: ", + inputParms->nodeNumber, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->operatingSys != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Operating system: ", + inputParms->operatingSys, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->redFile != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Red file: ", + inputParms->redFile, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->responseFile != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Response file: ", + inputParms->responseFile, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->release != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Release: ", + inputParms->release, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->request != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Request: ", + inputParms->request, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->startingPage != NULL ) ) + { + sprintf(outputLine, + "%s %s%s", + "Starting page offset: ", + inputParms->startingPage, + NEW_LINE); + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + return(printRc); +} diff --git a/c/db2uext2.ctape b/c/db2uext2.ctape new file mode 100644 index 0000000..74aa875 --- /dev/null +++ b/c/db2uext2.ctape @@ -0,0 +1,2052 @@ +/****************************************************************************** + * + * Source File Name = db2uext2.ctape + * + * Licensed Materials - Property of IBM + * + * (C) COPYRIGHT International Business Machines Corp. 1996. + * All Rights Reserved + * + * US Government Users Restricted Rights - Use, duplication or + * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + * + * Function = Sample Log Management User Exit C Source Code + * + *****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* Sample Name: db2uext2.ctape */ +/* */ +/* */ +/* Purpose: This is a sample User Exit utilizing the AIX system tape */ +/* commands to Archive and Retrieve database log files. All */ +/* limitations of the AIX system tape commands are limitations */ +/* of this user exit. */ +/* */ +/* */ +/* Options: 1. This sample provides an audit trail of calls ( stored in a */ +/* separate file for each option ) including a timestamp and */ +/* parameters received. This option can be disabled. */ +/* */ +/* 2. This sample provides an error trail of calls in error */ +/* including a timestamp and an error isolation string for */ +/* problem determination. This option can be disabled. */ +/* */ +/* */ +/* Usage: 1. Copy "db2uext2.ctape" to "db2uext2.c" and place this file */ +/* into a working directory. */ +/* */ +/* 2. Modify the "Installation Defined Variables" to suit your */ +/* environment. Two example scenarios have been provided */ +/* below for illustrative purposes. */ +/* */ +/* 3. Modify the program logic to suit your environment. If */ +/* there are situations where the user exit program fails on */ +/* archive request and you want DB2 to retry the request, set */ +/* the return code to RC_OPATTN. */ +/* */ +/* 4. Compile and link "db2uext2.c" with the following command: */ +/* "cc -o db2uext2 db2uext2.c" or a functional equivalent. */ +/* Place the resultant "db2uext2" named executable */ +/* into sqllib/adm. */ +/* */ +/* *** NOTE *** Code/command modification may be required */ +/* depending on compiler options used and */ +/* header file location */ +/* */ +/* 5. DB2 calls "db2uext2" in the following format - */ +/* */ +/* db2uext2 -OS -RL -RQ -DB */ +/* -NN -LP -LN */ +/* [-AP] */ +/* */ +/* where: os = operating system */ +/* release = DB2 release */ +/* request = 'ARCHIVE' or 'RETRIEVE' */ +/* dbname = database name */ +/* nodenumber = node number */ +/* logpath = log file path */ +/* logname = log file name */ +/* adsmpasswd = ADSM password (optional) */ +/* */ +/* 6. This user exit is designed to handle both archiving and */ +/* retrieving to and from the SAME tape. As such, the */ +/* performance tends to slow down as the tape fills. We have */ +/* listed performance tips you may wish to make to improve */ +/* the performance. */ +/* */ +/* 7. Log files are archived and retrieved from tape with the */ +/* following file naming convention: */ +/* */ +/* database name + . + node number + . + log file name */ +/* */ +/* For example: If the database name was "SAMPLE", the node */ +/* number was NODE0000 and the log file name was */ +/* "S0000001.LOG", the image of the log file */ +/* would be named "SAMPLE.NODE0000.S0000001.LOG" */ +/* */ +/* Note: This sample program may not work properly on multiple */ +/* logical nodes, because multiple instances of the user */ +/* exit may attempt to remove or create the temporary */ +/* directory at the same time. */ +/* */ +/* */ +/* Logic Flow: 1. install signal handlers */ +/* 2. verify the number of parameters passed */ +/* 3. verify the action requested */ +/* 4. start the audit trail ( if requested ) */ +/* 5. cleanup the working environment by removing and creating */ +/* a temporary directory to hold the archived or retrieved */ +/* log file before/after transferring it to/from tape */ +/* 6. if the requested action is to archive a file: */ +/* . copy the log file to be archived from the log path to */ +/* the temporary directory */ +/* if the log file is not found, proceed to point 16 */ +/* 7. open the tape */ +/* 8. rewind the tape */ +/* 9. close the tape */ +/* 10. if the requested action is to archive a file: */ +/* . search the tape to find the next available location */ +/* and store the location for future use */ +/* if the requested action is to retrieve a file: */ +/* . search the tape to find the file and store the location */ +/* for future use */ +/* . if the log file is not found, proceed to point 16 */ +/* 11. open the tape */ +/* 12. rewind the tape */ +/* 13. forward the tape to the stored location */ +/* 14. close the tape */ +/* 15. if the requested action is to archive a file: */ +/* . copy the log file from the temporary directory onto */ +/* the tape */ +/* if the requested action is to retrieve a file: */ +/* . copy the log file to the temporary directory from the */ +/* tape */ +/* . copy the retrieved log file from the temporary directory */ +/* to the log path */ +/* 16. cleanup the working environment by removing the temporary */ +/* directory */ +/* 17. log errors ( if requested and required ) */ +/* 18. end the audit trail ( if requested ) */ +/* 19. exit with the appropriate return code */ +/* */ +/* */ +/* Performance */ +/* Tips: 1. Archiving files to tape */ +/* . If you can guarantee that no retrieving of files will */ +/* take place when you are archiving, you will be able */ +/* to remove the logic listed in points 7 to 14. */ +/* This may improve performance drastically as no rewinding */ +/* or file searching will be attempted. */ +/* However, before connecting to the database, you must */ +/* forward the tape to the point after the last file on the */ +/* tape to prevent the logs from overwriting existing data. */ +/* . If you make the change listed above, do not use a device */ +/* configured for automatic rewinding as you will be */ +/* constantly overwriting the first file on the tape. */ +/* */ +/* 2. Retrieving files from tape */ +/* . If you can guarantee that no archiving of files will */ +/* take place then you are retrieving and the log files */ +/* being retrieved were archived in order to the same tape */ +/* and the tape does not contain log files from any other */ +/* database, you will be able to remove the logic listed in */ +/* points 7 to 14. This may improve performance drastically */ +/* as no rewinding or file searching will be attempted. */ +/* However, before connecting to the database, you must */ +/* forward the tape to the point at which the first log */ +/* file to be retrieved resides to prevent an incorrect log */ +/* file from being retrieved. */ +/* . If you make the change listed above, do not use a device */ +/* configured for automatic rewinding as you will be */ +/* constantly reading the first file on the tape. */ +/* */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*===========================================================================*/ +/*== ==*/ +/*== ------------------ INSTALLATION DEFINED VARIABLES ------------------- ==*/ +/*== ==*/ +/*== -------------------- REQUIRES USER MODIFICATION --------------------- ==*/ +/*== ==*/ +/*===========================================================================*/ +/*== TAPE_DEV: Physical name of the tape device ==*/ +/*== Notes: 1. this user exit is designed for a tape device in ==*/ +/*== non-rewinding mode ( ie. rmtx.1 ) ==*/ +/*== 2. any change to the device may require ==*/ +/*== modification to the user exit logic ==*/ +/*== 3. the default device is "/dev/rmt0.1" ==*/ +/*== ==*/ +/*== TAPE_PERM: Tape device open permissions ==*/ +/*== Notes: 1. the default permissions are "0666" ==*/ +/*== ==*/ +/*== TEMP_DIR: Temporary directory used to store tape image of the log ==*/ +/*== file to be archived or retrieved ==*/ +/*== Notes: 1. will be CREATED and REMOVED by the user exit ==*/ +/*== 2. the default temporary directory is ==*/ +/*== "/tmp/UserExits" ==*/ +/*== ==*/ +/*== AUDIT_ACTIVE: The user may wish an audit trail of the user exit run. ==*/ +/*== Sample audit functions have been provided ==*/ +/*== ( AuditLogStart() and AuditLogEnd() ) ==*/ +/*== Notes: 1. enable audit logging by setting AUDIT_ACTIVE ==*/ +/*== to 1 ==*/ +/*== 2. disable audit logging by setting ==*/ +/*== AUDIT_ACTIVE to 0 ==*/ +/*== 3. archive requests will be traced in a file ==*/ +/*== named "ARCHIVE.LOG" located in the audit and ==*/ +/*== error file path ==*/ +/*== 4. retrieve requests will be traced in a file ==*/ +/*== named "RETRIEVE.LOG" located in the audit ==*/ +/*== and error file path ==*/ +/*== 5. the default setting is enable audit ==*/ +/*== logging ==*/ +/*== ==*/ +/*== ERROR_ACTIVE: The user may wish an error trail of the user exit run. ==*/ +/*== A sample error log function has been provided ==*/ +/*== ( ErrorLog() ) ==*/ +/*== Notes: 1. enable error logging by setting ERROR_ACTIVE ==*/ +/*== to 1 ==*/ +/*== 2. disable error logging by setting ==*/ +/*== ERROR_ACTIVE to 0 ==*/ +/*== 3. errors will be traced in a file named ==*/ +/*== "USEREXIT.ERR" located in the audit and ==*/ +/*== error file path ==*/ +/*== 4. the default setting is enable error ==*/ +/*== logging ==*/ +/*== ==*/ +/*== AUDIT_ERROR_PATH: Path where Audit and Error logs will reside ==*/ +/*== Notes: 1. the path must exist ( the user exit will ==*/ +/*== not create the path ) ==*/ +/*== 2. the path must end with a back slash ==*/ +/*== 3. do not make the path the same as TEMP_DIR ==*/ +/*== ( TEMP_DIR is removed ) ==*/ +/*== 4. the default is "/u/" ==*/ +/*== ==*/ +/*== AUDIT_ERROR_ATTR: Standard C file open attributes for the Audit and ==*/ +/*== Error logs ==*/ +/*== Notes: 1. the default is "a" (text append) ==*/ +/*== ==*/ + +#define TAPE_DEV "/dev/rmt0.1" /* non-rewinding device */ +#define TAPE_PERM 666 /* tape permissions */ +#define TEMP_DIR "/tmp/UserExits" /* created and removed by the */ + /* user exit */ + +#define AUDIT_ACTIVE 1 /* enable audit trail logging */ +#define ERROR_ACTIVE 1 /* enable error trail logging */ +#define AUDIT_ERROR_PATH "/u/" /* path must end with a slash */ +#define AUDIT_ERROR_ATTR "a" /* append to text file */ + + +/*===========================================================================*/ +/*== ==*/ +/*== ------------------------ EXAMPLE SCENARIOS -------------------------- ==*/ +/*== ( FOR ILLUSTRATIVE PURPOSES ONLY ) ==*/ +/*== ==*/ +/*===========================================================================*/ +/*== ==*/ +/*== 1) Given that we are "userid1", are working with a database ==*/ +/*== named "SAMPLE1" on node NODE0001 and have modified the ==*/ +/*== installation defined variables to the following values: ==*/ +/*== ==*/ +/*== TAPE_DEV "/dev/rmt0.1" ==*/ +/*== TEMP_DIR "/tmp/UserExits" ==*/ +/*== AUDIT_ACTIVE 1 ==*/ +/*== ERROR_ACTIVE 1 ==*/ +/*== AUDIT_ERROR_PATH "/u/userid1/AuditLogs/" ==*/ +/*== AUDIT_ERROR_ATTR "a" ==*/ +/*== ==*/ +/*== If a request is received to archive log S0000000.LOG: ==*/ +/*== ==*/ +/*== . the audit log would be opened in append text mode and be named: ==*/ +/*== ==> "/u/userid1/AuditLogs/ARCHIVE.LOG" ==*/ +/*== ( AUDIT_ERROR_PATH + archive audit log file name ) ==*/ +/*== ==*/ +/*== . a temporary directory would be created and be named: ==*/ +/*== ==> "/tmp/UserExits" ==*/ +/*== ( TEMP_DIR ) ==*/ +/*== ==*/ +/*== . a tape image name for the log file would be created named: ==*/ +/*== ==> "SAMPLE1.NODE0001.S0000000.LOG" ==*/ +/*== ( database name + node number + log file name ) ==*/ +/*== ==*/ +/*== . the log file would be copied from the log path directory ==*/ +/*== for database "SAMPLE1" to the temporary directory as: ==*/ +/*== ==> "/tmp/UserExits/SAMPLE1.NODE0001.S0000000.LOG" ==*/ +/*== ( TEMP_DIR + temporary log file name ) ==*/ +/*== ==*/ +/*== . the temporary directory log file image would be archived to: ==*/ +/*== ==> "/dev/rmt0.1" as "SAMPLE1.NODE0001.S0000000.LOG" ==*/ +/*== ( TAPE_DEV ) ( tape image name ) ==*/ +/*== ==*/ +/*== . the error log would be opened in append text mode and be named: ==*/ +/*== ==> "/u/userid1/AuditLogs/USEREXIT.ERR" ==*/ +/*== ( AUDIT_ERROR_PATH + error log file name ( defined below ) ) ==*/ +/*== ==*/ +/*== ==*/ +/*== 2) Given that we are "userid2", are working with a database ==*/ +/*== named "SAMPLE2" on node NODE0000 and have modified the ==*/ +/*== installation defined variables to the following values: ==*/ +/*== ==*/ +/*== TAPE_DEV "/dev/rmt2.1" ==*/ +/*== TEMP_DIR "/u/userid2/tmp" ==*/ +/*== AUDIT_ACTIVE 1 ==*/ +/*== ERROR_ACTIVE 0 ==*/ +/*== AUDIT_ERROR_PATH "/u/userid2/Audit/Logs/" ==*/ +/*== AUDIT_ERROR_ATTR "w" ==*/ +/*== ==*/ +/*== If a request is received to retrieve log S0000001.LOG: ==*/ +/*== ==*/ +/*== . the audit log would be opened in write text mode and be named: ==*/ +/*== ==> "/u/userid2/Audit/Logs/RETRIEVE.LOG" ==*/ +/*== ( AUDIT_ERROR_PATH + retrieve audit log file name ) ==*/ +/*== ==*/ +/*== . a temporary directory would be created and be named: ==*/ +/*== ==> "/u/userid2/tmp" ==*/ +/*== ( TEMP_DIR ) ==*/ +/*== ==*/ +/*== . a tape image name for the log file would be created named: ==*/ +/*== ==> "SAMPLE2.NODE0000.S0000001.LOG" ==*/ +/*== ( database name + node number log file name ) ==*/ +/*== ==*/ +/*== . the tape log file image would be retrieved from: ==*/ +/*== ==> "/dev/rmt2.1" as "SAMPLE2.NODE0000.S0000001.LOG" ==*/ +/*== and placed into the temporary directory as: ==*/ +/*== ==> "/u/userid2/tmp/SAMPLE2.NODE0000.S0000001.LOG" ==*/ +/*== ( TEMP_DIR + tape image name ) ==*/ +/*== ==*/ +/*== . the tape image would be copied from the temporary directory to ==*/ +/*== the log path directory for database "SAMPLE2" as: ==*/ +/*== ==> "S0000001.LOG" ==*/ +/*== ( log file name ) ==*/ +/*== ==*/ +/*== . the error log would not be activated ==*/ +/*== ==*/ +/*===========================================================================*/ + + +/* ----------------------------------------------------------------- */ +/* User Exit Supported Return Codes */ +/* NOTE: DB2 will reinvoke the user exit for the same request */ +/* after 5 minutes if return code is 4 or 8. */ +/* */ +/* For other non-zero return codes, DB2 will not invoke */ +/* user exit for the database for at least 5 minutes. */ +/* If this request is to archive a log file, DB2 will not */ +/* make another archive request for this file, or other */ +/* log files produced during the 5 minute time period. */ +/* These log files will only be archived when all */ +/* applications disconnect from and the database, and the */ +/* database is reopenned. */ +/* ----------------------------------------------------------------- */ +#define RC_OK 0 /* ok */ +#define RC_RES 4 /* resource allocation error */ +#define RC_OPATTN 8 /* operator/user attention required*/ +#define RC_HARDWARE 12 /* hardware error */ +#define RC_DEFECT 16 /* software error */ +#define RC_PARM 20 /* invalid parameters */ +#define RC_NOTFOUND 24 /* db2uext2() / file not found */ +#define RC_UNKNOWN 28 /* unknown error */ +#define RC_OPCAN 32 /* operator/user terminated */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Constants */ +/* ----------------------------------------------------------------- */ +#define NUM_VALID_PARMS 5 /* number of valid parameters */ +#define SLASH "/" /* default slash character */ +#define NEW_LINE "\n" /* new line character */ +#define NULL_TERM "\0" /* null terminator */ +#define FILE_EXT ".LOG" /* audit log file extension/type */ +#define MEDIA_TYPE "tape" /* media type used */ +#define AUDIT_IO_ERROR 99 /* audit log I/O error */ +#define SYSTEM_CALL_LEN 550 /* system call string length */ +#define OUTPUT_LINE_LEN 550 /* output line length */ +#define FILE_NAME_LEN 255 /* file name length */ +#define HELP_STRING_LEN 80 /* error help string length */ +#define DELIMITER_LEN 80 /* delimiter length */ +#define PIPE_COMMAND_LEN 80 /* pipe command length */ +#define TAPE_FILE_LEN 32 /* tape file name length */ +#define COPY "cp" /* disk copy command */ +#define MKDIR "mkdir" /* make directory command */ +#define RMDIR "rm -rf" /* remove command (with force) */ +#define CHANGE_DIR "cd" /* change directory command */ +#define DOT "." /* file name separator */ +#define SEMI_COLON ";" /* command separator */ + +#define ARCHIVE_COMMAND "tar -cvf" /* copy file to tape command */ +#define RETRIEVE_COMMAND "tar -xvf" /* copy file from tape command */ +#define QUERY_COMMAND "tar -tf" /* query file on tape command */ +#define ERROR_FILE_NAME "USEREXIT.ERR" + /* error log file name */ + + +/* ----------------------------------------------------------------- */ +/* Define TRUE and FALSE if required */ +/* ----------------------------------------------------------------- */ +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +/* ----------------------------------------------------------------- */ +/* Define structure for input parameters */ +/* ----------------------------------------------------------------- */ +typedef struct input_parms +{ + int argc; + char* adsmPasswd; + char* dbName; + char* logFile; + char* label; + char* logFilePath; + char* mode; + char* nodeNumber; + char* operatingSys; + char* redFile; + char* responseFile; + char* release; + char* request; +} INPUT_PARMS; + +/* ----------------------------------------------------------------- */ +/* Print error to Error Log macro */ +/* ----------------------------------------------------------------- */ +#define PrintErr { if ( ERROR_ACTIVE ) \ + { \ + ErrorLog( inputParms, auditFileName, \ + systemCallParms, userExitRc, \ + errorHelpString) ; \ + } \ + } + + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototypes for Archive, Retrieve and Data */ +/* Manipulation */ +/* ----------------------------------------------------------------- */ +unsigned int + ArchiveFile( char *, /* system call parameters */ + char *, /* tape file image name */ + char * ) ; /* error isolation string */ + +unsigned int + RetrieveFile( char *, /* system call parameters */ + char *, /* tape file image name */ + char * ) ; /* error isolation string */ + +void RemoveTempDir() ; /* no parameters */ + +unsigned int + CreateTempDir( char *, /* system call parameters */ + char * ) ; /* error isolation string */ + +unsigned int + CopyFile( char *, /* system call parameters */ + char *, /* tape file image name */ + INPUT_PARMS *, /* input parameters structure */ + unsigned int *, /* file missing flag */ + char * ) ; /* error isolation string */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototypes for Tape Management */ +/* ----------------------------------------------------------------- */ +unsigned int + TapeOpen( signed int *, /* tape device file descriptor */ + char * ) ; /* error isolation string */ + +unsigned int + TapeClose( signed int, /* tape device file descriptor */ + char * ) ; /* error isolation string */ + +unsigned int + TapeRewind( signed int, /* tape device file descriptor */ + char * ) ; /* error isolation string */ + +unsigned int + TapeForward( signed int, /* tape device file descriptor */ + unsigned int, /* positional tape file count */ + char * ) ; /* error isolation string */ + +unsigned int + TapeFileSearch( char *, /* tape file name */ + unsigned int *, /* positional tape file count */ + unsigned int *, /* file missing flag */ + char * ) ; /* error isolation string */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototype for Signal Handler */ +/* ----------------------------------------------------------------- */ +void SignalEnd( int ) ; /* signal type */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototypes for Audit and Error Logs */ +/* ----------------------------------------------------------------- */ +unsigned int + AuditLogStart( INPUT_PARMS *, /* input parameter structure */ + char *, /* audit file name (with path) */ + char *); /* error isolation string */ + +unsigned int + AuditLogEnd( char *, /* audit file name (with path) */ + unsigned int, /* user exit return code */ + char * ); /* error isolation string */ + +void ErrorLog( INPUT_PARMS *, /* input parameter structure */ + char *, /* audit file name (with path) */ + char *, /* system call parameter string */ + unsigned int, /* user exit return code */ + char * ) ; /* error isolation string */ + +unsigned int + ParseArguments( int , /* input parameter count */ + char * [] , /* input paramter list */ + INPUT_PARMS * , /* input parameter structure */ + char * ) ; /* error help string */ + +unsigned int + PrintArguments( FILE *, /* output file pointer */ + INPUT_PARMS * ) ; /* input parameter structure */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Global Variables */ +/* ----------------------------------------------------------------- */ +unsigned int archiveRequested ; /* archive requested flag */ +unsigned int retrieveRequested ; /* retrieve requested flag */ + + +/*********************************************************************/ +/* User Exit Mainline */ +/*********************************************************************/ +int main( int argc, char *argv[] ) +{ + unsigned int userExitRc ; /* user exit return code */ + unsigned int auditLogRc ; /* return call from audit */ + + INPUT_PARMS inputParmsStruct; + INPUT_PARMS *inputParms = &inputParmsStruct; + + signed int tapeDevFD ; /* tape dev file descriptor*/ + unsigned int fileCount ; /* positional file count */ + unsigned int fileMissing ; /* file missing flag */ + char systemCallParms[ SYSTEM_CALL_LEN ] ; + /* system call parm string */ + char auditFileName[ FILE_NAME_LEN ] ; + /* audit log file name */ + char tapeFileName[ TAPE_FILE_LEN ] ; + /* tape image file name */ + char errorHelpString[ HELP_STRING_LEN ] ; + /* error help string */ + char dummyHelpString[ HELP_STRING_LEN ] ; + /* dummy help string */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + archiveRequested = FALSE ; + retrieveRequested = FALSE ; + userExitRc = RC_OK ; + auditLogRc = RC_OK ; + tapeDevFD = 0 ; + fileCount = 0 ; + fileMissing = FALSE ; + memset( inputParms, '\0', sizeof(INPUT_PARMS) ); + memset( systemCallParms, '\0', SYSTEM_CALL_LEN ) ; + memset( auditFileName, '\0', FILE_NAME_LEN ) ; + memset( tapeFileName, '\0', TAPE_FILE_LEN ) ; + memset( errorHelpString, '\0', HELP_STRING_LEN ) ; + memset( dummyHelpString, '\0', HELP_STRING_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Install signal handlers for terminate and interrupt */ + /* -------------------------------------------------------------- */ + if (( signal( SIGTERM, SignalEnd ) == SIG_ERR ) || + ( signal( SIGINT, SignalEnd ) == SIG_ERR )) + { + userExitRc = RC_DEFECT ; /* handler not installed */ + + sprintf( errorHelpString, "%s%s", + "Unable to install signal handler(s)", NEW_LINE ) ; + + PrintErr ; + } + + /* -------------------------------------------------------------- */ + /* Set the local variables to the passed parameters */ + /* -------------------------------------------------------------- */ + if ( userExitRc == RC_OK ) + { + userExitRc = ParseArguments( argc, argv, inputParms, + errorHelpString ) ; + } + + if ( userExitRc == RC_OK ) + { + + /* ----------------------------------------------------------- */ + /* Determine the user exit action */ + /* ----------------------------------------------------------- */ + if ( (inputParms->request != NULL) && + (strcmp( inputParms->request, "ARCHIVE" ) == 0 ) ) + { + archiveRequested = TRUE ; /* action is ARCHIVE */ + } + else + { + if ( (inputParms->request != NULL) && + (strcmp( inputParms->request, "RETRIEVE" ) == 0 ) ) + { + retrieveRequested = TRUE ; /* action is RETRIEVE */ + } + else + { + userExitRc = RC_PARM ; /* invalid action */ + + sprintf( errorHelpString, "%s %s %s%s", "Action", + inputParms->request, "is not valid", NEW_LINE ) ; + + PrintErr ; + } + } + } + + if ( userExitRc == RC_OK ) + { + /* ----------------------------------------------------------- */ + /* Trace the start of execution if the user has asked for an */ + /* audit log */ + /* ----------------------------------------------------------- */ + if ( AUDIT_ACTIVE ) + { + sprintf( auditFileName, /* audit log file name */ + "%s%s%s", /* format of the name */ + AUDIT_ERROR_PATH, /* audit log file path */ + inputParms->request, /* ARCHIVE or RETRIEVE */ + FILE_EXT ) ; /* file extension/type */ + + auditLogRc = AuditLogStart( + inputParms, /* input parms astructure*/ + auditFileName, /* audit log file name */ + errorHelpString );/* error isolation string*/ + + if ( auditLogRc == AUDIT_IO_ERROR )/* IO error on audit log */ + { + PrintErr ; + } + } + + /* ----------------------------------------------------------- */ + /* Remove and create a temporary directory to hold the log to */ + /* be archived or retrieved */ + /* ----------------------------------------------------------- */ + RemoveTempDir() ; + + userExitRc = CreateTempDir( systemCallParms, + errorHelpString ) ; + + if ( userExitRc == RC_OK ) + { + /* -------------------------------------------------------- */ + /* Create the file name to be archived or retrieved */ + /* -------------------------------------------------------- */ + sprintf( tapeFileName, + "%s%s%s%s%s%s", + inputParms->dbName, /* database name */ + DOT, /* . */ + inputParms->nodeNumber, /* node number */ + DOT, /* . */ + inputParms->logFile, /* log file name */ + NULL_TERM ) ; + + /* -------------------------------------------------------- */ + /* On an archive, copy the log file to the temporary */ + /* directory under the tape file name alias */ + /* -------------------------------------------------------- */ + if ( archiveRequested ) + { + userExitRc = CopyFile( systemCallParms, + tapeFileName, + inputParms, + &fileMissing, + errorHelpString ) ; + } + + /* -------------------------------------------------------- */ + /* Open, rewind and close the tape device */ + /* -------------------------------------------------------- */ + if (( userExitRc == RC_OK ) && + ( !fileMissing )) + { + memset( systemCallParms, '\0', SYSTEM_CALL_LEN ) ; + + userExitRc = TapeOpen( &tapeDevFD, + errorHelpString ) ; + + if ( userExitRc == RC_OK ) + { + userExitRc = TapeRewind( tapeDevFD, + errorHelpString ) ; + + if ( userExitRc == RC_OK ) + { + userExitRc = TapeClose( tapeDevFD, + errorHelpString ) ; + } + else + { + ( void ) TapeClose( tapeDevFD, + dummyHelpString ) ; + } + } + } + + /* -------------------------------------------------------- */ + /* Search the tape for the next available spot in the case */ + /* of an archive or the actual file in the case of a */ + /* retrieve */ + /* -------------------------------------------------------- */ + if (( userExitRc == RC_OK ) && + ( !fileMissing )) + { + userExitRc = TapeFileSearch( tapeFileName, + &fileCount, + &fileMissing, + errorHelpString ) ; + } + + /* -------------------------------------------------------- */ + /* Open, rewind and forward the tape to the appropriate */ + /* location */ + /* -------------------------------------------------------- */ + if (( userExitRc == RC_OK ) && + ( !fileMissing )) + { + userExitRc = TapeOpen( &tapeDevFD, + errorHelpString ) ; + + if ( userExitRc == RC_OK ) + { + userExitRc = TapeRewind( tapeDevFD, + errorHelpString ) ; + + if ( userExitRc == RC_OK ) + { + userExitRc = TapeForward( tapeDevFD, + fileCount, + errorHelpString ) ; + } + + if ( userExitRc == RC_OK ) + { + userExitRc = TapeClose( tapeDevFD, + errorHelpString ) ; + } + else + { + ( void ) TapeClose( tapeDevFD, + dummyHelpString ) ; + } + } + } + + /* -------------------------------------------------------- */ + /* If all is well, archive or retrieve the file */ + /* -------------------------------------------------------- */ + if (( userExitRc == RC_OK ) && + ( !fileMissing )) + { + if ( archiveRequested ) + { + userExitRc = ArchiveFile( systemCallParms, + tapeFileName, + errorHelpString ) ; + } + else + { + userExitRc = RetrieveFile( systemCallParms, + tapeFileName, + errorHelpString ) ; + + /* -------------------------------------------------- */ + /* The retrieved file must be copied from the temp */ + /* directory, renamed and placed into the log path */ + /* -------------------------------------------------- */ + if ( userExitRc == RC_OK ) + { + userExitRc = CopyFile( systemCallParms, + tapeFileName, + inputParms, + &fileMissing, + errorHelpString ) ; + } + } + } + + /* -------------------------------------------------------- */ + /* Remove the temporary directory */ + /* -------------------------------------------------------- */ + RemoveTempDir() ; + } + + /* ----------------------------------------------------------- */ + /* Trace any errors */ + /* ----------------------------------------------------------- */ + if ( userExitRc != RC_OK ) + { + PrintErr ; + } + + /* ----------------------------------------------------------- */ + /* Trace the end of execution if the user has asked for an */ + /* audit log */ + /* ----------------------------------------------------------- */ + if (( AUDIT_ACTIVE ) && + ( auditLogRc != AUDIT_IO_ERROR )) + { + auditLogRc = AuditLogEnd ( + auditFileName, /* audit log file name */ + userExitRc, /* user exit return code */ + errorHelpString ) ; /* error isolation string*/ + + if ( auditLogRc == AUDIT_IO_ERROR )/* IO error on audit log */ + { + PrintErr ; + } + } + } + + /* -------------------------------------------------------------- */ + /* Return the specified value to the caller */ + /* -------------------------------------------------------------- */ + exit( userExitRc ) ; +} + + +/*********************************************************************/ +/* ArchiveFile() - Archive a log file to tape from a temporary */ +/* directory. */ +/*********************************************************************/ +unsigned int + ArchiveFile( char *systemCallParms, + char *tapeFileName, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + unsigned int rc = RC_OK ; /* function return code */ + signed int systemCallRc = RC_OK ; /* system call rc */ + + /* -------------------------------------------------------------- */ + /* Construct the archive system call string */ + /* -------------------------------------------------------------- */ + sprintf( systemCallParms, + "%s %s%s %s %s %s%s", + CHANGE_DIR, /* change directory */ + TEMP_DIR, /* temporary directory */ + SEMI_COLON, /* ; */ + ARCHIVE_COMMAND, /* archive ( tar ) */ + TAPE_DEV, /* tape device */ + tapeFileName, /* tape file name */ + NULL_TERM ) ; + + systemCallRc = system( systemCallParms ) ; + + if ( systemCallRc != RC_OK ) + { + rc = RC_UNKNOWN ; /* command error */ + + sprintf( errorHelpString, "%s %s %s%s", "Error archiving file", + tapeFileName, "to tape", NEW_LINE ) ; + } + else + { + rc = RC_OK ; /* successful archive */ + } + + return( rc ) ; +} + + +/*********************************************************************/ +/* RetrieveFile() - Retrieve a log file from tape and place it in a */ +/* temporary directory. */ +/*********************************************************************/ +unsigned int + RetrieveFile( char *systemCallParms, + char *tapeFileName, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + unsigned int rc = RC_OK ; /* function return code */ + signed int systemCallRc = RC_OK ; /* system call rc */ + + /* -------------------------------------------------------------- */ + /* Construct the retrieve system call string */ + /* -------------------------------------------------------------- */ + sprintf( systemCallParms, + "%s %s%s %s %s %s%s", + CHANGE_DIR, /* change directory */ + TEMP_DIR, /* temporary directory */ + SEMI_COLON, /* ; */ + RETRIEVE_COMMAND, /* retrieve ( tar ) */ + TAPE_DEV, /* tape device */ + tapeFileName, /* tape file name */ + NULL_TERM ) ; + + systemCallRc = system( systemCallParms ) ; + + if ( systemCallRc != RC_OK ) + { + rc = RC_UNKNOWN ; /* command error */ + + sprintf( errorHelpString, "%s %s %s%s", "Error retrieving file", + tapeFileName, "from tape", NEW_LINE ) ; + } + else + { + rc = RC_OK ; /* successful retrieve */ + } + + return( rc ) ; +} + + +/*********************************************************************/ +/* RemoveTempDir() - Remove the temporary directory containing the */ +/* log file to be archived/retrieved to/from tape.*/ +/*********************************************************************/ +void RemoveTempDir() +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + char removeCallString[SYSTEM_CALL_LEN]; /* remove dir string */ + + memset( removeCallString, '\0', SYSTEM_CALL_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Construct the remove directory system call string */ + /* -------------------------------------------------------------- */ + sprintf( removeCallString, + "%s %s%s", + RMDIR, /* remove with force */ + TEMP_DIR, /* temporary directory */ + NULL_TERM ) ; + + system( removeCallString ) ; +} + + +/*********************************************************************/ +/* CreateTempDir() - Create the temporary directory which will */ +/* contain the log to be archived/retrieved */ +/* to/from tape. */ +/*********************************************************************/ +unsigned int + CreateTempDir( char *systemCallParms, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + unsigned int rc = RC_OK ; /* function return code */ + signed int systemCallRc = RC_OK ; /* system call rc */ + + /* -------------------------------------------------------------- */ + /* Construct the make directory system call string */ + /* -------------------------------------------------------------- */ + sprintf( systemCallParms, + "%s %s%s", + MKDIR, /* make directory */ + TEMP_DIR, /* temporary directory */ + NULL_TERM ) ; + + systemCallRc = system( systemCallParms ) ; + + if ( systemCallRc != RC_OK ) + { + rc = RC_UNKNOWN ; /* could not create dir */ + + sprintf( errorHelpString, "%s %s%s", + "Error creating directory", TEMP_DIR, NEW_LINE ) ; + } + else + { + rc = RC_OK ; /* successful creation */ + } + + return( rc ) ; +} + + +/*********************************************************************/ +/* CopyFile() - Copy a log file to/from the temporary directory */ +/* from/to the database log directory for a specific */ +/* database. */ +/*********************************************************************/ +unsigned int + CopyFile( char *systemCallParms, + char *tapeFileName, + INPUT_PARMS *inputParms, + unsigned int *fileMissing, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + FILE *tempFp = NULL ; /* temporary file pointer*/ + unsigned int rc = RC_OK ; /* function return code */ + signed int systemCallRc = RC_OK ; /* system call rc */ + char fileToArchive[ FILE_NAME_LEN ] ; + /* file to be archived */ + + /* -------------------------------------------------------------- */ + /* Construct the copy system call string depending on whether an */ + /* archive or retrieve request was received */ + /* -------------------------------------------------------------- */ + if ( archiveRequested ) /* ARCHIVE in progress */ + { + sprintf( systemCallParms, + "%s %s%s %s%s%s%s", + COPY, /* copy */ + inputParms->logFilePath, /* log file path */ + inputParms->logFile, /* log file name */ + TEMP_DIR, /* temporary directory */ + SLASH, /* slash */ + tapeFileName, /* constructed file name */ + NULL_TERM ) ; + + } + else /* RETRIEVE in progress */ + { + sprintf( systemCallParms, + "%s %s%s%s %s%s%s", + COPY, /* copy */ + TEMP_DIR, /* temporary directory */ + SLASH, /* slash */ + tapeFileName, /* constructed file name */ + inputParms->logFilePath, /* log file path */ + inputParms->logFile, /* log file name */ + NULL_TERM ) ; + } + + systemCallRc = system( systemCallParms ) ; + + if ( systemCallRc != RC_OK ) + { + /* ----------------------------------------------------------- */ + /* If we are archiving the log file, check to see if it exists */ + /* in the log path */ + /* ----------------------------------------------------------- */ + if ( archiveRequested ) + { + memset( fileToArchive, '\0', FILE_NAME_LEN ) ; + + sprintf( fileToArchive, /* file to be archived */ + "%s%s%s", /* format of parm string */ + inputParms->logFilePath, /* log file path */ + inputParms->logFile, /* log file name */ + NULL_TERM ) ; + + if (( tempFp = fopen( fileToArchive, "rb" )) == NULL ) + { + if (errno == ENOENT) + { + rc = RC_OK; + strcpy(errorHelpString, + "File does not exist, assume it is already archived."); + } + else + { + rc = RC_UNKNOWN; + sprintf(errorHelpString, + "Fail to open the log file %s, errno = %d%s", + fileToArchive, errno, NEW_LINE); + } + + *fileMissing = TRUE ; /* file not found */ + } + else + { + ( void ) fclose( tempFp ) ; /* close the file */ + + sprintf(errorHelpString,"%s %s %s %s%s%s%s", + "Error copying",fileToArchive,"to",TEMP_DIR, + SLASH,tapeFileName,NEW_LINE) ; + + rc = RC_UNKNOWN ; /* could not copy file */ + } + } + else + { + rc = RC_UNKNOWN ; /* could not copy file */ + + sprintf(errorHelpString,"%s %s%s%s %s %s%s%s","Error copying", + TEMP_DIR, SLASH, tapeFileName, "to", + inputParms->logFilePath, inputParms->logFile, + NEW_LINE ) ; + } + } + else + { + rc = RC_OK ; /* successful copy */ + } + + return( rc ) ; +} + + +/*********************************************************************/ +/* TapeOpen() - Open a tape device. */ +/*********************************************************************/ +unsigned int + TapeOpen( signed int *tapeDevFD, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + unsigned int rc = RC_OK ; /* function return code */ + + /* -------------------------------------------------------------- */ + /* Open the tape device in READ/WRITE mode using user defined */ + /* permissions */ + /* -------------------------------------------------------------- */ + *tapeDevFD = open( TAPE_DEV, /* tape device name */ + O_RDWR, /* open mode */ + TAPE_PERM ) ; /* tape permissions */ + + if ( *tapeDevFD == -1 ) /* error opening device */ + { + rc = RC_HARDWARE ; /* tape problem */ + + sprintf( errorHelpString,"%s %s %d %s%s","Error opening device", + TAPE_DEV,O_RDWR,TAPE_PERM,NEW_LINE ) ; + } + else + { + rc = RC_OK ; /* successful open */ + } + + return( rc ) ; +} + +/*********************************************************************/ +/* TapeClose() - Close a tape device. */ +/*********************************************************************/ +unsigned int + TapeClose( signed int tapeDevFD, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + unsigned int rc = RC_OK ; /* function return code */ + signed int tapeRc = RC_OK ; /* tape close rc */ + + /* -------------------------------------------------------------- */ + /* Close the device identified by the file descriptor */ + /* -------------------------------------------------------------- */ + tapeRc = close( tapeDevFD ) ; + + if ( tapeRc != RC_OK ) /* error closing device */ + { + rc = RC_HARDWARE ; /* tape problem */ + + sprintf( errorHelpString,"%s %s%s","Error closing device", + TAPE_DEV,NEW_LINE ) ; + } + else + { + rc = RC_OK ; /* successful close */ + } + + return( rc ) ; +} + + +/*********************************************************************/ +/* TapeRewind() - Rewind a tape. */ +/*********************************************************************/ +unsigned int + TapeRewind( signed int tapeDevFD, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + unsigned int rc = RC_OK ; /* function return code */ + signed int tapeRc = RC_OK ; /* tape ioctl() rc */ + struct stop tapeOperation ; /* ioctl() values */ + + tapeOperation.st_op = STREW ; /* rewind */ + tapeOperation.st_count = 1 ; /* to the beginning */ + + /* -------------------------------------------------------------- */ + /* Call ioctl() to rewind the tape to the beginning */ + /* -------------------------------------------------------------- */ + tapeRc = ioctl( tapeDevFD, /* file descriptor */ + STIOCTOP, /* ioctl for tape */ + &tapeOperation ) ; /* rewind operation */ + + if ( tapeRc != RC_OK ) /* error rewinding tape */ + { + rc = RC_HARDWARE ; /* tape problem */ + + sprintf( errorHelpString,"%s %s%s","Error rewinding device", + TAPE_DEV,NEW_LINE ) ; + } + else + { + rc = RC_OK ; /* successful rewind */ + } + + return( rc ) ; + +} + + +/*********************************************************************/ +/* TapeForward() - Fast forward the tape to a specified point. */ +/*********************************************************************/ +unsigned int + TapeForward( signed int tapeDevFD, + unsigned int fileCount, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + unsigned int rc = RC_OK ; /* function return code */ + signed int tapeRc = RC_OK ; /* tape ioctl() rc */ + struct stop tapeOperation ; /* ioctl() values */ + + tapeOperation.st_op = STFSF ; /* fast forward */ + tapeOperation.st_count = ( daddr_t ) fileCount ; + /* specified file count */ + + /* -------------------------------------------------------------- */ + /* Call ioctl() to fast forward the tape to the specified point */ + /* -------------------------------------------------------------- */ + tapeRc = ioctl( tapeDevFD, /* file descriptor */ + STIOCTOP, /* ioctl for tape */ + &tapeOperation ) ; /* forward operation */ + + if ( tapeRc != RC_OK ) /* error fast forwarding */ + { + rc = RC_HARDWARE ; /* tape problem */ + + sprintf( errorHelpString,"%s %s %s %d%s", + "Error forwarding device",TAPE_DEV,"to", + fileCount, NEW_LINE ) ; + } + else + { + rc = RC_OK ; /* successful forward */ + } + + return( rc ) ; +} + + +/*********************************************************************/ +/* TapeFileSearch() - Search the tape for a specified file. */ +/*********************************************************************/ +unsigned int + TapeFileSearch( char *tapeFileName, + unsigned int *fileCount, + unsigned int *fileMissing, + char *errorHelpString ) +{ + /* -------------------------------------------------------------- */ + /* Declare and initialize variables */ + /* -------------------------------------------------------------- */ + FILE *commandPtr ; /* received from popen() */ + unsigned int fileNotFound ; /* file found indicator */ + unsigned int endOfTapeData ; /* end of tape indicator */ + unsigned int rc ; /* function return code */ + char popenCommand[ PIPE_COMMAND_LEN ] ; + /* pipe command string */ + char fileOnTape[ TAPE_FILE_LEN ] ; + /* file name on tape */ + char fileRequested[ TAPE_FILE_LEN] ; + /* file name requested */ + + char *emptyFileName = "" ; /* empty file name */ + + commandPtr = NULL ; + fileNotFound = TRUE ; + endOfTapeData = FALSE ; + rc = RC_OK ; + *fileMissing = FALSE ; + memset( popenCommand, '\0', PIPE_COMMAND_LEN ) ; + memset( fileOnTape, '\0', TAPE_FILE_LEN ) ; + memset( fileRequested,'\0', TAPE_FILE_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Construct the requested file name by appending a new line */ + /* character string to the tape file name passed to the function */ + /* -------------------------------------------------------------- */ + sprintf( fileRequested, + "%s%s", + tapeFileName, /* tape file name */ + NEW_LINE ) ; + + /* -------------------------------------------------------------- */ + /* Construct the command for popen() to query the name of the */ + /* next file on tape */ + /* -------------------------------------------------------------- */ + sprintf( popenCommand, + "%s %s%s", + QUERY_COMMAND, /* tape query command */ + TAPE_DEV, /* tape device */ + NULL_TERM ) ; + + /* -------------------------------------------------------------- */ + /* Issue query commands until the file is found or we reach the */ + /* end of data on the tape. Keep track of the current file count */ + /* on the tape. */ + /* -------------------------------------------------------------- */ + while (( fileNotFound ) && + ( !endOfTapeData ) && + ( !( *fileMissing ))) + { + (*fileCount)++ ; /* increment file count */ + + memset( fileOnTape, '\0', TAPE_FILE_LEN ) ; + + /* ----------------------------------------------------------- */ + /* Open a pipe to receive file names from tape. The popen() */ + /* will issue a tar query command to display the next file */ + /* on tape ( which will be read by the fread() ). */ + /* ----------------------------------------------------------- */ + commandPtr = popen( popenCommand, "r" ) ; + + if ( commandPtr != NULL ) /* open was successful */ + { + /* -------------------------------------------------------- */ + /* Read the file name from the pipe */ + /* -------------------------------------------------------- */ + fread( fileOnTape, 1, TAPE_FILE_LEN, commandPtr ) ; + + /* -------------------------------------------------------- */ + /* If the file at this location is the one to be retrieved, */ + /* set the file found flag */ + /* -------------------------------------------------------- */ + if (( retrieveRequested ) && + ( strcmp( fileOnTape, fileRequested ) == 0 )) + { + fileNotFound = FALSE ; + } + else + { + /* ----------------------------------------------------- */ + /* If we have found an available location and we are */ + /* archiving a file, set the end of tape data flag. If */ + /* we are retrieving a file, it does not reside on this */ + /* tape. */ + /* ----------------------------------------------------- */ + if ( strcmp( fileOnTape, emptyFileName ) == 0 ) + { + if ( archiveRequested ) + { + endOfTapeData = TRUE ; + } + else + { + rc = RC_OK ; /* file not found while */ + /* retrieving is ok */ + *fileMissing = TRUE ; + } + } + } + + /* -------------------------------------------------------- */ + /* Close the pipe */ + /* -------------------------------------------------------- */ + pclose( commandPtr ) ; + + } + else + { + rc = RC_UNKNOWN ; /* could not open pipe */ + + sprintf( errorHelpString,"%s%s","Error opening pipe", + NEW_LINE ) ; + } + } + + /* -------------------------------------------------------------- */ + /* Decrement the file count by one as we have counted the last */ + /* file read and when fast forwarding, we want to position the */ + /* tape to the point before this file */ + /* -------------------------------------------------------------- */ + (*fileCount)-- ; + + return( rc ) ; +} + +/*********************************************************************/ +/* SignalEnd() - If a signal has been raised for which we have */ +/* installed a handler, perform the following: */ +/* . trace the signal in the error log (if enabled) */ +/* . exit the user exit with a RC_OPCAN return code */ +/*********************************************************************/ +void SignalEnd( int sigNum ) +{ + unsigned int userExitRc ; /* user exit return code */ + char errorHelpString[ HELP_STRING_LEN ] ; + /* error help string */ + + /* -------------------------------------------------------------- */ + /* Set the user exit return code to operator cancelled */ + /* -------------------------------------------------------------- */ + userExitRc = RC_OPCAN ; + + /* -------------------------------------------------------------- */ + /* Log the error if the error log has been requested */ + /* -------------------------------------------------------------- */ + if ( ERROR_ACTIVE ) + { + memset( errorHelpString, '\0', HELP_STRING_LEN ) ; + + sprintf( errorHelpString,"%s %d %s %s%s","Signal",sigNum, + ( sigNum == SIGTERM ) ? "(SIGTERM)" : "(SIGINT)", + "has been raised",NEW_LINE ) ; + + ErrorLog( NULL, NULL, NULL, userExitRc, errorHelpString ) ; + } + + /* -------------------------------------------------------------- */ + /* Exit the user exit with the appropriate return code */ + /* -------------------------------------------------------------- */ + exit( userExitRc ) ; +} + + +/*********************************************************************/ +/* AuditLogStart() - Log the following at user exit entrance: */ +/* 1. time system call was made */ +/* 2. parameters passed to the user exit */ +/* 3. media type */ +/*********************************************************************/ +unsigned int + AuditLogStart( INPUT_PARMS *inputParms, + char *auditFileName, + char *errorHelpString ) +{ + FILE *auditLogFp ; /* pointer to audit log file */ + unsigned int auditLogRc ; /* AuditLogStart() return code*/ + time_t actionTime ; /* date and time of exit start*/ + char outputLine[ OUTPUT_LINE_LEN ] ; + /* line to be written to log */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + auditLogFp = NULL ; + auditLogRc = RC_OK ; + memset( &actionTime, 0, sizeof( actionTime )) ; + memset( outputLine, '\0', OUTPUT_LINE_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Open the audit log file using the appropriate file name and */ + /* user defined file attributes */ + /* -------------------------------------------------------------- */ + auditLogFp = fopen( auditFileName, AUDIT_ERROR_ATTR ) ; + + /* -------------------------------------------------------------- */ + /* If the audit log file opened successfully, write the data to */ + /* the file */ + /* -------------------------------------------------------------- */ + if ( auditLogFp != NULL ) + { + memset( outputLine, '*', DELIMITER_LEN ) ; + outputLine[ DELIMITER_LEN ] = '\n' ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + time( &actionTime ) ; /* time user exit started */ + sprintf( outputLine, + "%s%s%s", + "Time Started: ", + ctime( &actionTime ), + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + if ( PrintArguments( auditLogFp, inputParms ) != RC_OK ) + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( outputLine, /* system action */ + "%s %s %s%s %s %s%s", + "System Action: ", + inputParms->request, + inputParms->logFilePath, + inputParms->logFile, + ( archiveRequested ) ? "to" : "from", + TAPE_DEV, + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( outputLine, /* user defined media type */ + "%s %s%s", + "Media Type: ", + MEDIA_TYPE, + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + /* ----------------------------------------------------------- */ + /* If an error was encountered during the audit log write */ + /* ----------------------------------------------------------- */ + if ( auditLogRc == AUDIT_IO_ERROR ) + { + sprintf( errorHelpString,"%s%s", + "Error writing to the Audit Log file", NEW_LINE ) ; + + ( void ) fclose( auditLogFp ) ; + } + else + { + if ( fclose( auditLogFp ) ) + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString, "%s%s", + "Error closing Audit Log file", NEW_LINE ) ; + } + } + } + else /* error opening file */ + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString,"%s%s", + "Error opening Audit Log file",NEW_LINE ) ; + } + + return( auditLogRc ) ; +} + + +/*********************************************************************/ +/* AuditLogEnd() - Log the following at user exit end: */ +/* 1. time system call returned */ +/* 2. user exit return code */ +/*********************************************************************/ +unsigned int + AuditLogEnd( char *auditFileName, + unsigned int userExitRc, + char *errorHelpString ) +{ + FILE *auditLogFp ; /* pointer to audit log file */ + unsigned int auditLogRc ; /* AuditLogEnd() return code */ + time_t actionTime ; /* date and time of exit end */ + char outputLine[OUTPUT_LINE_LEN]; + /* line to be written to log */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + auditLogFp = NULL ; + auditLogRc = RC_OK ; + memset( &actionTime, 0, sizeof( actionTime )) ; + memset( outputLine, '\0', OUTPUT_LINE_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Open the audit log file using the appropriate file name and */ + /* user defined file attributes */ + /* -------------------------------------------------------------- */ + auditLogFp = fopen( auditFileName, AUDIT_ERROR_ATTR ) ; + + /* -------------------------------------------------------------- */ + /* If the audit log file opened successfully, write the data to */ + /* the file */ + /* -------------------------------------------------------------- */ + if ( auditLogFp != NULL ) + { + sprintf( outputLine, /* user exit return code */ + "%s %d %s%s", + "User Exit RC: ", + userExitRc, + ( userExitRc ) ? "|||> ERROR <|||" : errorHelpString, + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine )) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + time( &actionTime ) ; /* time system call completed */ + sprintf( outputLine, + "%s %s%s", + "Time Completed: ", + ctime( &actionTime ), + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine )) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + /* ----------------------------------------------------------- */ + /* If an error was encountered during the audit log write */ + /* ----------------------------------------------------------- */ + if ( auditLogRc == AUDIT_IO_ERROR ) + { + sprintf( errorHelpString, "%s%s", + "Error writing to the Audit Log file",NEW_LINE ) ; + + ( void ) fclose( auditLogFp ) ; /* close the audit log */ + } + else + { + if ( fclose( auditLogFp ) ) /* close the audit log */ + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString,"%s%s", + "Error closing Audit Log file", NEW_LINE ) ; + } + } + } + else /* error opening file */ + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString,"%s%s", + "Error opening Audit Log file", NEW_LINE ) ; + } + + return( auditLogRc ) ; +} + + +/*********************************************************************/ +/* ErrorLog() - Log the following if an error has occurred: */ +/* . time the error occurred */ +/* . values of all parameters passed to the user */ +/* exit at the time of the error */ +/* . media type */ +/* . audit log file name */ +/* . system call string */ +/* . user exit return code */ +/* . error isolation help string */ +/*********************************************************************/ +void ErrorLog( INPUT_PARMS *inputParms, + char *auditFileName, + char *systemCallParms, + unsigned int userExitRc, + char *errorHelpString ) +{ + FILE *errorLogFp ; /* pointer to error log file */ + time_t actionTime ; /* date and time of error */ + char outputLine[ OUTPUT_LINE_LEN ] ; + /* line to be written to log */ + char errorFileName[ FILE_NAME_LEN ] ; + /* error log file name */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + errorLogFp = NULL ; + memset( &actionTime, 0, sizeof( actionTime )) ; + memset( outputLine, '\0', OUTPUT_LINE_LEN ) ; + memset( errorFileName, '\0', FILE_NAME_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Open the error log file using the user defined name and file */ + /* attributes */ + /* -------------------------------------------------------------- */ + sprintf( errorFileName, + "%s%s", + AUDIT_ERROR_PATH, /* error log path */ + ERROR_FILE_NAME ) ; /* error log file name */ + + errorLogFp = fopen( errorFileName, AUDIT_ERROR_ATTR ) ; + + /* -------------------------------------------------------------- */ + /* If the error log file opened successfully, write the available */ + /* data to the file */ + /* -------------------------------------------------------------- */ + if ( errorLogFp != NULL ) + { + memset( outputLine, '*', DELIMITER_LEN ) ; + outputLine[ DELIMITER_LEN ] = '\n' ; + fprintf( errorLogFp, outputLine ) ; + + time( &actionTime ) ; /* time error occurred */ + sprintf( outputLine, + "%s %s%s", + "Time of Error: ", + ctime( &actionTime ), + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + + if ( inputParms != NULL ) /* parmeters passed to user */ + { /* exit */ + (void) PrintArguments( errorLogFp, inputParms ) ; + } + + sprintf( outputLine, /* audit log file name */ + "%s %s%s", + "Audit Log File: ", + auditFileName, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* system call string */ + "%s %s%s", + "System Call Parms:", + systemCallParms, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* user defined media type */ + "%s %s%s", + "Media Type: ", + MEDIA_TYPE, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* user exit return code */ + "%s %d %s%s", + "User Exit RC: ", + userExitRc, + NEW_LINE, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* error isolation string */ + "%s %s%s%s", + "> Error isolation:", + errorHelpString, + NEW_LINE, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + /* ----------------------------------------------------------- */ + /* Close the error log file */ + /* ----------------------------------------------------------- */ + fclose( errorLogFp ) ; + } + + return ; +} + + +unsigned int + ParseArguments( int argc , + char *argv[] , + INPUT_PARMS *inputParms , + char *errorHelpString ) +{ + int parseRc; /* ParseArguments() return code */ + int count; /* index for for loop */ + char *argument; /* pointer to argument */ + int parmLen; /* length of parameter */ + int parmIden; /* parameter identifier */ + char *parmValue; /* parameter value */ + + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + parseRc = RC_OK ; + count = 1 ; + + /* -------------------------------------------------------------- */ + /* Copy values into inputParms structure. */ + /* -------------------------------------------------------------- */ + inputParms->argc = argc; + + while ( ( count < argc ) && ( parseRc == RC_OK) ) + { + argument = argv[count]; + + parmLen = strlen(argument); + if (parmLen < 4) + { + parseRc = RC_PARM; + break; + } + + parmIden = ((argument[2]) | (argument[1] << 8) | (argument[0] << 16)); + parmValue = &argument[3]; + +#define INPUT_PARM_AP 0x2d4150 /* -AP */ +#define INPUT_PARM_DB 0x2d4442 /* -DB */ +#define INPUT_PARM_LN 0x2d4c4e /* -LN */ +#define INPUT_PARM_LB 0x2d4c42 /* -LB */ +#define INPUT_PARM_LP 0x2d4c50 /* -LP */ +#define INPUT_PARM_MD 0x2d4d44 /* -MD */ +#define INPUT_PARM_NN 0x2d4e4e /* -NN */ +#define INPUT_PARM_OS 0x2d4f53 /* -OS */ +#define INPUT_PARM_RD 0x2d5244 /* -RD */ +#define INPUT_PARM_RF 0x2d5246 /* -RF */ +#define INPUT_PARM_RL 0x2d524c /* -RL */ +#define INPUT_PARM_RQ 0x2d5251 /* -RQ */ + + switch(parmIden) + { + case INPUT_PARM_AP: /* ADSM password */ + inputParms->adsmPasswd = parmValue; + break; + case INPUT_PARM_DB: /* database name */ + inputParms->dbName = parmValue; + break; + case INPUT_PARM_LN: /* log file name */ + inputParms->logFile = parmValue; + break; + case INPUT_PARM_LB: /* label */ + inputParms->label = parmValue; + break; + case INPUT_PARM_LP: /* log file path */ + inputParms->logFilePath = parmValue; + break; + case INPUT_PARM_MD: /* mode */ + inputParms->mode = parmValue; + break; + case INPUT_PARM_NN: /* node number */ + inputParms->nodeNumber = parmValue; + break; + case INPUT_PARM_OS: /* operating system */ + inputParms->operatingSys = parmValue; + break; + case INPUT_PARM_RD: /* redirection file */ + inputParms->redFile = parmValue; + break; + case INPUT_PARM_RF: /* response file */ + inputParms->responseFile = parmValue; + break; + case INPUT_PARM_RL: /* DB2 release */ + inputParms->release = parmValue; + break; + case INPUT_PARM_RQ: /* user exit request */ + inputParms->request = parmValue; + break; + default: /* log unrecognized parameter */ + if ( ERROR_ACTIVE ) + { + memset( errorHelpString, '\0', HELP_STRING_LEN ) ; + + sprintf( errorHelpString, + "%s %s%s%s%s", + "Unrecognized parameter :", + argument, + NEW_LINE, + "Parameter has been ignored.", + NEW_LINE ) ; + + ErrorLog( NULL, NULL, NULL, RC_OK, errorHelpString ) ; + } + break; + } + + count ++ ; /* increment count */ + } + + return(parseRc); +} + + + +unsigned int + PrintArguments(FILE *fp, INPUT_PARMS *inputParms) +{ + char outputLine[ OUTPUT_LINE_LEN ] ; + int printRc = RC_OK ; + + sprintf( outputLine, + "%s %d%s", + "Parameter Count: ", + inputParms->argc, + NEW_LINE ) ; + + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR ; + + if ( printRc == RC_OK ) + { + sprintf( outputLine, + "%s %s", + "Parameters Passed:", + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->adsmPasswd != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "ADSM password: ", + inputParms->adsmPasswd, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->dbName != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Database name: ", + inputParms->dbName, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->logFile != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Logfile name: ", + inputParms->logFile, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->label != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Label: ", + inputParms->label, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->logFilePath != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Logfile path: ", + inputParms->logFilePath, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->mode != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Mode: ", + inputParms->mode, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->nodeNumber != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Node number: ", + inputParms->nodeNumber, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->operatingSys != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Operating system: ", + inputParms->operatingSys, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->redFile != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Red file: ", + inputParms->redFile, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->responseFile != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Response file: ", + inputParms->responseFile, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->release != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Release: ", + inputParms->release, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->request != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Request: ", + inputParms->request, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + return(printRc); +} diff --git a/c/db2uext2.ctsm b/c/db2uext2.ctsm new file mode 100644 index 0000000..8175589 --- /dev/null +++ b/c/db2uext2.ctsm @@ -0,0 +1,2389 @@ +/****************************************************************************** + * + * Source File Name = db2uext2.ctsm + * + * Licensed Materials - Property of IBM + * + * (C) COPYRIGHT International Business Machines Corp. 1996. + * All Rights Reserved + * + * US Government Users Restricted Rights - Use, duplication or + * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + * + * Function = Sample Log Management User Exit C Source Code + * + *****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* Sample Name: db2uext2.ctsm */ +/* */ +/* */ +/* Purpose: This is a sample User Exit utilizing Tivoli Storage Manager */ +/* ( TSM ) to Archive and Retrieve database log files. */ +/* */ +/* Options: 1. This sample provides an audit trail of calls ( stored in a */ +/* separate file for each option ) including a timestamp and */ +/* parameters received. This option can be disabled. */ +/* */ +/* 2. This sample provides an error trail of calls in error */ +/* including a timestamp and an error isolation string for */ +/* problem determination. This option can be disabled. */ +/* */ +/* */ +/* Usage: 1. Copy "db2uext2.ctsm" to "db2uext2.c" and place this file */ +/* into a working directory. */ +/* */ +/* 2. Modify the "Installation Defined Variables" to suit your */ +/* environment. Two example scenarios have been provided */ +/* below for illustrative purposes. */ +/* */ +/* 3. Modify the program logic to suit your environment. If */ +/* there are situations where the user exit program fails on */ +/* archive request and you want DB2 to retry the request, set */ +/* the return code to RC_OPATTN. */ +/* */ +/* 4. Compile and link "db2uext2.c" with the following command: */ +/* cc_r -o db2uext2 db2uext2.c */ +/* /usr/tivoli/tsm/client/api/bin/libApiDS.a */ +/* -I/usr/tivoli/tsm/client/api/bin/sample */ +/* or a functional equivalent. */ +/* Place the resultant "db2uext2" named executable into */ +/* sqllib/adm or sqllib/bin. */ +/* */ +/* *** NOTE *** Code/command modification may be required */ +/* depending on compiler options used and header */ +/* file location. */ +/* */ +/* *** NOTE *** On 64-bit AIX compile as follows: */ +/* cc_r -o db2uext2 -q64 db2uext2.c */ +/* /usr/tivoli/tsm/client/api/bin64/libApiTSM64.a */ +/* -I/usr/tivoli/tsm/client/api/bin64/sample */ +/* */ +/* *** NOTE *** On Solaris compile as follows: */ +/* cc -o db2uext2 db2uext2.c -xarch=v9 */ +/* /opt/tivoli/tsm/client/api/bin/libApiDS.so */ +/* -I/opt/tivoli/tsm/client/api/bin/sample */ +/* */ +/* where -xarch= specifies architecture instruction */ +/* set. */ +/* */ +/* For 64-bit architectures, use the appropriate */ +/* library paths: */ +/* */ +/* cc -o db2uext2 db2uext2.c -xarch=v9 */ +/* /opt/tivoli/tsm/client/api/bin64/libApiDS64.so */ +/* -I/opt/tivoli/tsm/client/api/bin64/sample */ +/* */ +/* *** NOTE *** On HP compile as follows: */ +/* cc -D_INCLUDE_POSIX_SOURCE -Aa db2uext2.c */ +/* -o db2uext2 */ +/* -I/opt/tivoli/tsm/client/api/bin/sample +e */ +/* /opt/tivoli/tsm/client/api/bin/libApiDS.sl */ +/* */ +/* For 64-bit architectures, use the appropriate */ +/* library paths and flags: */ +/* */ +/* cc -D_INCLUDE_POSIX_SOURCE -Aa +DA2.0W */ +/* db2uext2.c -o db2uext2 */ +/* -I/opt/tivoli/tsm/client/api/bin64/sample +e */ +/* /opt/tivoli/tsm/client/api/bin64/libApiDS64.sl */ +/* */ +/* *** NOTE *** On Linux compile as follows: */ +/* cc -D_INCLUDE_POSIX_SOURCE db2uext2.c */ +/* -o db2uext2 */ +/* -I/opt/tivoli/tsm/client/api/bin/sample */ +/* /opt/tivoli/tsm/client/api/bin/libApiDS.so */ +/* -lApiDS -lpthread -lcrypt -ldl */ +/* */ +/* For 64-bit architectures, use the appropriate */ +/* library paths: */ +/* */ +/* cc -D_INCLUDE_POSIX_SOURCE db2uext2.c */ +/* -o db2uext2 */ +/* -I/opt/tivoli/tsm/client/api/bin64/sample */ +/* /opt/tivoli/tsm/client/api/bin64/libApiTSM64.so */ +/* -lApiTSM64 -lpthread -lcrypt -ldl */ +/* */ +/* On certain 64-bit architectures may need to specify */ +/* -m64 when using the gcc compiler, and -q64 when */ +/* using xlC */ +/* */ +/* 5. DB2 calls "db2uext2" in the following format - */ +/* */ +/* db2uext2 -OS -RL -RQ -DB */ +/* -NN -LP -LN */ +/* [-LSlogsize -SPstartingpage] */ +/* [-AP] */ +/* */ +/* where: os = operating system */ +/* release = DB2 release */ +/* request = 'ARCHIVE' or 'RETRIEVE' */ +/* dbname = database name */ +/* nodenumber = node number */ +/* logpath = log file path */ +/* logname = log file name */ +/* logsize = log file size (optional) */ +/* startingpage = starting offset in 4K page unit */ +/* (optional) */ +/* tsmpasswd = TSM password (optional) */ +/* */ +/* Note: logsize and startingpage are only used when */ +/* logpath is a raw device. */ +/* */ +/* 6. The following naming convention has been used in this user */ +/* exit: */ +/* */ +/* For the TSM register filespace call: */ +/* . filespace name = "/xxxxxxxx" where "xxxxxxx" is the */ +/* database name */ +/* . filespace type = "DB2" */ +/* */ +/* For the TSM object: */ +/* . object name filespace = "/xxxxxxxx" where "xxxxxxxx" */ +/* is the database name */ +/* . object high level name = "/NODEyyyy" where "yyyy" */ +/* is the node number */ +/* . object low level name = "/Szzzzzzz.LOG" where */ +/* "zzzzzzz" is the log file */ +/* number */ +/* */ +/* For example: If the database name was "SAMPLE", the node */ +/* number was NODE0000 and the log file name was */ +/* "S0000001.LOG", the following */ +/* would result: */ +/* */ +/* For the TSM register filespace call: */ +/* . filespace name = "/SAMPLE" */ +/* . filespace type = "DB2" */ +/* */ +/* For the TSM object: */ +/* . object name filespace = "/SAMPLE" */ +/* . object high level name = "/NODE0000" */ +/* . object low level name = "/S0000001.LOG" */ +/* */ +/* */ +/* Logic Flow: 1. install signal handlers */ +/* 2. verify the number of parameters passed */ +/* 3. verify the action requested */ +/* 4. start the audit trail ( if requested ) */ +/* 5. if the requested action is to archive a file: */ +/* . if the log file is not found, proceed to point 10 */ +/* 6. get the TSM library version */ +/* 7. setup environment variables and initialize the */ +/* TSM session */ +/* 8. if the requested action is to archive a file: */ +/* . register the filespace */ +/* . bind the application */ +/* . begin the transaction */ +/* . begin the sending of the object ( log file ) */ +/* . send the object in BUFFER_SIZE portions to TSM */ +/* . end the sending of the object */ +/* . end the transaction */ +/* if the requested action is to retrieve a file: */ +/* . begin the query to search for the object ( log file ) */ +/* . search for the object */ +/* . end the search for the object */ +/* . if the object is not found, proceed to point 10 */ +/* . begin the transfer of data */ +/* . receive the object in BUFFER_SIZE portions from TSM */ +/* into a temporary file */ +/* . end the transfer of data */ +/* . if successful, rename the temporary file to the log file */ +/* 9. terminate the TSM session */ +/* 10. log errors ( if requested and required ) */ +/* 11. end the audit trail ( if requested ) */ +/* 12. exit with the appropriate return code */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dsmapitd.h" +#include "dsmapifp.h" +#include "dsmrc.h" + +#ifdef __cplusplus +} +#endif + + +/*===========================================================================*/ +/*== ==*/ +/*== ------------------ INSTALLATION DEFINED VARIABLES ------------------- ==*/ +/*== ==*/ +/*== -------------------- REQUIRES USER MODIFICATION --------------------- ==*/ +/*== ==*/ +/*===========================================================================*/ +/*== ==*/ +/*== BUFFER_SIZE: Size of the buffer used to archive or retrieve a log ==*/ +/*== file to/from TSM. This user exit does not transmit ==*/ +/*== or receive a log file whole but does so in BUFFER_SIZE ==*/ +/*== portions ==*/ +/*== Notes: 1. this value should be modified to suit your ==*/ +/*== log file size (performance on larger log ==*/ +/*== files may improve with a larger BUFFER_SIZE) ==*/ +/*== 2. the default buffer size is 32768 bytes ==*/ +/*== 3. BUFFER_SIZE must be multiple of 4096 ==*/ +/*== ==*/ +/*== AUDIT_ACTIVE: The user may wish an audit trail of the user exit run. ==*/ +/*== Sample audit functions have been provided ==*/ +/*== ( AuditLogStart() and AuditLogEnd() ) ==*/ +/*== Notes: 1. enable audit logging by setting AUDIT_ACTIVE ==*/ +/*== to 1 ==*/ +/*== 2. disable audit logging by setting ==*/ +/*== AUDIT_ACTIVE to 0 ==*/ +/*== 3. archive requests will be traced in a file ==*/ +/*== named "ARCHIVE.LOG" located in the audit and ==*/ +/*== error file path ==*/ +/*== 4. retrieve requests will be traced in a file ==*/ +/*== named "RETRIEVE.LOG" located in the audit ==*/ +/*== and error file path ==*/ +/*== 5. the default setting is enable audit ==*/ +/*== logging ==*/ +/*== ==*/ +/*== ERROR_ACTIVE: The user may wish an error trail of the user exit run. ==*/ +/*== A sample error log function has been provided ==*/ +/*== ( ErrorLog() ) ==*/ +/*== Notes: 1. enable error logging by setting ERROR_ACTIVE ==*/ +/*== to 1 ==*/ +/*== 2. disable error logging by setting ==*/ +/*== ERROR_ACTIVE to 0 ==*/ +/*== 3. errors will be traced in a file named ==*/ +/*== "USEREXIT.ERR" located in the audit and ==*/ +/*== error file path ==*/ +/*== 4. the default setting is enable error ==*/ +/*== logging ==*/ +/*== ==*/ +/*== AUDIT_ERROR_PATH: Path where Audit and Error logs will reside ==*/ +/*== Notes: 1. the path must exist ( the user exit will ==*/ +/*== not create the path ) ==*/ +/*== 2. the path must end with a back slash ==*/ +/*== 3. the default is "/u/" ==*/ +/*== ==*/ +/*== AUDIT_ERROR_ATTR: Standard C file open attributes for the Audit and ==*/ +/*== Error logs ==*/ +/*== Notes: 1. the default is "a" (text append) ==*/ +/*== ==*/ +/*== NOTE: ==*/ +/*== . the DSMI_DIR, DSMI_CONFIG, DSMI_LOG variables defined in the ==*/ +/*== environment when the last db2start was issued will be used by ==*/ +/*== the user exit. The ability to overwrite them can be done by ==*/ +/*== setting the defined variables below. For more information on ==*/ +/*== these variables please see the TSM Admin Guide. ==*/ +/*== ==*/ +/*== . to utilize the LAN Free capabilities, you must have a minimum ==*/ +/*== TSM client of 4.2.0. ==*/ +/*== ==*/ +/*== DSMI_DIR: For UNIX: ==*/ +/*== Points to the path containing dsm.sys, ==*/ +/*== dsmtca, the en_US subdirectory, and any ==*/ +/*== other NLS language. ==*/ +/*== For Intel: ==*/ +/*== Points to the path containing ==*/ +/*== dscameng.txt and any NLS message file. ==*/ +/*== If this variable is NULL, then the userexit will ==*/ +/*== search the environment for a suitable path. ==*/ +/*== ==*/ +/*== DSMI_CONFIG: The fully-qualified name for the client options ==*/ +/*== file (dsm.opt). ==*/ +/*== If this variable is NULL, then the userexit will ==*/ +/*== search the environment for a suitable path. ==*/ +/*== ==*/ +/*== DSMI_LOG: Points to the path for the dsierror.log file. ==*/ +/*== If this variable is NULL, then the userexit will ==*/ +/*== search the environment for a suitable path. ==*/ +/*== ==*/ +/*== MGMT_CLASS: Indicates the management class to be used with the ==*/ +/*== TSM server. If this variable is NULL, then the ==*/ +/*== userexit will use the default management class. ==*/ +/*== ==*/ +/*== DSMINIT_OPTIONS: Points to a character string that contains user ==*/ +/*== options used during initialization with TSM. An ==*/ +/*== example would be for cross-node log file retrieval ==*/ +/*== where a string containing the following: ==*/ +/*== "-fromnode= -fromowner=" ==*/ +/*== would be used to retrieve log files archived from ==*/ +/*== TSM node under owner . ==*/ + +#define BUFFER_SIZE 32768 /* transmit or receive the log */ + /* file in 32k portions */ +#define AUDIT_ACTIVE 1 /* enable audit trail logging */ +#define ERROR_ACTIVE 1 /* enable error trail logging */ +#define AUDIT_ERROR_PATH "/u/" /* path must end with a slash */ +#define AUDIT_ERROR_ATTR "a" /* append to text file */ +#define DSMI_DIR NULL /* use value from the environment */ +#define DSMI_CONFIG NULL /* use value from the environment */ +#define DSMI_LOG NULL /* use value from the environment */ +#define MGMT_CLASS NULL /* use default management class */ +#define DSMINIT_OPTIONS NULL /* specify no user opts to init. */ + +/*===========================================================================*/ +/*== ==*/ +/*== ------------------------ EXAMPLE SCENARIOS -------------------------- ==*/ +/*== ( FOR ILLUSTRATIVE PURPOSES ONLY ) ==*/ +/*== ==*/ +/*===========================================================================*/ +/*== ==*/ +/*== 1) Given that we are "userid1", are working with a database ==*/ +/*== named "SAMPLE1" on node NODE0001 and have modified the ==*/ +/*== installation defined variables to the following values: ==*/ +/*== ==*/ +/*== BUFFER_SIZE 32768 ==*/ +/*== AUDIT_ACTIVE 1 ==*/ +/*== ERROR_ACTIVE 1 ==*/ +/*== AUDIT_ERROR_PATH "/u/userid1/AuditLogs/" ==*/ +/*== AUDIT_ERROR_ATTR "a" ==*/ +/*== DSMI_DIR NULL ==*/ +/*== DSMI_CONFIG NULL ==*/ +/*== DSMI_LOG NULL ==*/ +/*== MGMT_CLASS NULL ==*/ +/*== DSMINIT_OPTIONS NULL ==*/ +/*== ==*/ +/*== If a request is received to archive log S0000000.LOG: ==*/ +/*== ==*/ +/*== . the audit log would be opened in append text mode and be named: ==*/ +/*== ==> "/u/userid1/AuditLogs/ARCHIVE.LOG" ==*/ +/*== ( AUDIT_ERROR_PATH + archive audit log file name ) ==*/ +/*== ==*/ +/*== . the log file would be transmitted to TSM in: ==*/ +/*== ==> 32768 byte portions ==*/ +/*== ( BUFFER_SIZE ) ==*/ +/*== ==*/ +/*== . the error log would be opened in append text mode and ==*/ +/*== be named: ==*/ +/*== ==> "/u/userid1/AuditLogs/USEREXIT.ERR" ==*/ +/*== ( AUDIT_ERROR_PATH + error log file name ( defined below )) ==*/ +/*== ==*/ +/*== . the DSMI_DIR, DSMI_CONFIG, DSMI_LOG environment variables will ==*/ +/*== not be overwritten. ==*/ +/*== ==*/ +/*== ==*/ +/*== 2) Given that we are "userid2", are working with a database ==*/ +/*== named "SAMPLE2" on node NODE0000 and have modified the ==*/ +/*== installation defined variables to the following values: ==*/ +/*== ==*/ +/*== BUFFER_SIZE 16384 ==*/ +/*== AUDIT_ACTIVE 1 ==*/ +/*== ERROR_ACTIVE 0 ==*/ +/*== AUDIT_ERROR_PATH "/u/userid2/Audit/Logs/" ==*/ +/*== AUDIT_ERROR_ATTR "w" ==*/ +/*== DSMI_DIR NULL ==*/ +/*== DSMI_CONFIG "/u/userid2/dsm.opt" ==*/ +/*== DSMI_LOG "/u/userid2/error/" ==*/ +/*== MGMT_CLASS NULL ==*/ +/*== DSMINIT_OPTIONS NULL ==*/ +/*== ==*/ +/*== If a request is received to retrieve log S0000001.LOG: ==*/ +/*== ==*/ +/*== . the audit log would be opened in write text mode and be named: ==*/ +/*== ==> "/u/userid2/Audit/Logs/RETRIEVE.LOG" ==*/ +/*== ( AUDIT_ERROR_PATH + retrieve audit log file name ) ==*/ +/*== ==*/ +/*== . the log file image would be received from TSM for database ==*/ +/*== "SAMPLE2" as: ==*/ +/*== ==> "S0000001.LOG" ==*/ +/*== ( log file name ) ==*/ +/*== ==*/ +/*== . the log file image would be received from TSM in: ==*/ +/*== ==> 16384 byte portions ==*/ +/*== ( BUFFER_SIZE ) ==*/ +/*== ==*/ +/*== . the error log would not be activated ==*/ +/*== ==*/ +/*== . the DSMI_DIR environment variable will not be overwritten, while ==*/ +/*== DSMI_CONFIG will be overwritten with "/u/userid2/dsm.opt" and ==*/ +/*== DSMI_LOG will be overwritten with ==*/ +/*== "/u/userid2/error/dsierror.log". ==*/ +/*===========================================================================*/ + + +/* ----------------------------------------------------------------- */ +/* User Exit Supported Return Codes */ +/* NOTE: DB2 will reinvoke the user exit for the same request */ +/* after 5 minutes if return code is 4 or 8. */ +/* */ +/* For other non-zero return codes, DB2 will not invoke */ +/* user exit for the database for at least 5 minutes. */ +/* If this request is to archive a log file, DB2 will not */ +/* make another archive request for this file, or other */ +/* log files produced during the 5 minute time period. */ +/* These log files will only be archived when all */ +/* applications disconnect from and the database, and the */ +/* database is reopenned. */ +/* ----------------------------------------------------------------- */ +#define RC_OK 0 /* ok */ +#define RC_RES 4 /* resource allocation error */ +#define RC_OPATTN 8 /* operator/user attention required*/ +#define RC_HARDWARE 12 /* hardware error */ +#define RC_DEFECT 16 /* software error */ +#define RC_PARM 20 /* invalid parameters */ +#define RC_AUDIT 21 /* error open audit file */ +#define RC_NOTFOUND 24 /* db2uext2() / file not found */ +#define RC_UNKNOWN 28 /* unknown error */ +#define RC_OPCAN 32 /* operator/user terminated */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Constants */ +/* ----------------------------------------------------------------- */ +#define NUM_VALID_PARMS 5 /* number of valid parameters */ +#define SLASH "/" /* default slash character */ +#define NEW_LINE "\n" /* new line character */ +#define FILE_EXT ".LOG" /* audit log file extension/type */ +#define MEDIA_TYPE "TSM" /* media type used */ +#define AUDIT_IO_ERROR 99 /* audit log I/O error */ +#define SYSTEM_CALL_LEN 550 /* system call string length */ +#define OUTPUT_LINE_LEN 550 /* output line length */ +#define FILE_NAME_LEN 255 /* file name length */ +#define HELP_STRING_LEN 80 /* error help string length */ +#define FILE_SPACE_LEN 10 /* file space name length */ +#define TSM_FILE_LEN 32 /* TSM log file name length */ +#define TSM_DESC_LEN 50 /* TSM description length */ +#define TSM_OBJECT_HL "NODE_0" /* TSM object high level name */ +#define TSM_MAXPATH_LEN DSM_PATH_MAX + DSM_NAME_MAX /* TSM max */ + /* length for a file path */ +#define DELIMITER_LEN 80 /* delimiter length */ +#define DOT "." /* file name separator */ +#define SEMI_COLON ";" /* command separator */ +#define FILE_SPACE_TYPE "DB2" /* file space type */ +#define ERROR_FILE_NAME "USEREXIT.ERR" + /* error log file name */ +#define REMOVE "rm" /* system remove command */ + +/* There is no llseek, nor offset_t, on HP or Linux */ +#ifdef _INCLUDE_POSIX_SOURCE +# define llseek lseek + typedef unsigned long long offset_t; +#endif + +/* There is no O_RSHARE on SUN */ +#ifndef O_RSHARE +#define O_RSHARE 0 +#endif + +/* ----------------------------------------------------------------- */ +/* Define TRUE and FALSE if required */ +/* ----------------------------------------------------------------- */ +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +/* ----------------------------------------------------------------- */ +/* Define structure for input parameters */ +/* ----------------------------------------------------------------- */ +typedef struct input_parms +{ + int argc; + char* tsmPasswd; + char* dbName; + char* logFile; + char* label; + char* logFilePath; + char* logSize; + char* mode; + char* nodeNumber; + char* operatingSys; + char* redFile; + char* responseFile; + char* release; + char* request; + char* startingPage; +} INPUT_PARMS; + +/* ----------------------------------------------------------------- */ +/* Print error to Error Log macro */ +/* ----------------------------------------------------------------- */ +#define PrintErr { if ( ERROR_ACTIVE ) \ + { \ + ErrorLog( inputParms, auditFileName, \ + systemCallParms, userExitRc, \ + errorHelpString) ; \ + } \ + } + +/* ----------------------------------------------------------------- */ +/* TSM API level defintions */ +/* ----------------------------------------------------------------- */ +#define CalculateLevelVer(_version, _release, _level) \ +( \ + ((_version) * 1000) + ((_release) * 100) + ((_level) * 10) \ +) + +/*********************************************************************/ +/* DetermineThreadMode() - Based on the client API level, */ +/* determines what threading mode should be */ +/* used for the session. */ +/* For UNIXes, it is multi-threaded only */ +/* for client levels >= 4.2.0, o.w. single */ +/* threaded. */ +/*********************************************************************/ +dsBool_t DetermineThreadMode( dsInt16_t clientLibVer ) +{ +#define MULTITHREADING_VER_REQ 4200 /* TSM API req. for mulit-thread */ + + dsBool_t threadMode = DSM_MULTITHREAD ; + + /* -------------------------------------------------------------- */ + /* Verify that the client has the right level to use */ + /* multi-threading, otherwise use single threaded. */ + /* Multi-threaded is the default. */ + /* -------------------------------------------------------------- */ + if (clientLibVer < MULTITHREADING_VER_REQ) + threadMode = DSM_SINGLETHREAD; + + return threadMode; +} + + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototypes for Archive, Retrieve and Data */ +/* Manipulation */ +/* ----------------------------------------------------------------- */ +unsigned int + ArchiveFile( unsigned long, /* TSM session handle */ + dsmObjName, /* TSM object name */ + INPUT_PARMS *, + char *, /* filespace name */ + char * ) ; /* error isolation string */ + +unsigned int + RetrieveFile( unsigned long, /* TSM session handle */ + dsmObjName, /* TSM object name */ + INPUT_PARMS *, + unsigned int *, /* file missing flag */ + char * ) ; /* error isolation string */ + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototype for Signal Handler */ +/* ----------------------------------------------------------------- */ +void SignalEnd( int ) ; /* signal type */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Function Prototypes for Audit and Error Logs */ +/* ----------------------------------------------------------------- */ +unsigned int + AuditLogStart( INPUT_PARMS *, /* input parameter structure */ + char *, /* audit file name (with path) */ + char *); /* error isolation string */ + +unsigned int + AuditLogEnd( char *, /* audit file name (with path) */ + unsigned int, /* user exit return code */ + char * ); /* error isolation string */ + +void ErrorLog( INPUT_PARMS *, /* input parameter structure */ + char *, /* audit file name (with path) */ + char *, /* system call parameter string */ + unsigned int, /* user exit return code */ + char * ) ; /* error isolation string */ + +unsigned int + ParseArguments( int , /* input parameter count */ + char * [] , /* input paramter list */ + INPUT_PARMS * , /* input parameter structure */ + char * ) ; /* error help string */ + +unsigned int + PrintArguments( FILE* fp, /* output file pointer */ + INPUT_PARMS * ) ; /* input parameter structure */ + + +/* ----------------------------------------------------------------- */ +/* User Exit Global Variables */ +/* ----------------------------------------------------------------- */ +unsigned int archiveRequested ; /* archive requested flag */ +unsigned int retrieveRequested ; /* retrieve requested flag */ + + +/*********************************************************************/ +/* User Exit Mainline */ +/*********************************************************************/ +int main( int argc, char *argv[] ) +{ + unsigned int userExitRc ; /* user exit return code */ + unsigned int auditLogRc ; /* return call from audit */ + + INPUT_PARMS inputParmsStruct; + INPUT_PARMS *inputParms = &inputParmsStruct; + + unsigned int fileMissing ; /* file missing flag */ + char systemCallParms[ SYSTEM_CALL_LEN ] ; + /* system call parm string */ + char auditFileName[ FILE_NAME_LEN ] ; + /* audit log file name */ + char errorHelpString[ HELP_STRING_LEN ] ; + /* error help string */ + + dsmApiVersion tsmClientApiVer ; /* TSM Client API version */ + dsInt16_t clientLibVer ; /* numerical TSM Client */ + /* API version */ + dsBool_t threadMode ; /* Thread mode for TSM */ + envSetUp tsmEnvSetUpParms ; /* TSM environment setup */ + unsigned int tsmHandle ; /* TSM session handle */ + dsmObjName objectName ; /* TSM object name */ + signed short tsmRc ; /* rc from TSM APIs */ + char fileSpaceName[ FILE_SPACE_LEN ] ; + /* TSM filespace name */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + archiveRequested = FALSE ; + retrieveRequested = FALSE ; + userExitRc = RC_OK ; + auditLogRc = RC_OK ; + fileMissing = FALSE ; + tsmRc = DSM_RC_OK ; + memset( inputParms, '\0', sizeof(INPUT_PARMS) ); + memset( systemCallParms, '\0', SYSTEM_CALL_LEN ) ; + memset( auditFileName, '\0', FILE_NAME_LEN ) ; + memset( errorHelpString, '\0', HELP_STRING_LEN ) ; + memset( &tsmEnvSetUpParms, 0, sizeof(envSetUp) ) ; + memset( fileSpaceName, '\0', FILE_SPACE_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Install signal handlers for terminate and interrupt */ + /* -------------------------------------------------------------- */ + if (( signal( SIGTERM, SignalEnd ) == SIG_ERR ) || + ( signal( SIGINT, SignalEnd ) == SIG_ERR )) + { + userExitRc = RC_DEFECT ; /* handler not installed */ + + sprintf( errorHelpString, "%s%s", + "Unable to install signal handler(s)", NEW_LINE ) ; + + PrintErr ; + } + + /* -------------------------------------------------------------- */ + /* Set the local variables to the passed parameters */ + /* -------------------------------------------------------------- */ + if ( userExitRc == RC_OK ) + { + userExitRc = ParseArguments( argc, argv, inputParms, + errorHelpString ) ; + } + + /* ----------------------------------------------------------- */ + /* Determine the user exit action */ + /* ----------------------------------------------------------- */ + if ( userExitRc == RC_OK ) + { + if ( (inputParms->request != NULL) && + (strcmp( inputParms->request, "ARCHIVE" ) == 0 ) ) + { + archiveRequested = TRUE ; /* action is ARCHIVE */ + } + else + { + if ( (inputParms->request != NULL) && + (strcmp( inputParms->request, "RETRIEVE" ) == 0 ) ) + { + retrieveRequested = TRUE ; /* action is RETRIEVE */ + } + else + { + userExitRc = RC_PARM ; /* invalid action */ + + sprintf( errorHelpString, "%s %s %s%s", "Action", + inputParms->request, "is not valid", NEW_LINE ) ; + + PrintErr ; + } + } + } + + if ( userExitRc == RC_OK ) + { + /* ----------------------------------------------------------- */ + /* Trace the start of execution if the user has asked for an */ + /* audit log */ + /* ----------------------------------------------------------- */ + if ( AUDIT_ACTIVE ) + { + sprintf( auditFileName, /* audit log file name */ + "%s%s%s", /* format of the name */ + AUDIT_ERROR_PATH, /* audit log file path */ + inputParms->request, /* ARCHIVE or RETRIEVE */ + FILE_EXT ) ; /* file extension/type */ + + auditLogRc = AuditLogStart(inputParms, + auditFileName, + errorHelpString); + + if (auditLogRc == AUDIT_IO_ERROR) + { + /* IO error on audit log */ + userExitRc = RC_AUDIT; + } + } + } + + if ( userExitRc == RC_OK ) + { + /* ----------------------------------------------------- */ + /* Query the TSM version and initialize the session */ + /* ----------------------------------------------------- */ + dsmQueryApiVersion( &tsmClientApiVer ) ; + clientLibVer = CalculateLevelVer( tsmClientApiVer.version, + tsmClientApiVer.release, + tsmClientApiVer.level ) ; + + if ( DSMI_DIR != NULL ) + { + strncpy( tsmEnvSetUpParms.dsmiDir, DSMI_DIR, TSM_MAXPATH_LEN + 1 ) ; + } + if ( DSMI_CONFIG != NULL ) + { + strncpy( tsmEnvSetUpParms.dsmiConfig, DSMI_CONFIG, TSM_MAXPATH_LEN + 1 ) ; + } + if ( DSMI_LOG != NULL ) + { + strncpy( tsmEnvSetUpParms.dsmiLog, DSMI_LOG, TSM_MAXPATH_LEN + 1 ) ; + } + + threadMode = DetermineThreadMode( clientLibVer ) ; + tsmRc = dsmSetUp( threadMode, &tsmEnvSetUpParms ) ; + + /* ----------------------------------------------------- */ + /* Indicate if the environment setup was not successful */ + /* ----------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + userExitRc = RC_DEFECT ; /* dsmSetUp() failed */ + + sprintf( errorHelpString,"%s %d%s", + "dsmSetUp() returned", tsmRc, NEW_LINE ) ; + } + else + { + tsmRc = dsmInit( &tsmHandle, &tsmClientApiVer, NULL, NULL, + inputParms->tsmPasswd, FILE_SPACE_TYPE, + NULL, DSMINIT_OPTIONS ) ; + + /* ----------------------------------------------------- */ + /* Indicate if the initialization was not successful */ + /* ----------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + userExitRc = RC_DEFECT ; /* dsmInit() failed */ + + sprintf( errorHelpString,"%s %d%s", + "dsmInit() returned", tsmRc, NEW_LINE ) ; + } + else + { + /* -------------------------------------------------- */ + /* If the session initialization was successful */ + /* initialize common TSM data structures and ARCHIVE */ + /* or RETRIEVE the file */ + /* -------------------------------------------------- */ + sprintf( fileSpaceName, "/%s", inputParms->dbName ) ; + strcpy( objectName.fs, fileSpaceName ) ; + sprintf( objectName.hl, "/%s", inputParms->nodeNumber ) ; + sprintf( objectName.ll, "/%s", inputParms->logFile ) ; + objectName.objType = DSM_OBJ_FILE ; + + if ( archiveRequested ) + { + userExitRc = ArchiveFile( + tsmHandle, /* session handle */ + objectName, /* object name */ + inputParms, + fileSpaceName, /* filespace name */ + errorHelpString);/* error string */ + } + else + { + userExitRc = RetrieveFile( + tsmHandle, /* session handle */ + objectName, /* object name */ + inputParms, + &fileMissing, /* file missing flag */ + errorHelpString);/* error string */ + } + } + } + + /* -------------------------------------------------------- */ + /* Cleanup the environment after the TSM session */ + /* -------------------------------------------------------- */ + dsmCleanUp( threadMode ) ; + + /* ----------------------------------------------------------- */ + /* Trace any errors */ + /* ----------------------------------------------------------- */ + if ( userExitRc != RC_OK ) + { + PrintErr ; + } + + /* ----------------------------------------------------------- */ + /* Trace the end of execution if the user has asked for an */ + /* audit log */ + /* ----------------------------------------------------------- */ + if (( AUDIT_ACTIVE ) && + ( auditLogRc != AUDIT_IO_ERROR )) + { + auditLogRc = AuditLogEnd ( + auditFileName, /* audit log file name */ + userExitRc, /* user exit return code */ + errorHelpString ) ; /* error isolation string*/ + + if ( auditLogRc == AUDIT_IO_ERROR )/* IO error on audit log */ + { + PrintErr ; + } + } + } + + /* -------------------------------------------------------------- */ + /* Return the specified value to the caller */ + /* -------------------------------------------------------------- */ + exit( userExitRc ) ; +} + + +/*********************************************************************/ +/* ArchiveFile() - Archive a log file to TSM */ +/*********************************************************************/ +unsigned int + ArchiveFile( unsigned long tsmHandle, + dsmObjName objectName, + INPUT_PARMS *inputParms, + char *fileSpaceName, + char *errorHelpString ) +{ + int fh ; /* file handle to log file */ + regFSData regFileSpaceData ; /* register file space struct */ + mcBindKey mcData ; /* bind structure */ + sndArchiveData archiveData ; /* archive data structure */ + ObjAttr objectAttr ; /* object attribute structure */ + DataBlk dataBlock ; /* data block structure */ + int rc ; /* function return code */ + signed short tsmRc ; /* TSM API return code */ + unsigned short reason ; /* reason for end trans API */ + signed int amountRead ; /* number bytes read from log */ + offset_t logFileSize ; /* size of the log file */ + char fileSpaceType[ FILE_SPACE_LEN ] ; + /* file space type */ + char archiveFile[ TSM_FILE_LEN ] ; + /* archive file name */ + char archiveDescription[ TSM_DESC_LEN ] ; + /* archive file description */ + char *logBuffer = NULL; /* log buffer to transmit */ + char archivedFile [ FILE_NAME_LEN ]; + /* logfile name and path */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + fh = 0 ; + rc = RC_OK ; + tsmRc = DSM_RC_OK ; + reason = RC_OK ; + amountRead = 0 ; + memset( fileSpaceType, '\0', FILE_SPACE_LEN ) ; + memset( archiveFile, '\0', TSM_FILE_LEN ) ; + memset( archiveDescription, '\0', TSM_DESC_LEN ) ; + + /* ----------------------------------------------------------- */ + /* Initialize the archived file path and name. For rawlogs we */ + /* ignore the logFile parameter and use the logFilePath only. */ + /* ----------------------------------------------------------- */ + if (inputParms->logSize == NULL) + { + sprintf( archivedFile, /* file to be archived */ + "%s%s", /* format of parm string */ + inputParms->logFilePath, /* log file path */ + inputParms->logFile ) ; /* log file name */ + } + else + { + sprintf( archivedFile, /* file to be archived */ + "%s", /* format of parm string */ + inputParms->logFilePath );/* log file path */ + } + + + /* ----------------------------------------------------------- */ + /* Initialize the register filespace parameters */ + /* ----------------------------------------------------------- */ + strcpy( fileSpaceType, FILE_SPACE_TYPE ) ; + regFileSpaceData.stVersion = regFSDataVersion ; + regFileSpaceData.fsName = fileSpaceName ; + regFileSpaceData.fsType = fileSpaceType ; + regFileSpaceData.occupancy.hi = 0 ; + regFileSpaceData.occupancy.lo = 0 ; + regFileSpaceData.capacity.hi = 0 ; + regFileSpaceData.capacity.lo = 0 ; + strcpy( regFileSpaceData.fsAttr.unixFSAttr.fsInfo, + inputParms->dbName ) ; + regFileSpaceData.fsAttr.unixFSAttr.fsInfoLength = + strlen( inputParms->dbName ) + 1 ; + + /* ----------------------------------------------------------- */ + /* Register the filespace with TSM. You may want to comment */ + /* this call out if you have already registered the file space.*/ + /* ----------------------------------------------------------- */ + tsmRc = dsmRegisterFS( tsmHandle, ®FileSpaceData ) ; + + /* ----------------------------------------------------------- */ + /* If the filespace is already registered or the register was */ + /* successful we can continue */ + /* ----------------------------------------------------------- */ + if (( tsmRc == DSM_RC_FS_ALREADY_REGED ) || + ( tsmRc == DSM_RC_OK )) + { + rc = RC_OK ; + } + else + { + sprintf( errorHelpString, "%s %d%s", "dsmRegisterFS() returned", + tsmRc, NEW_LINE ) ; + + rc = RC_DEFECT ; + } + + /* -------------------------------------------------------------- */ + /* The register has checked out, now we must bind */ + /* -------------------------------------------------------------- */ + if ( rc == RC_OK ) + { + mcData.stVersion = mcBindKeyVersion ; + + tsmRc = dsmBindMC(tsmHandle, &objectName, stArchive, &mcData) ; + + /* ----------------------------------------------------------- */ + /* Indicate the bind failed */ + /* ----------------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf( errorHelpString,"%s %d%s", "dsmBindMC() returned", + tsmRc, NEW_LINE ) ; + + rc = RC_DEFECT ; + } + } + + if ( rc == RC_OK ) + { + fh = open(archivedFile, O_RDONLY | O_RSHARE); + if (fh == -1) + { + if (errno == ENOENT) + { + rc = RC_OK; + strcpy(errorHelpString, + "File does not exist, assume it is already archived."); + goto finish; + } + else + { + rc = RC_UNKNOWN; + sprintf(errorHelpString, + "Fail to open the log file %s, errno = %d%s", + archivedFile, errno, NEW_LINE); + } + } + else + { + /* ----------------------------------------------------- */ + /* Find out the size of the log file if not supplied */ + /* ----------------------------------------------------- */ + int startingPage; + offset_t offsetll; + + if (inputParms->logSize == NULL ) + { + logFileSize = llseek( fh, 0LL, SEEK_END ); + rc = logFileSize; + if ( logFileSize >= 0 ) + { + rc = llseek(fh, 0LL, SEEK_SET); + } + + if (rc == -1) + { + sprintf(errorHelpString, + "Error seeking to end of file %s %s errno = %d%s", + archivedFile, "in ArchiveFile(),", + errno, NEW_LINE); + + rc = RC_UNKNOWN; + } + } + else + { + logFileSize = atol (inputParms->logSize) * 4096; + } + + /* ----------------------------------------------------------- */ + /* Position the file pointer to proper position in the file */ + /* ----------------------------------------------------------- */ + if (inputParms->startingPage != NULL) + { + startingPage = atoi(inputParms->startingPage); + offsetll = (offset_t)startingPage * 4096; + if (llseek(fh, offsetll, SEEK_SET) == -1) + { + sprintf(errorHelpString, "llseek() failed, errno = %d%s", + errno, NEW_LINE); + + rc = RC_UNKNOWN; + } + } + } + } + + if ( rc == RC_OK ) + { + /* ----------------------------------------------------------- */ + /* Allocate memory for logBuffer */ + /* ----------------------------------------------------------- */ + logBuffer = malloc(BUFFER_SIZE); + if (logBuffer == NULL) + { + sprintf(errorHelpString, "malloc() failed, BUFFER_SIZE %d, errno = %d", + BUFFER_SIZE, errno); + rc = RC_UNKNOWN; + } + else + { + /* -------------------------------------------------------- */ + /* The register and bind have checked out so begin the */ + /* transaction */ + /* -------------------------------------------------------- */ + tsmRc = dsmBeginTxn(tsmHandle); + + /* -------------------------------------------------------- */ + /* Indicate the begin transaction failed */ + /* -------------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf(errorHelpString, "%s %d%s", + "dsmBeginTxn() returned", tsmRc, NEW_LINE); + + rc = RC_DEFECT; + } + } + } + + if ( rc == RC_OK ) + { + /* ----------------------------------------------------------- */ + /* Initialize the send object parameters */ + /* ----------------------------------------------------------- */ + sprintf( archiveDescription, "%s %s", + "Log file for DB2 database", inputParms->dbName ) ; + + archiveData.stVersion = sndArchiveDataVersion ; + archiveData.descr = archiveDescription ; + + memset(&objectAttr, 0, sizeof(objectAttr)) ; + objectAttr.stVersion = ObjAttrVersion ; + objectAttr.owner[ 0 ] = '\0' ; + objectAttr.sizeEstimate.hi = 0 ; + objectAttr.sizeEstimate.lo = logFileSize ; + objectAttr.objCompressed = bFalse ; + sprintf( archiveFile, + "%s.%s", + inputParms->dbName, + inputParms->logFile ) ; + objectAttr.objInfo = archiveFile ; + objectAttr.objInfoLength = strlen( archiveFile ) + 1 ; + objectAttr.mcNameP = MGMT_CLASS ; + + dataBlock.stVersion = DataBlkVersion ; + dataBlock.bufferPtr = NULL ; + dataBlock.bufferLen = 0 ; + dataBlock.numBytes = 0 ; + + /* ----------------------------------------------------------- */ + /* Initialize the sending of the object to TSM */ + /* ----------------------------------------------------------- */ + tsmRc = dsmSendObj( tsmHandle, stArchive, &archiveData, + &objectName, &objectAttr, &dataBlock ) ; + + /* ----------------------------------------------------------- */ + /* Indicate the send object failed */ + /* ----------------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf( errorHelpString,"%s %d%s", + "dsmSendObj() returned", tsmRc, NEW_LINE ) ; + + rc = RC_DEFECT ; + } + else + { + /* -------------------------------------------------------- */ + /* The call to send object was successful so send the */ + /* contents in portions of BUFFER_SIZE bytes */ + /* -------------------------------------------------------- */ + memset( logBuffer, '\0', BUFFER_SIZE ) ; + + /* ----------------------------------------------------- */ + /* Keep sending the object until the end of the log file */ + /* or until an error is detected */ + /* ----------------------------------------------------- */ + while (( logFileSize > 0 ) && + ( rc == RC_OK )) + { + amountRead = read( fh, logBuffer, BUFFER_SIZE ) ; + if ( amountRead < BUFFER_SIZE ) + { + if ((amountRead == 0) || + ((amountRead % 4096) != 0)) + { + sprintf(errorHelpString,"%s %s, %s %d%s", + "Error reading from file", archivedFile, + "amount read", amountRead, NEW_LINE); + rc = RC_UNKNOWN; + } + } + + /* -------------------------------------------------- */ + /* If the read is deemed successful, send the buffer */ + /* to TSM. */ + /* -------------------------------------------------- */ + if ( rc == RC_OK ) + { + logFileSize -= amountRead; + dataBlock.bufferLen = amountRead; + dataBlock.bufferPtr = logBuffer; + + tsmRc = dsmSendData(tsmHandle, &dataBlock); + + /* ----------------------------------------------- */ + /* Indicate the send data failed */ + /* ----------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf( errorHelpString,"%s %d%s", + "dsmSendData() returned", tsmRc, + NEW_LINE ) ; + + rc = RC_DEFECT ; + } + } + } + + /* ----------------------------------------------------- */ + /* Close the log file */ + /* ----------------------------------------------------- */ + if ( close( fh )) + { + /* -------------------------------------------------- */ + /* Indicate the file close failed if no other error */ + /* has occurred */ + /* -------------------------------------------------- */ + if ( rc == RC_OK) + { + sprintf(errorHelpString, + "Error closing file %s in ArchiveFile(), errno = %d%s", + archivedFile, errno, NEW_LINE); + + rc = RC_UNKNOWN ; + } + } + + /* -------------------------------------------------------- */ + /* End the sending of the object */ + /* -------------------------------------------------------- */ + if ( rc == RC_OK ) + { + tsmRc = dsmEndSendObj( tsmHandle ) ; + + /* ----------------------------------------------------- */ + /* Indicate the end send object failed */ + /* ----------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf(errorHelpString,"%s %d%s", + "dsmEndSendObj() returned", tsmRc, NEW_LINE); + + rc = RC_DEFECT; + } + } + else + { + (void)dsmEndSendObj(tsmHandle); + } + } + + /* ----------------------------------------------------------- */ + /* End the transaction */ + /* ----------------------------------------------------------- */ + if (rc == RC_OK) + { + tsmRc = dsmEndTxn(tsmHandle, DSM_VOTE_COMMIT, &reason); + + /* -------------------------------------------------------- */ + /* Indicate the end transaction failed */ + /* -------------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf(errorHelpString,"%s %d %s %d%s", + "dsmEndTxn() returned", tsmRc, "Reason", + reason, NEW_LINE); + + rc = RC_DEFECT; + } + } + else + { + (void)dsmEndTxn(tsmHandle, DSM_VOTE_ABORT, &reason); + } + + /* -------------------------------------------------- */ + /* Terminate the TSM session */ + /* -------------------------------------------------- */ + if (rc == RC_OK) + { + tsmRc = dsmTerminate( tsmHandle ) ; + + if ( tsmRc != DSM_RC_OK) + { + rc = RC_DEFECT ; + + sprintf( errorHelpString,"%s %d%s", + "dsmTerminate() returned", + tsmRc, NEW_LINE ) ; + } + } + else + { + (void) dsmTerminate( tsmHandle ); + } + } + +finish: + return(rc); +} + + +/*********************************************************************/ +/* RetrieveFile() - Retrieve a log file from TSM */ +/*********************************************************************/ +unsigned int + RetrieveFile( unsigned long tsmHandle, + dsmObjName objectName, + INPUT_PARMS *inputParms, + unsigned int *fileMissing, + char *errorHelpString ) +{ + FILE *fp ; /* pointer to log file */ + ObjID objectId ; /* object id structure */ + DataBlk dataBlock ; /* data block structure */ + dsmGetList getList ; /* get list structure */ + qryArchiveData queryData ; /* query data structure */ + qryRespArchiveData queryRespData ; /* query response structure */ + unsigned short objNotFinished ; /* object not finished flag */ + unsigned short fileNotComplete; /* file not complete flag */ + unsigned int rc ; /* function return code */ + unsigned int amountWrite ; /* number of bytes written */ + char *logBuffer = NULL; /* log buffer to transmit */ + char retrievedFile[FILE_NAME_LEN]; + /* logfile name and path */ + char tempFile[FILE_NAME_LEN]; + char systemCommand[2*FILE_NAME_LEN + 12]; + char *tmpPtr; + int fileNameLen; + signed short tsmRc ; /* TSM API return code */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + fp = NULL ; + objNotFinished = TRUE ; + fileNotComplete = TRUE ; + *fileMissing = FALSE ; + rc = RC_OK ; + amountWrite = 0 ; + tsmRc = DSM_RC_OK ; + sprintf(retrievedFile, /* file to be archived */ + "%s%s", /* format of parm string */ + inputParms->logFilePath, /* log file path */ + inputParms->logFile); /* log file name */ + + strcpy(tempFile, retrievedFile); + fileNameLen = strlen(tempFile); + strcpy(&tempFile[fileNameLen - 3], "TMP"); + + + /* -------------------------------------------------------------- */ + /* Initialize the begin query parameters */ + /* -------------------------------------------------------------- */ + queryData.stVersion = qryArchiveDataVersion ; + queryData.objName = &objectName ; + queryData.owner = NULL ; + queryData.descr = "*" ; + queryData.insDateLowerBound.year = DATE_MINUS_INFINITE ; + queryData.insDateUpperBound.year = DATE_PLUS_INFINITE ; + queryData.expDateLowerBound.year = DATE_MINUS_INFINITE ; + queryData.expDateUpperBound.year = DATE_PLUS_INFINITE ; + + /* -------------------------------------------------------------- */ + /* Begin the query */ + /* -------------------------------------------------------------- */ + tsmRc = dsmBeginQuery(tsmHandle,qtArchive,(void *) &queryData) ; + + /* -------------------------------------------------------------- */ + /* Indicate the begin query failed */ + /* -------------------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf(errorHelpString,"%s %d%s","dsmBeginQuery() returned", + tsmRc, NEW_LINE); + + rc = RC_DEFECT; + } + + if ( rc == RC_OK ) + { + /* ----------------------------------------------------------- */ + /* Allocate memory for logBuffer */ + /* ----------------------------------------------------------- */ + logBuffer = malloc(BUFFER_SIZE); + if (logBuffer == NULL) + { + sprintf(errorHelpString, "malloc() failed, BUFFER_SIZE %d, errno = %d", + BUFFER_SIZE, errno); + rc = RC_UNKNOWN; + } + else + memset(logBuffer, '\0', BUFFER_SIZE); + } + + if ( rc == RC_OK ) + { + /* ----------------------------------------------------------- */ + /* Initialize the get next object query parameters */ + /* ----------------------------------------------------------- */ + queryRespData.stVersion = qryRespArchiveDataVersion ; + + dataBlock.stVersion = DataBlkVersion ; + dataBlock.bufferPtr = ( char * ) &queryRespData ; + dataBlock.bufferLen = sizeof( qryRespArchiveData ) ; + + /* ----------------------------------------------------------- */ + /* Query TSM for the object until all objects are queried or */ + /* the object is not found or an unexpected error occurs */ + /* (This logic should pick up the last version of the object) */ + /* ----------------------------------------------------------- */ + while (( objNotFinished ) && + ( rc == RC_OK ) && + ( !(*fileMissing) )) + { + tsmRc = dsmGetNextQObj( tsmHandle, &dataBlock ) ; + + switch ( tsmRc ) + { + /* ------------------------------------------------------ */ + /* The query has finished */ + /* ------------------------------------------------------ */ + case DSM_RC_FINISHED: objNotFinished = FALSE ; + rc = RC_OK ; + break ; + + /* ------------------------------------------------------ */ + /* Still more data to query */ + /* ------------------------------------------------------ */ + case DSM_RC_MORE_DATA: rc = RC_OK ; + break ; + + /* ------------------------------------------------------ */ + /* No match was found */ + /* ------------------------------------------------------ */ + case DSM_RS_ABORT_NO_MATCH: rc = RC_OK ; + *fileMissing = TRUE ; + break ; + + /* ------------------------------------------------------ */ + /* Unexpected return code has been received */ + /* ------------------------------------------------------ */ + default: sprintf( errorHelpString,"%s %d%s", + "dsmGetNextQObj() returned",tsmRc, + NEW_LINE ) ; + rc = RC_DEFECT ; + break ; + } + } + + /* ----------------------------------------------------------- */ + /* End the query */ + /* ----------------------------------------------------------- */ + if ( rc == RC_OK ) + { + tsmRc = dsmEndQuery( tsmHandle ) ; + + /* -------------------------------------------------------- */ + /* Indicate the end query failed */ + /* -------------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf( errorHelpString,"%s %d%s", + "dsmEndQuery() returned", tsmRc, NEW_LINE ) ; + + rc = RC_DEFECT ; + } + } + else + { + ( void ) dsmEndQuery( tsmHandle ) ; + } + } + + /* -------------------------------------------------------------- */ + /* If the file to retrieve was found, start pulling the data */ + /* from TSM */ + /* -------------------------------------------------------------- */ + if (( rc == RC_OK ) && + ( !(*fileMissing) )) + { + /* ----------------------------------------------------------- */ + /* Open the log file as write binary */ + /* ----------------------------------------------------------- */ + fp = fopen(tempFile, "wb"); + + /* ----------------------------------------------------------- */ + /* If the file was opened successfully */ + /* ----------------------------------------------------------- */ + if ( fp != NULL ) + { + /* -------------------------------------------------------- */ + /* Initialize the begin get data parameters */ + /* -------------------------------------------------------- */ + objectId = queryRespData.objId ; + + getList.stVersion = dsmGetListVersion ; + getList.numObjId = 1 ; + getList.objId = &objectId ; + + /* -------------------------------------------------------- */ + /* Begin the data transfer */ + /* -------------------------------------------------------- */ + tsmRc = dsmBeginGetData( tsmHandle, bTrue, gtArchive, + &getList ) ; + + /* -------------------------------------------------------- */ + /* Indicate that begin get data failed */ + /* -------------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf( errorHelpString, "%s %d%s", + "dsmBeginGetData() returned", tsmRc, NEW_LINE ) ; + + rc = RC_DEFECT ; + } + else + { + /* ----------------------------------------------------- */ + /* Initialize the Get Object parameters */ + /* ----------------------------------------------------- */ + dataBlock.bufferPtr = logBuffer; + dataBlock.bufferLen = 0; + + /* ----------------------------------------------------- */ + /* Get the object specifying a buffer length of zero */ + /* ----------------------------------------------------- */ + tsmRc = dsmGetObj( tsmHandle, &objectId, &dataBlock ) ; + + /* ----------------------------------------------------- */ + /* Indicate the get object failed */ + /* ----------------------------------------------------- */ + if ( tsmRc != DSM_RC_MORE_DATA ) + { + sprintf( errorHelpString,"%s %d%s", + "dsmGetObj() returned", tsmRc, NEW_LINE ) ; + + rc = RC_DEFECT ; + } + else + { + /* -------------------------------------------------- */ + /* Initialize the get data parameters */ + /* -------------------------------------------------- */ + dataBlock.bufferPtr = logBuffer ; + dataBlock.bufferLen = BUFFER_SIZE ; + rc = RC_OK ; + + while (( fileNotComplete ) && + ( rc == RC_OK )) + { + /* ----------------------------------------------- */ + /* Get the object data from TSM */ + /* ----------------------------------------------- */ + tsmRc = dsmGetData( tsmHandle, &dataBlock ) ; + + if (( tsmRc == DSM_RC_FINISHED ) || + ( tsmRc == DSM_RC_MORE_DATA )) + { + /* -------------------------------------------- */ + /* Signal that we are finished */ + /* -------------------------------------------- */ + if ( tsmRc == DSM_RC_FINISHED ) + { + fileNotComplete = FALSE ; + } + + /* -------------------------------------------- */ + /* Write the buffer to the log file */ + /* -------------------------------------------- */ + amountWrite = fwrite( dataBlock.bufferPtr, 1, + dataBlock.numBytes, fp ) ; + + /* -------------------------------------------- */ + /* Indicate the write failed */ + /* -------------------------------------------- */ + if ( amountWrite != dataBlock.numBytes ) + { + + sprintf(errorHelpString,"%s %s %s%s", + "Error writing to file", tempFile, + "in RetrieveFile()",NEW_LINE); + + rc = RC_UNKNOWN; + } + else + { + rc = RC_OK; + } + + amountWrite = 0; + } + else + { + /* -------------------------------------------- */ + /* Indicate that get data failed */ + /* -------------------------------------------- */ + sprintf(errorHelpString,"%s %d%s", + "dsmGetData() returned",tsmRc,NEW_LINE) ; + + rc = RC_DEFECT ; + } + } + } + } + + /* -------------------------------------------------------- */ + /* Close the log file */ + /* -------------------------------------------------------- */ + if (fclose( fp )) + { + /* ----------------------------------------------------- */ + /* Indicate the file close failed if no other error has */ + /* occurred */ + /* ----------------------------------------------------- */ + if (rc == RC_OK) + { + sprintf(errorHelpString,"%s %s %s%s", + "Error closing file", + tempFile, "in RetrieveFile()", NEW_LINE); + + rc = RC_UNKNOWN; + } + } + } + else + { + /* -------------------------------------------------------- */ + /* Indicate file open failed */ + /* -------------------------------------------------------- */ + sprintf(errorHelpString,"%s %s %s%s","Error opening file", + tempFile,"in RetrieveFile()", NEW_LINE); + + rc = RC_UNKNOWN; + } + + /* ----------------------------------------------------------- */ + /* End the get object operation */ + /* ----------------------------------------------------------- */ + if ( rc == RC_OK ) + { + tsmRc = dsmEndGetObj( tsmHandle ) ; + + /* -------------------------------------------------------- */ + /* Indicate the end get object failed */ + /* -------------------------------------------------------- */ + if ( tsmRc != DSM_RC_OK ) + { + sprintf(errorHelpString,"%s %d%s", + "dsmEndGetObj() returned", tsmRc, NEW_LINE); + + rc = RC_DEFECT; + } + } + else + { + (void)dsmEndGetObj(tsmHandle); + } + + /* ----------------------------------------------------------- */ + /* End the get data operation */ + /* ----------------------------------------------------------- */ + if ( rc == RC_OK ) + { + tsmRc = dsmEndGetData(tsmHandle); + + if (tsmRc != DSM_RC_OK) + { + /* ----------------------------------------------------- */ + /* Indicate the end get data failed */ + /* ----------------------------------------------------- */ + sprintf(errorHelpString,"%s %d%s", + "dsmEndGetData() returned", tsmRc, NEW_LINE); + + rc = RC_DEFECT; + } + } + else + { + (void)dsmEndGetData(tsmHandle); + } + + /* -------------------------------------------------- */ + /* Terminate the TSM session */ + /* -------------------------------------------------- */ + if (rc == RC_OK) + { + tsmRc = dsmTerminate( tsmHandle ); + + if ( tsmRc != DSM_RC_OK ) + { + sprintf( errorHelpString,"%s %d%s", + "dsmTerminate() returned", + tsmRc, NEW_LINE ); + + rc = RC_DEFECT; + } + } + else + { + (void) dsmTerminate( tsmHandle ); + } + + if (rc == RC_OK) + { + rc = rename(tempFile, retrievedFile); + + if (rc != RC_OK) + { + sprintf(errorHelpString,"Failed to rename temp file, rc = %d", + rc); + + rc = RC_UNKNOWN; + } + } + else + { + sprintf(systemCommand, "REMOVE %s", tempFile); + system(systemCommand); + } + } + + return(rc); +} + + +/*********************************************************************/ +/* SignalEnd() - If a signal has been raised for which we have */ +/* installed a handler, perform the following: */ +/* . trace the signal in the error log (if enabled) */ +/* . exit the user exit with a RC_OPCAN return code */ +/*********************************************************************/ +void SignalEnd( int sigNum ) +{ + unsigned int userExitRc ; /* user exit return code */ + char errorHelpString[ HELP_STRING_LEN ] ; + /* error help string */ + + /* -------------------------------------------------------------- */ + /* Set the user exit return code to operator cancelled */ + /* -------------------------------------------------------------- */ + userExitRc = RC_OPCAN ; + + /* -------------------------------------------------------------- */ + /* Log the error if the error log has been requested */ + /* -------------------------------------------------------------- */ + if ( ERROR_ACTIVE ) + { + memset( errorHelpString, '\0', HELP_STRING_LEN ) ; + + sprintf( errorHelpString,"%s %d %s %s%s","Signal",sigNum, + ( sigNum == SIGTERM ) ? "(SIGTERM)" : "(SIGINT)", + "has been raised",NEW_LINE ) ; + + ErrorLog( NULL, NULL, NULL, userExitRc, errorHelpString ) ; + } + + /* -------------------------------------------------------------- */ + /* Exit the user exit with the appropriate return code */ + /* -------------------------------------------------------------- */ + exit( userExitRc ) ; +} + + +/*********************************************************************/ +/* AuditLogStart() - Log the following at user exit entrance: */ +/* 1. time system call was made */ +/* 2. parameters passed to the user exit */ +/* 3. media type */ +/*********************************************************************/ +unsigned int + AuditLogStart( INPUT_PARMS *inputParms, + char *auditFileName, + char *errorHelpString ) +{ + FILE *auditLogFp ; /* pointer to audit log file */ + unsigned int auditLogRc ; /* AuditLogStart() return code*/ + time_t actionTime ; /* date and time of exit start*/ + char outputLine[ OUTPUT_LINE_LEN ] ; + /* line to be written to log */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + auditLogFp = NULL ; + auditLogRc = RC_OK ; + memset( &actionTime, 0, sizeof( actionTime )) ; + memset( outputLine, '\0', OUTPUT_LINE_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Open the audit log file using the appropriate file name and */ + /* user defined file attributes */ + /* -------------------------------------------------------------- */ + auditLogFp = fopen( auditFileName, AUDIT_ERROR_ATTR ) ; + + /* -------------------------------------------------------------- */ + /* If the audit log file opened successfully, write the data to */ + /* the file */ + /* -------------------------------------------------------------- */ + if ( auditLogFp != NULL ) + { + memset( outputLine, '*', DELIMITER_LEN ) ; + outputLine[ DELIMITER_LEN ] = '\n' ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + time( &actionTime ) ; /* time system call started */ + sprintf( outputLine, + "%s%s%s", + "Time Started: ", + ctime( &actionTime ), + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + if ( PrintArguments( auditLogFp, inputParms ) != RC_OK ) + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( outputLine, /* system action */ + "%s %s %s %s file %s %s %s for database %s%s", + "System Action: ", + inputParms->request, + ( archiveRequested ) ? "from" : "to", + inputParms->logFilePath, + inputParms->logFile, + ( archiveRequested ) ? "to" : "from", + "TSM", + inputParms->dbName, + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( outputLine, /* user defined media type */ + "%s %s%s", + "Media Type: ", + MEDIA_TYPE, + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + /* ----------------------------------------------------------- */ + /* If an error was encountered during the audit log write */ + /* ----------------------------------------------------------- */ + if ( auditLogRc == AUDIT_IO_ERROR ) + { + sprintf( errorHelpString, "%s%s", + "Error writing to the Audit Log file",NEW_LINE ) ; + + ( void ) fclose( auditLogFp ) ; /* close the audit log */ + + } + else + { + if ( fclose( auditLogFp ) ) /* close the audit log */ + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString, "%s%s", + "Error closing Audit Log file", NEW_LINE ) ; + } + } + } + else /* error opening file */ + { + auditLogRc = AUDIT_IO_ERROR; + + sprintf(errorHelpString, "%s%s", + "Error opening Audit Log file", NEW_LINE); + } + + return(auditLogRc); +} + + +/*********************************************************************/ +/* AuditLogEnd() - Log the following at user exit end: */ +/* 1. time system call returned */ +/* 2. user exit return code */ +/*********************************************************************/ +unsigned int + AuditLogEnd( char *auditFileName, + unsigned int userExitRc, + char *errorHelpString ) +{ + FILE *auditLogFp ; /* pointer to audit log file */ + unsigned int auditLogRc ; /* AuditLogEnd() return code */ + time_t actionTime ; /* date and time of exit end */ + char outputLine[OUTPUT_LINE_LEN]; + /* line to be written to log */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + auditLogFp = NULL ; + auditLogRc = RC_OK ; + memset( &actionTime, 0, sizeof( actionTime )) ; + memset( outputLine, '\0', OUTPUT_LINE_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Open the audit log file using the appropriate file name and */ + /* user defined file attributes */ + /* -------------------------------------------------------------- */ + auditLogFp = fopen( auditFileName, AUDIT_ERROR_ATTR ) ; + + /* -------------------------------------------------------------- */ + /* If the audit log file opened successfully, write the data to */ + /* the file */ + /* -------------------------------------------------------------- */ + if ( auditLogFp != NULL ) + { + sprintf( outputLine, /* user exit return code */ + "%s %d %s%s", + "User Exit RC: ", + userExitRc, + ( userExitRc ) ? "|||> ERROR <|||" : errorHelpString, + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + time( &actionTime ) ; /* time system call completed */ + sprintf( outputLine, + "%s %s%s", + "Time Completed: ", + ctime( &actionTime ), + NEW_LINE ) ; + + if (( fprintf( auditLogFp, outputLine ) ) <= 0 ) + auditLogRc = AUDIT_IO_ERROR ; + + /* ----------------------------------------------------------- */ + /* If an error was encountered during the audit log write */ + /* ----------------------------------------------------------- */ + if ( auditLogRc == AUDIT_IO_ERROR ) + { + sprintf( errorHelpString, "%s%s", + "Error writing to the Audit Log file", NEW_LINE ) ; + + ( void ) fclose( auditLogFp ) ; /* close the audit log */ + + } + else + { + if ( fclose( auditLogFp ) ) /* close the audit log */ + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString,"%s%s", + "Error closing Audit Log file", NEW_LINE ) ; + } + } + } + else /* error opening file */ + { + auditLogRc = AUDIT_IO_ERROR ; + + sprintf( errorHelpString,"%s%s", + "Error opening Audit Log file",NEW_LINE ) ; + } + + return( auditLogRc ) ; +} + + +/*********************************************************************/ +/* ErrorLog() - Log the following if an error has occurred: */ +/* . time the error occurred */ +/* . values of all parameters passed to the user */ +/* exit at the time of the error */ +/* . media type */ +/* . audit log file name */ +/* . system call string */ +/* . user exit return code */ +/* . error isolation help string */ +/*********************************************************************/ +void ErrorLog( INPUT_PARMS *inputParms, + char *auditFileName, + char *systemCallParms, + unsigned int userExitRc, + char *errorHelpString ) +{ + FILE *errorLogFp ; /* pointer to error log file */ + time_t actionTime ; /* date and time of error */ + char outputLine[ OUTPUT_LINE_LEN ] ; + /* line to be written to log */ + char errorFileName[ FILE_NAME_LEN ] ; + /* error log file name */ + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + errorLogFp = NULL ; + memset( &actionTime, 0, sizeof( actionTime )) ; + memset( outputLine, '\0', OUTPUT_LINE_LEN ) ; + memset( errorFileName, '\0', FILE_NAME_LEN ) ; + + /* -------------------------------------------------------------- */ + /* Open the error log file using the user defined name and file */ + /* attributes */ + /* -------------------------------------------------------------- */ + sprintf( errorFileName, + "%s%s", + AUDIT_ERROR_PATH, /* error log path */ + ERROR_FILE_NAME ) ; /* error log file name */ + + errorLogFp = fopen( errorFileName, AUDIT_ERROR_ATTR ) ; + + /* -------------------------------------------------------------- */ + /* If the error log file opened successfully, write the available */ + /* data to the file */ + /* -------------------------------------------------------------- */ + if ( errorLogFp != NULL ) + { + memset( outputLine, '*', DELIMITER_LEN ) ; + outputLine[ DELIMITER_LEN ] = '\n' ; + fprintf( errorLogFp, outputLine ) ; + + time( &actionTime ) ; /* time error occurred */ + sprintf( outputLine, + "%s %s%s", + "Time of Error: ", + ctime( &actionTime ), + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + + if ( inputParms != NULL ) /* parmeters passed to user */ + { /* exit */ + (void) PrintArguments( errorLogFp, inputParms ) ; + } + + if (auditFileName) + { + sprintf( outputLine, /* audit log file name */ + "%s %s%s", + "Audit Log File: ", + auditFileName, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + } + + if (systemCallParms) + { + sprintf( outputLine, /* system call string */ + "%s %s%s", + "System Call Parms:", + systemCallParms, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + } + + sprintf( outputLine, /* user defined media type */ + "%s %s%s", + "Media Type: ", + MEDIA_TYPE, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* user exit return code */ + "%s %d %s%s", + "User Exit RC: ", + userExitRc, + NEW_LINE, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + sprintf( outputLine, /* error isolation string */ + "%s %s%s%s", + "> Error isolation:", + errorHelpString, + NEW_LINE, + NEW_LINE ) ; + fprintf( errorLogFp, outputLine ) ; + + /* ----------------------------------------------------------- */ + /* Close the error log file */ + /* ----------------------------------------------------------- */ + fclose( errorLogFp ) ; + } + + return ; +} + + +unsigned int + ParseArguments( int argc , + char *argv[] , + INPUT_PARMS *inputParms , + char *errorHelpString ) +{ + int parseRc; /* ParseArguments() return code */ + int count; /* index for for loop */ + char *argument; /* pointer to argument */ + int parmLen; /* length of parameter */ + int parmIden; /* parameter identifier */ + char *parmValue; /* parameter value */ + + + /* -------------------------------------------------------------- */ + /* Initialize variables */ + /* -------------------------------------------------------------- */ + parseRc = RC_OK ; + count = 1 ; + + /* -------------------------------------------------------------- */ + /* Copy values into inputParms structure. */ + /* -------------------------------------------------------------- */ + inputParms->argc = argc; + + while ( ( count < argc ) && ( parseRc == RC_OK) ) + { + argument = argv[count]; + + parmLen = strlen(argument); + if (parmLen < 4) + { + parseRc = RC_PARM; + break; + } + + parmIden = ((argument[2]) | (argument[1] << 8) | (argument[0] << 16)); + parmValue = &argument[3]; + +#define INPUT_PARM_AP 0x2d4150 /* -AP */ +#define INPUT_PARM_DB 0x2d4442 /* -DB */ +#define INPUT_PARM_LN 0x2d4c4e /* -LN */ +#define INPUT_PARM_LB 0x2d4c42 /* -LB */ +#define INPUT_PARM_LP 0x2d4c50 /* -LP */ +#define INPUT_PARM_LS 0x2d4c53 /* -LS */ +#define INPUT_PARM_MD 0x2d4d44 /* -MD */ +#define INPUT_PARM_NN 0x2d4e4e /* -NN */ +#define INPUT_PARM_OS 0x2d4f53 /* -OS */ +#define INPUT_PARM_RD 0x2d5244 /* -RD */ +#define INPUT_PARM_RF 0x2d5246 /* -RF */ +#define INPUT_PARM_RL 0x2d524c /* -RL */ +#define INPUT_PARM_RQ 0x2d5251 /* -RQ */ +#define INPUT_PARM_SP 0x2d5350 /* -SP */ + + switch(parmIden) + { + case INPUT_PARM_AP: /* TSM password */ + inputParms->tsmPasswd = parmValue; + break; + case INPUT_PARM_DB: /* database name */ + inputParms->dbName = parmValue; + break; + case INPUT_PARM_LN: /* log file name */ + inputParms->logFile = parmValue; + break; + case INPUT_PARM_LB: /* label */ + inputParms->label = parmValue; + break; + case INPUT_PARM_LP: /* log file path */ + inputParms->logFilePath = parmValue; + break; + case INPUT_PARM_LS: /* log file size */ + inputParms->logSize = parmValue; + break; + case INPUT_PARM_MD: /* mode */ + inputParms->mode = parmValue; + break; + case INPUT_PARM_NN: /* node number */ + inputParms->nodeNumber = parmValue; + break; + case INPUT_PARM_OS: /* operating system */ + inputParms->operatingSys = parmValue; + break; + case INPUT_PARM_RD: /* redirection file */ + inputParms->redFile = parmValue; + break; + case INPUT_PARM_RF: /* response file */ + inputParms->responseFile = parmValue; + break; + case INPUT_PARM_RL: /* DB2 release */ + inputParms->release = parmValue; + break; + case INPUT_PARM_RQ: /* user exit request */ + inputParms->request = parmValue; + break; + case INPUT_PARM_SP: /* starting page offset */ + inputParms->startingPage = parmValue; + break; + default: /* log unrecognized parameter */ + if ( ERROR_ACTIVE ) + { + memset( errorHelpString, '\0', HELP_STRING_LEN ) ; + + sprintf( errorHelpString, + "%s %s%s%s%s", + "Unrecognized parameter :", + argument, + NEW_LINE, + "Parameter has been ignored.", + NEW_LINE ) ; + + ErrorLog( NULL, NULL, NULL, RC_OK, errorHelpString ) ; + } + break; + } + + count ++; /* increment count */ + } + + if (inputParms->request == NULL) + parseRc = RC_PARM; + + return(parseRc); +} + + + +unsigned int PrintArguments(FILE *fp, INPUT_PARMS *inputParms) +{ + char outputLine[ OUTPUT_LINE_LEN ] ; + int printRc = RC_OK ; + + sprintf( outputLine, + "%s %d%s", + "Parameter Count: ", + inputParms->argc, + NEW_LINE ) ; + + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR ; + + if ( printRc == RC_OK ) + { + sprintf( outputLine, + "%s %s", + "Parameters Passed:", + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->tsmPasswd != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "TSM password: ", + inputParms->tsmPasswd, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->dbName != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Database name: ", + inputParms->dbName, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->logFile != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Logfile name: ", + inputParms->logFile, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->label != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Label: ", + inputParms->label, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->logFilePath != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Logfile path: ", + inputParms->logFilePath, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->logSize != NULL ) ) + { + sprintf(outputLine, + "%s%s 4K pages%s", + "Logfile size: ", + inputParms->logSize, + NEW_LINE); + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->mode != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Mode: ", + inputParms->mode, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->nodeNumber != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Node number: ", + inputParms->nodeNumber, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->operatingSys != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Operating system: ", + inputParms->operatingSys, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->redFile != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Red file: ", + inputParms->redFile, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->responseFile != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Response file: ", + inputParms->responseFile, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->release != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Release: ", + inputParms->release, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->request != NULL ) ) + { + sprintf( outputLine, + "%s %s%s", + "Request: ", + inputParms->request, + NEW_LINE ) ; + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + if ( ( printRc == RC_OK ) && + ( inputParms->startingPage != NULL ) ) + { + sprintf(outputLine, + "%s %s%s", + "Starting page offset: ", + inputParms->startingPage, + NEW_LINE); + if (( fprintf( fp, outputLine ) ) <= 0 ) + printRc = AUDIT_IO_ERROR; + } + + return(printRc); +} diff --git a/c/dbauth.sqc b/c/dbauth.sqc new file mode 100644 index 0000000..8bb5024 --- /dev/null +++ b/c/dbauth.sqc @@ -0,0 +1,262 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: dbauth.sqc +** +** SAMPLE: How to grant, display, and revoke authorities at database level +** +** DB2 API USED: +** sqluadau -- Get Authorizations +** +** SQL STATEMENTS USED: +** GRANT (Database Authorities) +** SELECT INTO +** REVOKE (Database Authorities) +** +** OUTPUT FILE: dbauth.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilemb.h" + +int DbAuthGrant(void); +int DbAuthForAnyUserOrGroupDisplay(void); +int DbAuthForCurrentUserDisplay(void); +int DbAuthRevoke(void); + +/* support function */ +char *authStrVal(short); + +EXEC SQL BEGIN DECLARE SECTION; + char granteetype[2]; + char dbadmauth[2]; + char createtabauth[2]; + char bindaddauth[2]; + char connectauth[2]; + char nofenceauth[2]; + char implschemaauth[2]; + char loadauth[2]; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS " + "HOW TO GRANT/DISPLAY/REVOKE AUTHORITIES AT DATABASE LEVEL.\n"); + + /* connect to the database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + rc = DbAuthGrant(); + rc = DbAuthForAnyUserOrGroupDisplay(); + rc = DbAuthForCurrentUserDisplay(); + rc = DbAuthRevoke(); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if (rc != 0) + { + return rc; + } + + return 0; +} /* end main */ + +char *authStrVal(short authShortVal) +{ + if (authShortVal == 1) + { + return ("YES"); + } + else + { + return ("NO"); + } + +} /* authStrVal */ + +int DbAuthGrant(void) +{ + struct sqlca sqlca; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" GRANT (Database Authorities)\n"); + printf(" COMMIT\n"); + printf("TO GRANT AUTHORITIES AT DATABASE LEVEL.\n"); + + /* grant user authorities at database level */ + printf("\n GRANT CONNECT, CREATETAB, BINDADD ON DATABASE"); + printf(" TO USER user1\n"); + + EXEC SQL GRANT CONNECT, CREATETAB, BINDADD ON DATABASE TO USER user1; + EMB_SQL_CHECK("user authorities at db. level -- grant"); + + printf(" COMMIT\n"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("transaction -- commit"); + + return 0; +} /* DbAuthGrant */ + +int DbAuthForAnyUserOrGroupDisplay(void) +{ + struct sqlca sqlca; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENT:\n"); + printf(" SELECT INTO\n"); + printf("TO DISPLAY AUTHORITIES FOR ANY USER AT DATABASE LEVEL.\n"); + + printf("\n SELECT granteetype, dbadmauth, createtabauth, bindaddauth,\n" + " connectauth, nofenceauth, implschemaauth, loadauth\n" + " FROM syscat.dbauth\n" + " WHERE grantee = 'USER1'\n"); + + EXEC SQL SELECT granteetype, dbadmauth, createtabauth, bindaddauth, + connectauth, nofenceauth, implschemaauth, loadauth + INTO :granteetype, :dbadmauth, :createtabauth, :bindaddauth, + :connectauth, :nofenceauth, :implschemaauth, :loadauth + FROM syscat.dbauth + WHERE grantee = 'USER1'; + EMB_SQL_CHECK("user authorities at database level -- get"); + + printf("\n Grantee Type = %c\n", granteetype[0]); + printf(" DBADM auth. = %c\n", dbadmauth[0]); + printf(" CREATETAB auth. = %c\n", createtabauth[0]); + printf(" BINDADD auth. = %c\n", bindaddauth[0]); + printf(" CONNECT auth. = %c\n", connectauth[0]); + printf(" NO_FENCE auth. = %c\n", nofenceauth[0]); + printf(" IMPL_SCHEMA auth. = %c\n", implschemaauth[0]); + printf(" LOAD auth. = %c\n", loadauth[0]); + + return 0; +} /* DbAuthForAnyUserOrGroupDisplay */ + +int DbAuthForCurrentUserDisplay(void) +{ + struct sqlca sqlca; + + struct sql_authorizations currentUserAuthorities; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" sqluadau -- Get Authorizations\n"); + printf("TO DISPLAY CURRENT USER AUTHORITIES AT DATABASE LEVEL:\n"); + + currentUserAuthorities.sql_authorizations_len = SQL_AUTHORIZATION_SIZE; + + /* get current user authorities */ + sqluadau(¤tUserAuthorities, &sqlca); + DB2_API_CHECK("current user authorities -- get"); + + printf("\n User DBADM authority : %s\n", + authStrVal(currentUserAuthorities.sql_dbadm_auth)); + printf(" User CREATETAB authority : %s\n", + authStrVal(currentUserAuthorities.sql_createtab_auth)); + printf(" User BINDADD authority : %s\n", + authStrVal(currentUserAuthorities.sql_bindadd_auth)); + printf(" User CONNECT authority : %s\n", + authStrVal(currentUserAuthorities.sql_connect_auth)); + printf(" User CREATE_NOT_FENC authority : %s\n", + authStrVal(currentUserAuthorities.sql_create_not_fenc_auth)); + printf(" User IMPLICIT_SCHEMA authority : %s\n", + authStrVal(currentUserAuthorities.sql_implicit_schema_auth)); + printf(" User LOAD authority : %s\n", + authStrVal(currentUserAuthorities.sql_load_auth)); + + printf("\n Group DBADM authority : %s\n", + authStrVal(currentUserAuthorities.sql_dbadm_grp_auth)); + printf(" Group CREATETAB authority : %s\n", + authStrVal(currentUserAuthorities.sql_createtab_grp_auth)); + printf(" Group BINDADD authority : %s\n", + authStrVal(currentUserAuthorities.sql_bindadd_grp_auth)); + printf(" Group CONNECT authority : %s\n", + authStrVal(currentUserAuthorities.sql_connect_grp_auth)); + printf(" Group CREATE_NOT_FENC authority: %s\n", + authStrVal(currentUserAuthorities.sql_create_not_fenc_grp_auth)); + printf(" Group IMPLICIT_SCHEMA authority: %s\n", + authStrVal(currentUserAuthorities.sql_implicit_schema_grp_auth)); + printf(" Group LOAD authority : %s\n", + authStrVal(currentUserAuthorities.sql_load_grp_auth)); + + return 0; +} /* DbAuthForCurrentUserDisplay */ + +int DbAuthRevoke(void) +{ + struct sqlca sqlca; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" REVOKE (Database Authorities)\n"); + printf(" COMMIT\n"); + printf("TO REVOKE AUTHORITIES AT DATABASE LEVEL.\n"); + + /* revoke user authorities at database level */ + printf("\n REVOKE CONNECT, CREATETAB, BINDADD ON DATABASE" + " FROM USER user1\n"); + + EXEC SQL REVOKE CONNECT, CREATETAB, BINDADD ON DATABASE FROM user1; + EMB_SQL_CHECK("user authorities at db. level -- revoke"); + + printf(" COMMIT\n"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("transaction -- commit"); + + return 0; +} /* DbAuthRevoke */ + diff --git a/c/dbcfg.sqc b/c/dbcfg.sqc new file mode 100644 index 0000000..b5fdab4 --- /dev/null +++ b/c/dbcfg.sqc @@ -0,0 +1,490 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: dbcfg.sqc +** +** SAMPLE: Configure database and database manager configuration parameters +** +** This sample demonstrates the use of the db2AutoConfig() API +** which configures database and database manager configuration +** parameters. The program configures the sample database in two +** scenarios determined by specifying "1" or "2" as the multinode +** command line parameter (any other value defaults to option "1"). +** With option "1", the db2AutoConfig() API automatically configures +** the sample database. The recommendation and diagnostics are +** produced by this API and printed to standard output. By +** specifying "2" as the multinode command line parameter, the +** db2AutoConfig() API is used to generate optimized configuration +** recommendations for a database on two partitions. +** +** DB2 APIs USED: +** db2AutoConfig -- AUTOCONFIG +** db2AutoConfigFreeMemory -- AUTOCONFIG FREE MEMORY +** sqlesetc -- SET CLIENT +** sqlaintp -- SQLCA MESSAGE +** +** SQL STATEMENTS USED: +** INCLUDE +** CONNECT +** +** STRUCTURES USED: +** sqle_conn_setting +** db2AutoConfigInterface +** db2AutoConfigArray +** db2AutoConfigOutput +** db2AutoConfigValues +** sqlca +** +** OUTPUT FILE: dbcfg.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ +#include +#include +#include +#include +#include +#include "db2AuCfg.h" +#include "utilemb.h" + +#define NUMSETTINGS 3 + +#define CHCKERR(s) if (sqlca.sqlcode < 0) { print_err(&sqlca); return -1; } + +EXEC SQL INCLUDE SQLCA; + +EXEC SQL BEGIN DECLARE SECTION; + char dbName[16]; + char userid[30]; + char passwd[30]; +EXEC SQL END DECLARE SECTION; + +/* This procedure prints error information released by the APIs. */ +void print_err(struct sqlca *ca) +{ + char err[512]; + printf("________________ERROR INFO_________________________\n"); + + /* get error message */ + sqlaintp(err, sizeof(err), 80, ca); + + printf("%s\n", err); + printf("SQLCODE : %d\n", ca->sqlcode); + printf("SQLERRMC: %s\n", ca->sqlerrmc); + printf("SQLERRP : %s\n", ca->sqlerrp); + printf("_______________END ERROR INFO______________________\n"); + return; +} /* print_err */ + +/* This procedure prints diagnotic information released by the APIs. */ +int print_info(db2AutoConfigDiags * Diag) +{ + + int i = 0; + + printf("Token, Value\n"); + + while (i < (Diag->numElements)) + { + printf("%5d %6d\n", (Diag->pElements[i]).token, + (Diag->pElements[i]).value); + i++; + } + return 0; +} /* print_info */ + +/* Procedure to produce db cfg recommendations produced by the API. */ +int print_infodb(struct db2CfgParam *itemList, int num) +{ + int i = 0; + + printf("Token, Value\n"); + + while (i < num) + { + int tok = itemList[i].token; + if ( /* these are db cfg tokens */ + tok == SQLF_DBTN_BUFF_PAGE || + tok == SQLF_DBTN_CATALOGCACHE_SZ || + tok == SQLF_DBTN_DFT_DEGREE) + { + printf("%5d %6d\n", itemList[i].token, *(int *)itemList[i].ptrvalue); + } + i++; + } + return 0; +} /* print_infodb */ + +/* Procedure to produce dbm cfg recommendations produced by the API. */ +int print_infodbm(struct db2CfgParam *itemList, int num) +{ + int i = 0; + + printf("Token, Value\n"); + + while (i < num) + { + int tok = itemList[i].token; + if (/* these are dbm cfg tokens */ + tok == SQLF_KTN_NUM_POOLAGENTS || tok == SQLF_KTN_SHEAPTHRES) + { + printf("%5d %6d\n", itemList[i].token, *(int *)itemList[i].ptrvalue); + } + + if (/* these are dbm cfg tokens */ + tok == SQLF_KTN_ASLHEAPSZ) + { + printf("%5d %6d\n", itemList[i].token, *(short *)itemList[i].ptrvalue); + } + + i++; + } + return 0; +} /* print_infodbm */ + +int main(int argc, char *argv[]) +{ + struct sqle_conn_setting connSetting[NUMSETTINGS]; + SQL_API_RC rc; + struct sqlca sqlca; + db2AutoConfigInterface autoConfigInterface; + + int inputCount = 2; + + /* input to API */ + db2int32 mem_percent; /* 250 percent of server memory used on dbm */ + db2int32 workload; /* workload is mixed queries and transactions */ + + unsigned short token; + int i = autoConfigInterface.oResult.oNewDbmValues.numElements - 1; + + if (argc != 5) + { + printf("dbcfg <1|2>\n"); + return -1; + } + + strcpy(dbName, argv[1]); + strcpy(userid, argv[2]); + strcpy(passwd, argv[3]); + + printf("\nHOW TO CONFIGURE DATABASE AND DATABASE MANAGER CONFIGURATION "); + printf("PARAMETERS\n"); + + printf("\n______STARTING AUTOCONF TESTCASE ON INSTANCE " + "OWNING NODE (node 0)\n"); + + /* 1 SET CLIENT */ + + if (atoi(argv[4]) == 2) /* need to connect and attach to node if MPP */ + { + /* attach to node 0 */ + connSetting[0].type = SQL_ATTACH_NODE; + connSetting[0].value = 0; + + /* connect to node 0 */ + connSetting[1].type = SQL_CONNECT_NODE; + connSetting[1].value = 0; + + /* disconnect from node on commit (implicit when connect reset) */ + connSetting[2].type = SQL_DISCONNECT; + connSetting[2].value = SQL_DISCONNECT_AUTO; + + /* set client information */ + sqlesetc(&connSetting[0], NUMSETTINGS, &sqlca); + printf("SQLESETC instance owning node\n"); + CHCKERR("set client"); + } + + /* 2 CONNECT TO DATABASE */ + + EXEC SQL CONNECT TO:dbName USER:userid USING:passwd; + printf("______Connect\n"); + CHCKERR("connect db"); + + /* 3 ENTER PARMS INTO CONFIG API AND INTERFACE */ + + /* allocate memory for input parameters */ + + autoConfigInterface.iParams.pElements = + (db2AutoConfigElement *)malloc(sizeof(db2AutoConfigElement) * + inputCount); + + /* set up the interface for calling db2AutoConfig */ + + autoConfigInterface.iProductID = DB2_SG_PID_DEFAULT; + strcpy(autoConfigInterface.iDbAlias, dbName); + strcpy(autoConfigInterface.iProductVersion, "1.1"); + + /*** IMPORTANT: the recommendations are automatically + applied to db/dbm cfg + ***/ + autoConfigInterface.iApply = DB2_SG_APPLY; + + mem_percent = 25; + workload = 2; + + autoConfigInterface.iParams.numElements = 2; + autoConfigInterface.iParams.pElements[0].token = DB2_SG_MEMORY_PERCENTAGE; + autoConfigInterface.iParams.pElements[0].value = mem_percent; + autoConfigInterface.iParams.pElements[1].token = DB2_SG_WORKLOAD; + autoConfigInterface.iParams.pElements[1].value = workload; + + /* 4 AUTOCONFIG CALL */ + + rc = db2AutoConfig(db2Version970, &autoConfigInterface, &sqlca); + printf("______DB2AUTOCONFIG_________\n"); + CHCKERR("db2autoconfig"); + + /* 5 PRINT RECOMMENDATION AND DIAGNOSTICS */ + + if (rc == DB2_SG_RC_OK) + { + printf("NUMBER OF DIAGNOSTICS: %d\n", + autoConfigInterface.oResult.oDiagnostics.numElements); + + if (autoConfigInterface.oResult.oDiagnostics.numElements > 0) + { + /* print the diagnostic results */ + printf("==> resource values are not optimizable, " + "diagnostics produced:\n"); + + print_info(&((autoConfigInterface.oResult).oDiagnostics)); + printf("___________________\n"); + } + + if (autoConfigInterface.oResult.oOldDbValues.numElements > 0) + { + /* handle the configuration results */ + printf("==> resource values are optimizable " + "recommendations produced:\n"); + printf("==> NUMBER OF PRODUCED OLD DB CFG RECOMMENDATIONS: %d\n", + autoConfigInterface.oResult.oOldDbValues.numElements); + printf("==> PRODUCED VALUES\n"); + print_infodb(autoConfigInterface.oResult.oOldDbValues.pConfigs, + autoConfigInterface.oResult.oOldDbValues.numElements); + printf("___________________\n"); + } + + if (autoConfigInterface.oResult.oNewDbValues.numElements > 0) + { + printf("==> NUMBER OF PRODUCED NEW DB CFG RECOMMENDATIONS: %d\n", + autoConfigInterface.oResult.oNewDbValues.numElements); + printf("==> PRODUCED VALUES\n"); + print_infodb(autoConfigInterface.oResult.oNewDbValues.pConfigs, + autoConfigInterface.oResult.oNewDbValues.numElements); + printf("___________________\n"); + + } + + if (autoConfigInterface.oResult.oOldDbmValues.numElements > 0) + { + printf("==> NUMBER OF PRODUCED OLD DBM CFG RECOMMENDATIONS: %d\n", + autoConfigInterface.oResult.oOldDbmValues.numElements); + printf("==> PRODUCED VALUES\n"); + print_infodbm(autoConfigInterface.oResult.oOldDbmValues.pConfigs, + autoConfigInterface.oResult.oOldDbmValues.numElements); + printf("___________________\n"); + } + + if (autoConfigInterface.oResult.oNewDbmValues.numElements > 0) + { + printf("==> NUMBER OF PRODUCED NEW DBM CFG RECOMMENDATIONS: %d\n", + autoConfigInterface.oResult.oNewDbmValues.numElements); + printf("==> PRODUCED VALUES\n"); + print_infodbm(autoConfigInterface.oResult.oNewDbmValues.pConfigs, + autoConfigInterface.oResult.oNewDbmValues.numElements); + printf("___________________\n"); + } + + /* 6 FREE MEMORY */ + + /* must free all the memory allocated by db2AutoConfig() */ + db2AutoConfigFreeMemory(db2Version970, &autoConfigInterface, &sqlca); + } + else + { + /* handle error */ + printf("ERROR in API CALL\n"); + } + + /* disconnect from node */ + EXEC SQL CONNECT RESET; + printf("_____+CONNECT RESET\n"); + CHCKERR("connect reset"); + + /* IF 5 ARGUMENTS SPECIFIED, + TREAT AS PARTITIONED DATABASE WITH A SECOND PARTITION */ + if (atoi(argv[4]) == 2) + { + /* repeat for second partition (Node 1) */ + printf("________ OPTION 2 CONFIGURING DATABASE PARTITION RESIDING " + "ON NON INSTANCE OWNING PARTITION (node 1)\n"); + + /* 1 SET CLIENT */ + + /* attach to node 1 */ + connSetting[0].type = SQL_ATTACH_NODE; + connSetting[0].value = 1; + + /* connect to node 1 */ + connSetting[1].type = SQL_CONNECT_NODE; + connSetting[1].value = 1; + + /* disconnect from node on commit */ + connSetting[2].type = SQL_DISCONNECT; + connSetting[2].value = SQL_DISCONNECT_AUTO; + + /* set client information */ + sqlesetc(&connSetting[0], NUMSETTINGS, &sqlca); + printf("______+SQLESETC 2nd node (NODE 1)\n"); + CHCKERR("set client"); + + /* 2 CONNECT TO DATABASE */ + + EXEC SQL CONNECT TO :dbName USER :userid USING :passwd; + printf("____________++connect to db\n"); + CHCKERR("connect to db"); + + /* 3 ENTER PARMS INTO API AND INTERFACE */ + + /* input to smartguide */ + mem_percent = 45; /* percentage of memory for dbm server is 34% */ + workload = 2; /* workload is mixed with queries and transactions */ + inputCount = 2; + + /* allocate memory for input parameters */ + autoConfigInterface.iParams.pElements = + (db2AutoConfigElement *)malloc(sizeof(db2AutoConfigElement) * + inputCount); + + /* set up the interface for calling db2AutoConfig */ + autoConfigInterface.iProductID = DB2_SG_PID_DEFAULT; + strcpy(autoConfigInterface.iDbAlias, dbName); + strcpy(autoConfigInterface.iProductVersion, "1.1"); + + /*** IMPORTANT - this time the configuration parameters + *** are not automatically applied + ***/ + autoConfigInterface.iApply = DB2_SG_APPLY; + + autoConfigInterface.iParams.numElements = 2; + autoConfigInterface.iParams.pElements[0].token = + DB2_SG_MEMORY_PERCENTAGE; + autoConfigInterface.iParams.pElements[0].value = mem_percent; + autoConfigInterface.iParams.pElements[1].token = DB2_SG_WORKLOAD; + autoConfigInterface.iParams.pElements[1].value = workload; + + /* 4 AUTOCONFIG CALL */ + + rc = db2AutoConfig(db2Version970, &autoConfigInterface, &sqlca); + printf("______+DB2AUTOCONFIG_________\n"); + CHCKERR("db2 connect to sample"); + + /* 5 PRINT RECOMMENDATION AND DIAGNOSTITCS */ + + if (rc == DB2_SG_RC_OK) + { + printf("NUMBER OF DIAGNOSTICS: %d\n", + autoConfigInterface.oResult.oDiagnostics.numElements); + + if (autoConfigInterface.oResult.oDiagnostics.numElements > 0) + { + /* handle the diagnostic results */ + printf("==>resource values are not optimizable, " + "diagnostics produced: "); + print_info(&((autoConfigInterface.oResult).oDiagnostics)); + printf("___________________\n"); + } + + if (autoConfigInterface.oResult.oOldDbValues.numElements > 0) + { + /* handle the configuration results */ + printf("==> resource values are optimizable " + "recommendations produced:\n"); + printf("==> NUMBER OF PRODUCED OLD DB CFG RECOMMENDATIONS: %d\n", + autoConfigInterface.oResult.oOldDbValues.numElements); + printf("==> PRODUCED VALUES\n"); + print_infodb(autoConfigInterface.oResult.oOldDbValues.pConfigs, + autoConfigInterface.oResult.oOldDbValues.numElements); + printf("___________________\n"); + } + + if (autoConfigInterface.oResult.oNewDbValues.numElements > 0) + { + printf("==> NUMBER OF PRODUCED NEW DB CFG RECOMMENDATIONS: %d\n", + autoConfigInterface.oResult.oNewDbValues.numElements); + printf("==> PRODUCED VALUES\n"); + print_infodb(autoConfigInterface.oResult.oNewDbValues.pConfigs, + autoConfigInterface.oResult.oNewDbValues.numElements); + printf("___________________\n"); + } + + if (autoConfigInterface.oResult.oOldDbmValues.numElements > 0) + { + printf("==> NUMBER OF PRODUCED OLD DBM CFG RECOMMENDATIONS: %d\n", + autoConfigInterface.oResult.oOldDbmValues.numElements); + printf("==> PRODUCED VALUES\n"); + print_infodbm(autoConfigInterface.oResult.oOldDbmValues.pConfigs, + autoConfigInterface.oResult.oOldDbmValues.numElements); + printf("___________________\n"); + } + + if (autoConfigInterface.oResult.oNewDbmValues.numElements > 0) + { + printf("==> NUMBER OF PRODUCED NEW DBM CFG RECOMMENDATIONS: %d\n", + autoConfigInterface.oResult.oNewDbmValues.numElements); + printf("==> PRODUCED VALUES\n"); + print_infodbm(autoConfigInterface.oResult.oNewDbmValues.pConfigs, + autoConfigInterface.oResult.oNewDbmValues.numElements); + printf("___________________\n"); + } + + /* 6 FREE MEMORY */ + + /* must free all the memory allocated by db2AutoConfig() */ + db2AutoConfigFreeMemory(db2Version970, &autoConfigInterface, &sqlca); + } + else + { + /* handle error */ + printf("ERROR in API CALL\n"); + } + + /* disconnect from node */ + EXEC SQL CONNECT RESET; + printf("______CONNECT RESET\n"); + CHCKERR("connect reset"); + } + return 0; +} /* main */ + diff --git a/c/dbconn.sqc b/c/dbconn.sqc new file mode 100644 index 0000000..cff3d69 --- /dev/null +++ b/c/dbconn.sqc @@ -0,0 +1,199 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: dbconn.sqc +** +** SAMPLE: How to connect to and disconnect from a database +** +** DB2 API USED: +** db2DatabaseRestart -- RESTART DATABASE +** sqlefrce -- FORCE APPLICATION +** +** SQL STATEMENT USED: +** CONNECT +** +** OUTPUT FILE: dbconn.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +int DbConnect(char *, char *, char *); +int DbRestart(char *, char *, char *); +int DbDisconnect(void); +int AllApplicationsConnectedToAllDatabasesForceOff(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char nodeName[SQL_INSTNAME_SZ + 1]; + + EXEC SQL BEGIN DECLARE SECTION; + char dbAlias[15]; + char user[128 + 1]; + char pswd[15]; + EXEC SQL END DECLARE SECTION; + + /* check the command line arguments */ + rc = CmdLineArgsCheck3(argc, argv, dbAlias, nodeName, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO CONNECT TO/DISCONNECT FROM DATABASES."); + printf("\n"); + + rc = DbConnect(dbAlias, user, pswd); + rc = DbRestart(dbAlias, user, pswd); + rc = DbDisconnect(); + + /* attach to a local or remote instance */ + rc = InstanceAttach(nodeName, user, pswd); + if (rc != 0) + { + return rc; + } + + /* The next function will disconnect all the applications from all */ + /* the databases located in the instance you are attached to. */ + /* Uncomment the next function if this is acceptable. */ + + /* rc = AllApplicationsConnectedToAllDatabasesForceOff(); */ + + /* detach from the local or remote instance */ + rc = InstanceDetach(nodeName); + if (rc != 0) + { + return rc; + } + + return rc; +} /* end main */ + +int DbConnect(char dbAlias[], char user[], char pswd[]) +{ + struct sqlca sqlca; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENT:\n"); + printf(" CONNECT TO\n"); + printf("TO CONNECT TO A DATABASE.\n"); + + /* connect to a database */ + printf("\n Execute the statement\n"); + printf(" CONNECT TO %s\n", dbAlias); + if (strlen(user) > 0) + { + EXEC SQL CONNECT TO :dbAlias USER :user USING :pswd; + EMB_SQL_CHECK("database -- connect with userid and password"); + } + else + { + + EXEC SQL CONNECT TO :dbAlias; + EMB_SQL_CHECK("Database -- Connect"); + } + + return 0; +} /* DbConnect */ + +int DbRestart(char dbAlias[], char user[], char pswd[]) +{ + struct sqlca sqlca; + struct db2RestartDbStruct dbRestartParam; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" db2DatabaseRestart -- RESTART DATABASE\n"); + printf("TO RESTART A DATABASE.\n"); + + /* restart a database */ + dbRestartParam.piDatabaseName = dbAlias; + dbRestartParam.piUserId = user; + dbRestartParam.piPassword = pswd; + dbRestartParam.piTablespaceNames = NULL; + printf("\n Restart a database.\n"); + printf(" database alias: %s\n", dbAlias); + + /* restart database */ + db2DatabaseRestart(db2Version970, &dbRestartParam, &sqlca); + DB2_API_CHECK("Database -- Restart"); + + return 0; +} /* DbRestart */ + +int DbDisconnect(void) +{ + struct sqlca sqlca; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENT:\n"); + printf(" CONNECT RESET"); + printf("\nTO DISCONNECT FROM THE CURRENT DATABASE.\n"); + + /* disconnect from the database */ + printf("\n Execute the statement\n"); + printf(" CONNECT RESET\n"); + + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("Database -- Disconnect"); + + return 0; +} /* DbDisconnect */ + +int AllApplicationsConnectedToAllDatabasesForceOff(void) +{ + struct sqlca sqlca; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" sqlefrce -- FORCE APPLICATION\n"); + printf("TO FORCE OFF ALL THE APPLICATIONS CONNECTED TO ALL DATABASES.\n"); + + /* force off all the appl. connected to all databases */ + printf("\n Force off all applications connected to all databases.\n"); + + /* force application */ + sqlefrce(SQL_ALL_USERS, NULL, SQL_ASYNCH, &sqlca); + DB2_API_CHECK("DBM Config. -- Set"); + + return 0; +} /* AllApplicationsConnectedToAllDatabasesForceOff */ + diff --git a/c/dbcreate.c b/c/dbcreate.c new file mode 100644 index 0000000..bd08264 --- /dev/null +++ b/c/dbcreate.c @@ -0,0 +1,169 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: dbcreate.c +** +** SAMPLE: Create and drop databases +** +** DB2 APIs USED: +** sqlecrea -- CREATE DATABASE +** sqledrpd -- DROP DATABASE +** � +** STRUCTURES USED: +** sqlca +** SQLEDBTERRITORYINFO +** sqledbdesc +** +** OUTPUT FILE: dbcreate.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilapi.h" + +int DbCreate(void); +int DbDrop(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char nodeName[SQL_INSTNAME_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck2(argc, argv, nodeName, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO CREATE/DROP A DATABASE.\n"); + + /* attach to a local or remote instance */ + rc = InstanceAttach(nodeName, user, pswd); + if (rc != 0) + { + return rc; + } + + rc = DbCreate(); + rc = DbDrop(); + + /* detach from the local or remote instance */ + rc = InstanceDetach(nodeName); + if (rc != 0) + { + return rc; + } + + return 0; +} /* main */ + +int DbCreate(void) +{ + struct sqlca sqlca; + char dbName[SQL_DBNAME_SZ + 1]; + char dbLocalAlias[SQL_ALIAS_SZ + 1]; + char dbPath[SQL_PATH_SZ + 1]; + struct sqledbdesc dbDescriptor; + SQLEDBTERRITORYINFO territoryInfo; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" sqlecrea -- CREATE DATABASE\n"); + printf("TO CREATE A NEW DATABASE:\n"); + + /* create a new database */ + strcpy(dbName, "dbcreate"); + strcpy(dbLocalAlias, "dbcreate"); + strcpy(dbPath, ""); + + strcpy(dbDescriptor.sqldbdid, SQLE_DBDESC_2); + dbDescriptor.sqldbccp = 0; + dbDescriptor.sqldbcss = SQL_CS_USER; + memcpy(dbDescriptor.sqldbudc, sqle_819_500, SQL_CS_SZ); + strcpy(dbDescriptor.sqldbcmt, "comment for database"); + dbDescriptor.sqldbsgp = 0; + dbDescriptor.sqldbnsg = 10; + dbDescriptor.sqltsext = -1; + dbDescriptor.sqlcatts = NULL; + dbDescriptor.sqlusrts = NULL; + dbDescriptor.sqltmpts = NULL; + + strcpy(territoryInfo.sqldbcodeset, "ISO8859-1"); + strcpy(territoryInfo.sqldblocale, "C"); + + printf("\n Create a [remote] database and catalog it locally:\n"); + printf(" database name : %s\n", dbName); + printf(" local database alias: %s\n", dbLocalAlias); + + /* create database */ + sqlecrea(dbName, + dbLocalAlias, + dbPath, + &dbDescriptor, + &territoryInfo, + '\0', + NULL, + &sqlca); + DB2_API_CHECK("Database -- Create"); + + return 0; +} /* DbCreate */ + +int DbDrop(void) +{ + struct sqlca sqlca; + char dbLocalAlias[SQL_ALIAS_SZ + 1]; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" sqledrpd -- DROP DATABASE\n"); + printf("TO DROP A DATABASE:\n"); + + /* drop a database */ + strcpy(dbLocalAlias, "dbcreate"); + printf("\n Drop a [remote] database and uncatalog it locally.\n"); + printf(" local database alias: %s\n", dbLocalAlias); + + /* drop database */ + sqledrpd(dbLocalAlias, &sqlca); + DB2_API_CHECK("Database -- Drop"); + + return 0; +} /* DbDrop */ + diff --git a/c/dbhistfile.sqc b/c/dbhistfile.sqc new file mode 100644 index 0000000..143a9b7 --- /dev/null +++ b/c/dbhistfile.sqc @@ -0,0 +1,550 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: dbhistfile.sqc +** +** SAMPLE: How to read and update a database recovery history file entry. +** +** This program ends in ".sqc" even though it does not contain +** embedded SQL statements. It links in the embedded SQL utility +** file for database connection and disconnection, so it needs the +** embedded SQL extension for the precompiler. +** +** DB2 APIs USED: +** db2HistoryCloseScan -- Close Recovery History File Scan +** db2HistoryGetEntry -- Get Next Recovery History File Entry +** db2HistoryOpenScan -- Open Recovery History File Scan +** db2HistoryUpdate -- Update Recovery History File +** +** OUTPUT FILE: dbhistfile.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ +#include "utilrecov.c" + +/* local function prototypes */ +int DbRecoveryHistoryFileRead(char *); +int DbFirstRecoveryHistoryFileEntryUpdate(char *, char *, char *); +int HistoryEntryDataFieldsAlloc(struct db2HistoryData *, struct db2HistoryOpenStruct *); +int HistoryEntryDisplay(struct db2HistoryData ); +int HistoryEntryDataFieldsFree(struct db2HistoryData *); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char nodeName[SQL_INSTNAME_SZ + 1] = { 0 }; + char serverWorkingPath[SQL_PATH_SZ + 1] = { 0 }; + char dbAlias[SQL_ALIAS_SZ + 1] = { 0 }; + char user[USERID_SZ + 1] = { 0 }; + char pswd[PSWD_SZ + 1] = { 0 }; + + /* check the command line arguments */ + rc = CmdLineArgsCheck3(argc, argv, dbAlias, nodeName, user, pswd); + CHECKRC(rc, "CmdLineArgsCheck3"); + + printf("\nTHIS SAMPLE SHOWS HOW TO READ A DATABASE RECOVERY HISTORY FILE \n"); + printf("AND UPDATE A RECOVERY HISTORY FILE ENTRY. \n"); + + /* attach to a local or remote instance */ + rc = InstanceAttach(nodeName, user, pswd); + CHECKRC(rc, "Instance Attach"); + + /* get the server working path */ + rc = ServerWorkingPathGet(dbAlias, serverWorkingPath); + CHECKRC(rc, "ServerWorkingPathGet"); + + rc = DbRecoveryHistoryFileRead(dbAlias); + CHECKRC(rc, "DbRecoveryHistoryFileRead"); + + rc = DbFirstRecoveryHistoryFileEntryUpdate(dbAlias, user, pswd); + CHECKRC(rc, "DbFirstRecoveryHistoryFileEntryUpdate"); + + /* Detach from the local or remote instance */ + rc = InstanceDetach(nodeName); + CHECKRC(rc, "InstanceDetach"); + + return 0; +} /* end main */ + +int DbRecoveryHistoryFileRead(char dbAlias[]) +{ + int rc = 0; + struct sqlca sqlca = { 0 }; + struct db2HistoryOpenStruct dbHistoryOpenParam = { 0 }; + sqluint32 numEntries = 0; + sqluint16 recoveryHistoryFileHandle = 0; + sqluint32 entryNb = 0; + struct db2HistoryGetEntryStruct dbHistoryEntryGetParam = { 0 }; + struct db2HistoryData histEntryData = { 0 }; + + printf("\n*********************************************\n"); + printf("*** READ A DATABASE RECOVERY HISTORY FILE ***\n"); + printf("*********************************************\n"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" db2HistoryOpenScan -- Open Recovery History File Scan\n"); + printf(" db2HistoryGetEntry -- Get Next Recovery History File Entry\n"); + printf(" db2HistoryCloseScan -- Close Recovery History File Scan\n"); + printf("TO READ A DATABASE RECOVERY HISTORY FILE.\n"); + + /* initialize the data structures */ + dbHistoryOpenParam.piDatabaseAlias = dbAlias; + dbHistoryOpenParam.piTimestamp = NULL; + dbHistoryOpenParam.piObjectName = NULL; + dbHistoryOpenParam.iCallerAction = DB2HISTORY_LIST_HISTORY; + + dbHistoryEntryGetParam.pioHistData = &histEntryData; + dbHistoryEntryGetParam.iCallerAction = DB2HISTORY_GET_ALL; + printf("\n Open recovery history file for '%s' database.\n", dbAlias); + + /*******************************************/ + /* OPEN THE DATABASE RECOVERY HISTORY FILE */ + /*******************************************/ + + /* open the recovery history file to scan */ + db2HistoryOpenScan(db2Version980, &dbHistoryOpenParam, &sqlca); + DB2_API_CHECK("database recovery history file -- open"); + numEntries = dbHistoryOpenParam.oNumRows; + + /* dbHistoryOpenParam.oHandle returns the handle for scan access */ + recoveryHistoryFileHandle = dbHistoryOpenParam.oHandle; + dbHistoryEntryGetParam.iHandle = recoveryHistoryFileHandle; + + rc = HistoryEntryDataFieldsAlloc(&histEntryData, &dbHistoryOpenParam); + CHECKRC(rc, "HistoryEntryDataFieldsAlloc"); + + + /**********************************************/ + /* READ AN ENTRY IN THE RECOVERY HISTORY FILE */ + /**********************************************/ + for (entryNb = 0; entryNb < numEntries; entryNb++) + { + printf("\n Read entry number %u.\n", entryNb); + + /* get the next entry from the recovery history file */ + db2HistoryGetEntry(db2Version980, &dbHistoryEntryGetParam, &sqlca); + DB2_API_CHECK("database recovery history file entry -- read") + + /* display the entries in the recovery history file */ + printf("\n Display entry number %u.\n", entryNb); + rc = HistoryEntryDisplay(histEntryData); + CHECKRC(rc, "HistoryEntryDisplay"); + } + + /********************************************/ + /* CLOSE THE DATABASE RECOVERY HISTORY FILE */ + /********************************************/ + printf("\n Close recovery history file for '%s' database.\n", dbAlias); + + /* The API db2HistoryCloseScan ends the recovery history file scan and + frees DB2 resources required for the scan. */ + db2HistoryCloseScan(db2Version980, &recoveryHistoryFileHandle, &sqlca); + DB2_API_CHECK("database recovery history file -- close"); + + /* free the allocated memory */ + rc = HistoryEntryDataFieldsFree(&histEntryData); + CHECKRC(rc, "HistoryEntryDataFieldsFree"); + + return 0; +} /* DbRecoveryHistoryFileRead */ + +int DbFirstRecoveryHistoryFileEntryUpdate(char dbAlias[], char user[], + char pswd[]) +{ + int rc = 0; + struct sqlca sqlca = { 0 }; + struct db2HistoryOpenStruct dbHistoryOpenParam = { 0 }; + sqluint16 recoveryHistoryFileHandle = 0; + struct db2HistoryGetEntryStruct dbHistoryEntryGetParam = { 0 }; + struct db2HistoryData histEntryData = { 0 }; + char newLocation[DB2HISTORY_LOCATION_SZ + 1] = { 0 }; + char newComment[DB2HISTORY_COMMENT_SZ + 1] = { 0 }; + struct db2HistoryUpdateStruct dbHistoryUpdateParam = { 0 }; + + printf("\n*****************************************************\n"); + printf("*** UPDATE A DATABASE RECOVERY HISTORY FILE ENTRY ***\n"); + printf("*****************************************************\n"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" db2HistoryOpenScan -- Open Recovery History File Scan\n"); + printf(" db2HistoryGetEntry -- Get Next Recovery History File Entry\n"); + printf(" db2HistoryUpdate -- Update Recovery History File\n"); + printf(" db2HistoryCloseScan -- Close Recovery History File Scan\n"); + printf("TO UPDATE A DATABASE RECOVERY HISTORY FILE ENTRY.\n"); + + /* initialize data structures */ + dbHistoryOpenParam.piDatabaseAlias = dbAlias; + dbHistoryOpenParam.piTimestamp = NULL; + dbHistoryOpenParam.piObjectName = NULL; + dbHistoryOpenParam.iCallerAction = DB2HISTORY_LIST_HISTORY; + + dbHistoryEntryGetParam.pioHistData = &histEntryData; + dbHistoryEntryGetParam.iCallerAction = DB2HISTORY_GET_ALL; + + /*******************************************/ + /* OPEN THE DATABASE RECOVERY HISTORY FILE */ + /*******************************************/ + printf("\n Open the recovery history file for '%s' database.\n", + dbAlias); + + /* The API db2HistoryOpenScan starts a recovery history file scan */ + db2HistoryOpenScan(db2Version980, &dbHistoryOpenParam, &sqlca); + DB2_API_CHECK("database recovery history file -- open"); + + /* dbHistoryOpenParam.oHandle returns the handle for scan access */ + recoveryHistoryFileHandle = dbHistoryOpenParam.oHandle; + dbHistoryEntryGetParam.iHandle = recoveryHistoryFileHandle; + + rc = HistoryEntryDataFieldsAlloc(&histEntryData, &dbHistoryOpenParam); + CHECKRC(rc, "HistoryEntryDataFieldsAlloc"); + + /*****************************************************/ + /* READ THE FIRST ENTRY IN THE RECOVERY HISTORY FILE */ + /*****************************************************/ + printf("\n Read the first entry in the recovery history file.\n"); + + /* The API db2HistoryGetEntry gets the next entry from the recovery + history file. */ + db2HistoryGetEntry(db2Version980, &dbHistoryEntryGetParam, &sqlca); + DB2_API_CHECK("first recovery history file entry -- read"); + /* check if the recovery history file is empty */ + if (sqlca.sqlcode == SQLE_RC_NOMORE) + { + printf(" The History File is Empty!\n"); + printf(" No data to return.\n\n"); + return 1; + } + + printf("\n Display the first entry.\n"); + + /* HistoryEntryDisplay is a support function used to display the entries + in the recovery history file. */ + rc = HistoryEntryDisplay(histEntryData); + CHECKRC(rc, "HistoryEntryDisplay"); + + /* update the first history file entry */ + rc = DbConn(dbAlias, user, pswd); + CHECKRC(rc, "DbConn"); + + strcpy(newLocation, "this is the NEW LOCATION"); + strcpy(newComment, "this is the NEW COMMENT"); + printf("\n Update the first entry in the history file:\n"); + printf(" new location = '%s'\n", newLocation); + printf(" new comment = '%s'\n", newComment); + + dbHistoryUpdateParam.piNewLocation = newLocation; + dbHistoryUpdateParam.piNewDeviceType = NULL; + dbHistoryUpdateParam.piNewComment = newComment; + dbHistoryUpdateParam.iEID.ioNode = histEntryData.oEID.ioNode; + dbHistoryUpdateParam.iEID.ioHID = histEntryData.oEID.ioHID; + + /* The API db2HistoryUpdate can be used to update the location, + device type, or comment in a history file entry. */ + + /* Call this API to update the location and comment of the first + entry in the history file: */ + db2HistoryUpdate(db2Version980, &dbHistoryUpdateParam, &sqlca); + DB2_API_CHECK("first history file entry -- update"); + + rc = DbDisconn(dbAlias); + CHECKRC(rc, "DbDisconn"); + + /********************************************/ + /* CLOSE THE DATABASE RECOVERY HISTORY FILE */ + /********************************************/ + printf("\n Close recovery history file for '%s' database.\n", dbAlias); + + /* The API db2HistoryCloseScan ends the recovery history file scan and + frees DB2 resources required for the scan. */ + db2HistoryCloseScan(db2Version980, &recoveryHistoryFileHandle, &sqlca); + DB2_API_CHECK("database recovery history file -- close"); + + /**********************************************/ + /* RE-OPEN THE DATABASE RECOVERY HISTORY FILE */ + /**********************************************/ + printf("\n Open the recovery history file for '%s' database.\n", + dbAlias); + + /* starts a recovery history file scan */ + db2HistoryOpenScan(db2Version980, &dbHistoryOpenParam, &sqlca); + DB2_API_CHECK("database recovery history file -- open"); + + recoveryHistoryFileHandle = dbHistoryOpenParam.oHandle; + dbHistoryEntryGetParam.iHandle = recoveryHistoryFileHandle; + printf("\n Read the first recovery history file entry.\n"); + + /************************************************************************/ + /* READ THE FIRST ENTRY IN THE RECOVERY HISTORY FILE AFTER MODIFICATION */ + /************************************************************************/ + db2HistoryGetEntry(db2Version980, &dbHistoryEntryGetParam, &sqlca); + DB2_API_CHECK("first recovery history file entry -- read"); + + printf("\n Display the first entry.\n"); + rc = HistoryEntryDisplay(histEntryData); + CHECKRC(rc, "HistoryEntryDisplay"); + + /********************************************/ + /* CLOSE THE DATABASE RECOVERY HISTORY FILE */ + /********************************************/ + printf("\n Close the recovery history file for '%s' database.\n", + dbAlias); + + /* ends the recovery history file scan */ + db2HistoryCloseScan(db2Version980, &recoveryHistoryFileHandle, &sqlca); + DB2_API_CHECK("database recovery history file -- close"); + + /* free the allocated memory */ + rc = HistoryEntryDataFieldsFree(&histEntryData); + CHECKRC(rc, "HistoryEntryDataFieldsFree"); + + return 0; +} /* DbFirstRecoveryHistoryFileEntryUpdate */ + +/***************************************************************************/ +/* HistoryEntryDataFieldsAlloc */ +/* Allocates memory for all the fields in a database recovery history */ +/* file entry */ +/***************************************************************************/ +int HistoryEntryDataFieldsAlloc(struct db2HistoryData *pHistEntryData, struct db2HistoryOpenStruct *pHistOpenParam) +{ + int rc = 0; + sqluint32 tsNb = 0; + + strcpy(pHistEntryData->ioHistDataID, "SQLUHINF"); + + pHistEntryData->oObjectPart.pioData = malloc(DB2HISTORY_OBJPART_SZ + 1); + pHistEntryData->oObjectPart.iLength = DB2HISTORY_OBJPART_SZ + 1; + + pHistEntryData->oEndTime.pioData = malloc(DB2HISTORY_TIMESTAMP_SZ + 1); + pHistEntryData->oEndTime.iLength = DB2HISTORY_TIMESTAMP_SZ + 1; + + pHistEntryData->ioLogRange.oStream = malloc(pHistOpenParam->oMaxLogStreams * sizeof(db2HistoryLogStreamRange)); + pHistEntryData->ioLogRange.iNumLogStreams = pHistOpenParam->oMaxLogStreams; + + pHistEntryData->oID.pioData = malloc(DB2HISTORY_ID_SZ + 1); + pHistEntryData->oID.iLength = DB2HISTORY_ID_SZ + 1; + + pHistEntryData->oTableQualifier.pioData = + malloc(DB2HISTORY_TABLE_QUAL_SZ + 1); + pHistEntryData->oTableQualifier.iLength = DB2HISTORY_TABLE_QUAL_SZ + 1; + + pHistEntryData->oTableName.pioData = malloc(DB2HISTORY_TABLE_NAME_SZ + 1); + pHistEntryData->oTableName.iLength = DB2HISTORY_TABLE_NAME_SZ + 1; + + pHistEntryData->oLocation.pioData = malloc(DB2HISTORY_LOCATION_SZ + 1); + pHistEntryData->oLocation.iLength = DB2HISTORY_LOCATION_SZ + 1; + + pHistEntryData->oComment.pioData = malloc(DB2HISTORY_COMMENT_SZ + 1); + pHistEntryData->oComment.iLength = DB2HISTORY_COMMENT_SZ + 1; + + pHistEntryData->oCommandText.pioData = malloc(DB2HISTORY_COMMAND_SZ + 1); + pHistEntryData->oCommandText.iLength = DB2HISTORY_COMMAND_SZ + 1; + + pHistEntryData->poEventSQLCA = + (struct sqlca *)malloc(sizeof(struct sqlca)); + + pHistEntryData->poTablespace = (db2Char *) malloc(10 * sizeof(db2Char)); + for (tsNb = 0; tsNb < 10; tsNb++) + { + pHistEntryData->poTablespace[tsNb].pioData = malloc(18 + 1); + pHistEntryData->poTablespace[tsNb].iLength = 18 + 1; + } + + pHistEntryData->iNumTablespaces = 10; + + return 0; +} /* HistoryEntryDataFieldsAlloc */ + +/***************************************************************************/ +/* HistoryEntryDisplay */ +/* Displays the fields of an entry in the database recovery history file */ +/***************************************************************************/ +int HistoryEntryDisplay(struct db2HistoryData histEntryData) +{ + int rc = 0; + int bufLen = 0; + char *buf = NULL; + sqluint32 tsNb = 0; + + bufLen = + MIN(histEntryData.oObjectPart.oLength, + histEntryData.oObjectPart.iLength); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.oObjectPart.pioData, bufLen); + buf[bufLen] = '\0'; + printf(" object part: %s\n", buf); + free(buf); + + bufLen = + MIN(histEntryData.oEndTime.oLength, histEntryData.oEndTime.iLength); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.oEndTime.pioData, bufLen); + buf[bufLen] = '\0'; + printf(" end time: %s\n", buf); + free(buf); + + bufLen = + MIN(histEntryData.ioLogRange.oNumLogStreams, histEntryData.ioLogRange.iNumLogStreams); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.ioLogRange.oStream, bufLen); + buf[bufLen] = '\0'; + printf(" log range: %s\n", buf); + free(buf); + + bufLen = MIN(histEntryData.oID.oLength, histEntryData.oID.iLength); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.oID.pioData, bufLen); + buf[bufLen] = '\0'; + printf(" ID: %s\n", buf); + free(buf); + + bufLen = + MIN(histEntryData.oTableQualifier.oLength, + histEntryData.oTableQualifier.iLength); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.oTableQualifier.pioData, bufLen); + buf[bufLen] = '\0'; + printf(" table qualifier: %s\n", buf); + free(buf); + + bufLen = + MIN(histEntryData.oTableName.oLength, histEntryData.oTableName.iLength); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.oTableName.pioData, bufLen); + buf[bufLen] = '\0'; + printf(" table name: %s\n", buf); + free(buf); + + bufLen = + MIN(histEntryData.oLocation.oLength, histEntryData.oLocation.iLength); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.oLocation.pioData, bufLen); + buf[bufLen] = '\0'; + printf(" location: %s\n", buf); + free(buf); + + bufLen = + MIN(histEntryData.oComment.oLength, histEntryData.oComment.iLength); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.oComment.pioData, bufLen); + buf[bufLen] = '\0'; + printf(" comment: %s\n", buf); + free(buf); + + bufLen = + MIN(histEntryData.oCommandText.oLength, + histEntryData.oCommandText.iLength); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.oCommandText.pioData, bufLen); + buf[bufLen] = '\0'; + printf(" command text: %s\n", buf); + printf(" history file entry ID: %u\n", histEntryData.oEID.ioHID); + printf(" table spaces:\n"); + free(buf); + + for (tsNb = 0; tsNb < histEntryData.oNumTablespaces; tsNb++) + { + bufLen = + MIN(histEntryData.poTablespace[tsNb].oLength, + histEntryData.poTablespace[tsNb].iLength); + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.poTablespace[tsNb].pioData, bufLen); + buf[bufLen] = '\0'; + printf(" %s\n", buf); + free(buf); + } + + printf(" oLastLSN: %d\n", histEntryData.oLastLSN); + printf(" type of operation: %c\n", histEntryData.oOperation); + printf(" granularity of the operation: %c\n", histEntryData.oObject); + printf(" operation type: %c\n", histEntryData.oOptype); + printf(" entry status: %c\n", histEntryData.oStatus); + printf(" device type: %c\n", histEntryData.oDeviceType); + printf(" SQLCA:\n"); + printf(" sqlcode: %ld\n", histEntryData.poEventSQLCA->sqlcode); + + bufLen = SQLUDF_SQLSTATE_LEN; + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.poEventSQLCA->sqlstate, bufLen); + buf[bufLen] = '\0'; + printf(" sqlstate: %s\n", buf); + free(buf); + + bufLen = histEntryData.poEventSQLCA->sqlerrml; + buf = malloc(bufLen + 1); + memcpy(buf, histEntryData.poEventSQLCA->sqlerrmc, bufLen); + buf[bufLen] = '\0'; + printf(" message: %s\n", buf); + free(buf); + + return 0; +} /* HistoryEntryDisplay */ + +/***************************************************************************/ +/* HistoryEntryDataFieldsFree */ +/* Deallocates the memory for database recovery history file structures */ +/***************************************************************************/ +int HistoryEntryDataFieldsFree(struct db2HistoryData *pHistEntryData) +{ + int rc = 0; + sqluint32 tsNb = 0; + + free(pHistEntryData->oObjectPart.pioData); + free(pHistEntryData->oEndTime.pioData); + free(pHistEntryData->ioLogRange.oStream); + free(pHistEntryData->oID.pioData); + free(pHistEntryData->oTableQualifier.pioData); + free(pHistEntryData->oTableName.pioData); + free(pHistEntryData->oLocation.pioData); + free(pHistEntryData->oComment.pioData); + free(pHistEntryData->oCommandText.pioData); + free(pHistEntryData->poEventSQLCA); + pHistEntryData->oObjectPart.pioData = NULL; + pHistEntryData->oEndTime.pioData = NULL; + pHistEntryData->ioLogRange.oStream = NULL; + pHistEntryData->oID.pioData = NULL; + pHistEntryData->oTableQualifier.pioData = NULL; + pHistEntryData->oTableName.pioData = NULL; + pHistEntryData->oLocation.pioData = NULL; + pHistEntryData->oComment.pioData = NULL; + pHistEntryData->oCommandText.pioData = NULL; + pHistEntryData->poEventSQLCA = NULL; + + for (tsNb = 0; tsNb < 10; tsNb++) + { + free(pHistEntryData->poTablespace[tsNb].pioData); + pHistEntryData->poTablespace[tsNb].pioData = NULL; + } + + free(pHistEntryData->poTablespace); + pHistEntryData->poTablespace = NULL; + + return 0; +} /* HistoryEntryDataFieldsFree */ diff --git a/c/dbinfo.c b/c/dbinfo.c new file mode 100644 index 0000000..2115043 --- /dev/null +++ b/c/dbinfo.c @@ -0,0 +1,281 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: dbinfo.c +** +** SAMPLE: Set and get information at the database level +** +** DB2 API USED: +** db2CfgGet -- Get Configuration +** db2CfgSet -- Set Configuration + +** STRUCTURES USED: +** sqlca +** +** OUTPUT FILE: dbinfo.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilapi.h" + +int LocalOrRemoteDbConfigSetGet(char *); +int LocalOrRemoteDbConfigDefaultsSetGet(char *); + +/* support functions */ +int LocalOrRemoteDbConfigSave(db2Cfg); +int LocalOrRemoteDbConfigRestore(db2Cfg); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char nodeName[SQL_INSTNAME_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + db2CfgParam cfgParameters[2]; /* to save the DB Config. */ + db2Cfg cfgStruct; + + /* check the command line arguments */ + rc = CmdLineArgsCheck3(argc, argv, dbAlias, nodeName, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO SET/GET INFO AT DATABASE LEVEL.\n"); + + /* attach to a local or remote instance */ + rc = InstanceAttach(nodeName, user, pswd); + if (rc != 0) + { + return rc; + } + + /* initialize cfgStruct */ + cfgStruct.numItems = 2; + cfgStruct.paramArray = cfgParameters; + cfgStruct.flags = db2CfgDatabase | db2CfgDelayed; + cfgStruct.dbname = dbAlias; + + /* save DB. Config. */ + rc = LocalOrRemoteDbConfigSave(cfgStruct); + + if (rc != 0) + { + return rc; + } + + /* work with DB. Config. */ + rc = LocalOrRemoteDbConfigSetGet(dbAlias); + rc = LocalOrRemoteDbConfigDefaultsSetGet(dbAlias); + + /* restore DB Config. */ + rc = LocalOrRemoteDbConfigRestore(cfgStruct); + + /* detach from the local or remote instance */ + rc = InstanceDetach(nodeName); + if (rc != 0) + { + return rc; + } + + return 0; +} /* end main */ + +int LocalOrRemoteDbConfigSave(db2Cfg cfgStruct) +{ + struct sqlca sqlca; + + /* initialize paramArray */ + cfgStruct.paramArray[0].flags = 0; + cfgStruct.paramArray[0].token = SQLF_DBTN_TSM_OWNER; + cfgStruct.paramArray[0].ptrvalue = (char *)malloc(sizeof(char) * 65); + cfgStruct.paramArray[1].flags = 0; + cfgStruct.paramArray[1].token = SQLF_DBTN_MAXAPPLS; + cfgStruct.paramArray[1].ptrvalue = (char *)malloc(sizeof(sqluint16)); + + printf("\n**** SAVE DB CONFIG. FOR: %s ****\n", cfgStruct.dbname); + + /* get database configuration */ + db2CfgGet(db2Version970, (void *)&cfgStruct, &sqlca); + DB2_API_CHECK("DB Config. -- Save"); + + return 0; +} /* LocalOrRemoteDbConfigSave */ + +int LocalOrRemoteDbConfigRestore(db2Cfg cfgStruct) +{ + struct sqlca sqlca; + + printf("\n*** RESTORE DB CONFIG. FOR: %s ***\n", cfgStruct.dbname); + + /* update database configuration */ + db2CfgSet(db2Version970, (void *)&cfgStruct, &sqlca); + DB2_API_CHECK("DB Config. -- Restore"); + + free(cfgStruct.paramArray[0].ptrvalue); + free(cfgStruct.paramArray[1].ptrvalue); + + return 0; +} /* LocalOrRemoteDbConfigRestore */ + +int LocalOrRemoteDbConfigSetGet(char *dbAlias) +{ + struct sqlca sqlca; + db2CfgParam cfgParameters[2]; + db2Cfg cfgStruct; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" db2CfgGet -- GET CONFIGURATION\n"); + printf(" db2CfgSet -- SET CONFIGURATION\n"); + printf("TO SET/GET DATABASE CONFIGURATION PARAMETERS:\n"); + + /* initialize cfgParameters */ + cfgParameters[0].flags = 0; + cfgParameters[0].token = SQLF_DBTN_TSM_OWNER; + cfgParameters[0].ptrvalue = (char *)malloc(sizeof(char) * 65); + cfgParameters[1].flags = 0; + cfgParameters[1].token = SQLF_DBTN_MAXAPPLS; + cfgParameters[1].ptrvalue = (char *)malloc(sizeof(sqluint16)); + + /* set two DB Config. fields */ + strcpy(cfgParameters[0].ptrvalue, "tsm_owner"); + *(sqluint16 *)(cfgParameters[1].ptrvalue) = 50; + printf("\n Set the DB Config. fields for the \"%s\" database:\n", + dbAlias); + printf(" TSM owner = %s\n", cfgParameters[0].ptrvalue); + printf(" maxappls = %u\n", + *(sqluint16 *)(cfgParameters[1].ptrvalue)); + + /* initialize cfgStruct */ + cfgStruct.numItems = 2; + cfgStruct.paramArray = cfgParameters; + cfgStruct.flags = db2CfgDatabase | db2CfgDelayed; + cfgStruct.dbname = dbAlias; + + /* set database configuration */ + db2CfgSet(db2Version970, (void *)&cfgStruct, &sqlca); + DB2_API_CHECK("DB Config. -- Set"); + + /* get two DB Configuration parameters */ + strcpy(cfgParameters[0].ptrvalue, ""); + *(sqluint16 *)(cfgParameters[1].ptrvalue) = 0; + + printf(" Get two DB Config. fields for the \"%s\" database:\n", + dbAlias); + + /* get database configuration */ + db2CfgGet(db2Version970, (void *)&cfgStruct, &sqlca); + DB2_API_CHECK("DB Config. -- Get"); + + printf(" TSM owner = %s\n", cfgParameters[0].ptrvalue); + printf(" maxappls = %u\n", + *(sqluint16 *)(cfgParameters[1].ptrvalue)); + + /* free the memory allocated */ + free(cfgParameters[0].ptrvalue); + free(cfgParameters[1].ptrvalue); + + return 0; +} /* LocalOrRemoteDbConfigSetGet */ + +int LocalOrRemoteDbConfigDefaultsSetGet(char *dbAlias) +{ + struct sqlca sqlca; + db2CfgParam cfgParameters[2]; + db2Cfg cfgStruct; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" db2CfgSet -- SET CONFIGURATION\n"); + printf(" db2CfgGet -- GET CONFIGURATION\n"); + printf("TO SET/GET DATABASE CONFIGURATION DEFAULTS:\n"); + + /* initialize cfgParameters */ + cfgParameters[0].flags = 0; + cfgParameters[0].token = SQLF_DBTN_TSM_OWNER; + cfgParameters[0].ptrvalue = (char *)malloc(sizeof(char) * 65); + cfgParameters[1].flags = 0; + cfgParameters[1].token = SQLF_DBTN_MAXAPPLS; + cfgParameters[1].ptrvalue = (char *)malloc(sizeof(sqluint16)); + + /* set all DB Config. defaults */ + printf("\n Set all database configuration defaults"); + printf(" for the \"%s\" database.\n", dbAlias); + + + /* set cfgStruct */ + cfgStruct.numItems = 0; + cfgStruct.paramArray = NULL; + cfgStruct.flags = db2CfgDatabase | db2CfgReset | db2CfgDelayed; + cfgStruct.dbname = dbAlias; + + /* reset database configuration */ + db2CfgSet(db2Version970, (void *)&cfgStruct, &sqlca); + DB2_API_CHECK("DB Config. defaults -- Set"); + + /* get two DB Configuration defaults */ + strcpy(cfgParameters[0].ptrvalue, ""); + *(sqluint16 *)(cfgParameters[1].ptrvalue) = 0; + + printf(" Get two database configuration defaults"); + printf(" for the \"%s\" database:\n", dbAlias); + + /* set cfgStruct */ + cfgStruct.numItems = 2; + cfgStruct.paramArray = cfgParameters; + cfgStruct.flags = db2CfgDatabase | db2CfgGetDefaults; + cfgStruct.dbname = dbAlias; + + /* get database configuration defaults */ + db2CfgGet(db2Version970, (void *)&cfgStruct, &sqlca); + DB2_API_CHECK("DB Config. Defaults -- Get"); + + printf(" TSM owner = %s\n", cfgParameters[0].ptrvalue); + printf(" maxappls = %u\n", + *(sqluint16 *)(cfgParameters[1].ptrvalue)); + + /* free the memory allocated */ + free(cfgParameters[0].ptrvalue); + free(cfgParameters[1].ptrvalue); + + return 0; +} /* LocalOrRemoteDbConfigDefaultsSetGet */ + diff --git a/c/dbinline.sqc b/c/dbinline.sqc new file mode 100644 index 0000000..14c6a2c --- /dev/null +++ b/c/dbinline.sqc @@ -0,0 +1,885 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: dbinline.sqc +** +** SAMPLE: How to use inline SQL Procedure Language +** +** This sample demonstrates how to use Inline SQL Procedure Language. +** The program uses an existing database to create various tables, +** functions and triggers to show three sample usages. The first +** example is a scalar function. The second example is a table-level +** function and the third example demonstrates a pair of triggers. +** +** SQL STATEMENTS USED: +** INCLUDE +** CREATE TABLE +** CREATE FUNCTION (SQL Scalar, Table or Row) +** CREATE TRIGGER +** INSERT +** DECLARE CURSOR +** OPEN +** FETCH +** CLOSE +** BEGIN ATOMIC +** LEAVE +** IF statement +** WHILE statement +** FOR statement +** RETURN +** SELECT +** UPDATE +** DROP FUNCTION +** DROP TABLE +** DROP TRIGGER +** +** STRUCTURES USED: +** sqlca +** +** OUTPUT FILE: dbinline.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +EXEC SQL BEGIN DECLARE SECTION; + + char dbAlias[15]; + char user[15]; + char pswd[15]; + char strStmt[1000]; + short input; + short output; + short key; + short value; + char status[8 + 1]; + char part_no[5 + 1]; + short amount; + short reorder_no; + short stock_change; + char action[3 + 1]; + char timestamp [25 + 1]; + short transaction_no; + +EXEC SQL END DECLARE SECTION; + +int ScalarFunction(void); +int TableFunction(void); +int Triggers(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if(rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO USE INLINE SQL PROCEDURE LANGUAGE.\n"); + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if(rc != 0) + { + return rc; + } + + ScalarFunction(); + TableFunction(); + Triggers(); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if(rc != 0) + { + return rc; + } + + return 0; + +} /* main */ + + /* ScalarFunction + This function shows BEGIN ATOMIC, DECLARE variable, IF, WHILE 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%0AG>y-1uAYSZoErrUbg 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%0AcB0Q(B$Zc>YRHz*VC` z9$JEf=-g%WqCp@%qbFbym<-Lb(KZm_o^e0piP)Isxru~Qv53D$$A`CSL$O?cjEZF^ zofDWL5-yz&G9WMgaqDTeD1^6pJ7P%>yQB_&wtzUfN;>6BXR~N3UO+RETBX>Y{A2bE zcmWDG6*&9B>EX6&LaF4VG1dtZfd|Fh1=0y{m16*}JoOPbeR@hKK;hyNL9chhXVIR< zxa%`vVmp@V)S>>l!Uxcnd@#GzohLmWY|a(9&~w`6ER-G(&(0Sf4`uLpXbL@Vt#^<; zleZfKosPlq5=P8&DJ!@+b1=Q2SAC0fMLl{j(d#DNWIcgL(biKn4m@C4&=fvh^etUc z!~Du~aLRcVV+Df9OE-7~cp^%~I4<+FLN4C5NZnZzz4z3SW4^*1j(`I0sT{{R!BdI! za^9nrJ|4?Ab{*U4E$z;XuP`|C`On~CWY-BWEdpjWgt?2^Ej@4Fn8$;LLx$@x{Ol4_ zAOY72h2ppgKO13HhPrRbuYnslRo?}g2U1Xb#=teY5X=r@V^uA&Jslh4OdU`I?`b%0 z2O~V~p;5IF(1tcJ61?cJu-m7(5efO#pu{6HFVzk{Mh@Y!6Fdcd4Ts)M(eyOd;%a z81K8X6yrRw2dT;|$e}jFJdlbyE13r_731ABX}r<B+%x?BZ^) zQyYmP*=0qIohXgFO2rxDPSNWydp)KeQex?|EZ{#Q?yJiADh&??X1LbaTqikYCg7%5 z+oKElC(~7IS&`1#@E#SY)!RXomWXs=JU(x8UmsHqWBvV(@a)B{jV-98KC{@4ZMKbD z!e6ehv{WmE95Zun7AFR1bCDy0A!mjC38iau9Wg!ErF>L>)(I5Zz#k<4Q8b(L#`%caqG&UC=m-JDv9mDSN^s>I>ARxu&j3hd?va!T^gNA)mf)qIp~t`XyC9GHxH`EJ5^+b`BAr6w^22?5szKa5Gp zCEJ}BM=7vF3PkU>V42TQ#@m>1hl1B5{B^=(02k~>O9pDbB1ygrsR;UD7&wSNP#v%Y zJl8wGabp$CkA>kBj(y>{6d%H+T^#~kN-+m9sm&QQtYlw#CRv6WnAAUrNoP)@%oLOn z57Gpfw43m!3BL>ZDY4$WV0S=ZYz2K|m5Ahwj=9XyBxBqecI@c$3_?##)@~i+XbueP zQ04qX;zru*8uYYhHo9lwWniM{yT|bP<>|f{?daZPK9Re0-Fy&2BRojrLiAxz=&?jr(#Wc7o!|IuW$oQCC?80BVPBi%x7N90zSS#F-PTycSJ=Bn~T>;Ou5AX@p-U< z26#Z^XobUd?Qnd~SDb?$H|07-8B8qvDrTDuS2|SFF)JP*aqZU*3vCtAz1{aO-`K)Pn&T05`#)@>>j4|H#@Q=q1n_{78IgQ7UPJ(Y8N+CYH zIshhB%X-w$piK7zae_&9*H37BST5~{U??s*F81_C?J~Czk8Z4f>z-r2(j?Cii4ySk zgfAn!vAjO&08(HsCFVU~0y8czGu2MUXE3>dskR07R9m0+^9{<*DvA?!*7~-*>N3|{pGJA! z(X0mYo#GlY@H{NtibHz z{R{0k%HQ+5)lZ~af5VXQd7s8`WMCBCpBLQPB-A_X zU{h`;rbGS8+aN}mNHkmITSHjhW}C6h>4WQpSTp18IL0t=ouQxq?!R=kyA=iyZt!I0 z?KI`mhJ$0Rd)hj|ZcgGg zH%F?tt zhAo~kaoRoYvGKt5a-8>h42zKR+&#h=;1xU}__(lHG}!cQuDG0Mx-z#$JTUyrLCL=d z5ix~-ci^whsikFYAq8fsxTXr#0ZrN$WM~I>frN3ztlQEL%EAtEU}LZ|Bj}=~u#s?) z6c%`GQ||W=U;Hv9| z=nQ87pNi8UYvKkctFd8K$yR!8P!SCAag>+7?FIGI@YGWcJoPl=0PZ+C@b=!BjDiJo zkcj-|ckN8~xOY*)QqY-qy$?cfBH#hM5+TGzc=KsUgw6UMnxD-QQ6iRUUm?k6T@j{P zGDJjZ<8WJ(!vxC>v{btkN)~(Fg{x5>Y8joQjd~ILG`Z$Pps{sh%1wsM$@RBg6=%HBB0a@A_wiT$J%XMu^_anXVn&hN39h`P`wD0dEbo09|6rmZu9A@^inYs-wkGe$xWf+3S)72qiay>MKVUrSiDlg7ABgGn zr%2|~Ct(I=xRzvKF3sx6SRaUygy&{65WNF-EuH{fOPzJOHU{0KrWXq?=01wFh}HJB znqZD)BUT&Ae;)K^ZCvS-oG=+|3hT1^C77*aY^_&1Q`XE-G5mI8FLF)vG5prdK?RnA zG|rkumT_hB+14ho(`|YC9M9X`w;%w)Qrysuz@ivFFu;WYc9$7zSF|MLEnlojx04w+ zYLB-Q%+TW(6>9^Kh5#V)4q7LIgPbNa%;rUs7y9#?;t}7t(x(`G1R(KvFRX|}!4!LI z4e!hD>wh(k*^YJ>w%bznjYKMPQzEX5yXn5+C{kdF1;1DF9p9liVsX4AI)-s+Tt8^- zFd$teg?#9go&1ybuSuBCT-&kKUa$-{&Rou3?8r>laT>0YYVQr0U)Uu51z=zg8n9Qw zFp?j^z4sR(O@Y~QshAxH@5Sgkz7?Y@OW07AFj>T2xlyZ+H5nwXP|cF3+Q?Cspfeb= zB>IVj8tCB8n4}Wa1*0AT3X);U`w0yUqVOj{VR0$PKPg;-40<1l!Jxk}jQ$s-U7OhbrBTXJdkH|+oRh&O~7h}ZxZgyBR2 zu@BQ=obAR@XnuWh6#5AWXY9i?yX$B1A-mgc+oZ=n97QBzA3iBgM2BahAeM}2k!X)L zvI#2oVVa12cnyp>J5EDI?8El%SG(au^TE*==gFLO*Kx)^wATBQ2~+xU75wlw1V1E2 z2!6{wLheL3p9q|o8dZ2A-r5lUzsxgW@zZ*wwr|TF`M)q zSeD)fQKmX$%2^r-yQ<$u^H0Pt%<7@+WK3F!wh~u^XFMeg4|+A@=NiI;7HcQ3(Y5SN z$ffr^w5(yN2DtZr@C~>A868yVz=2}&c}N?Axxx8)+7YhRZiR-m6?~q5EaJ6VAv-S* zlh_BW!D_OuwVABnr{}GLwslOUnr-Nbzf@mrkNpLVs{0)_?uH3EH0Noo>b}L^nxv&j z&@x}pl4Y@DFh+nc5OykcA_b&_Xjg9fuycOTE%tOFMUqO1T<3-`=(4Xs* zf`>8o4`{c-v?%->^_k{9(ICU!Gfw+7AL|4p7{>`0Z_pEnRyNff58f@{;hZ+}3Tb3v zPanz$4dP0PXziYs*gJETK#68G^duTFX?~0;_bYHY1CIsc_>iUSt4P$HfCXxC|$$cX?cwlyg$*05}{cZ^<~5Vf)G)2z&ySajbKuJx#O&DCji^Vk;v~Y z$h**ou1w`WCi}X)^?b!?w;YJQj z!;`ipztnUV=A<&h^98o#@fv<*)m<@OK#;{*c+ijQ-BIEM1UTOk)4a{jlco{xtI1W4 z3{&nx3<_^&9EU4~k?GRJ(jL@%R|BrE3(9pzjgc?S*mm91dGN-!%z6H?c3_JS#_ z0UB;arpb!1Yen3fa!lZClpvz2O#`dN5do=*r>O*tpQynk%Kp#}3aAC1I6}A_HjtBn z5fX)bE`(4+E_gQmPyf}F`ZIgsJ?=!HyI`Vg@PVt0K3Zl$$}$T??ZFR2Hd zCu(F3rAeB}ch%WUxⅅ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

Resume: Delores M. Quintana

+

Table of Contents

+Resume: Delores M. Quintana
+Personal Information
+Department Information
+Education
+Work History
+Interests
+

+

+

Resume: Delores M. Quintana

+

+

Personal Information

+
+
Address: +
1150 Eglinton Ave +
+Mellonville, Idaho 83725 +
Phone: +
(208) 875-9933 +
Birthdate: +
September 15, 1925 +
Sex: +
Female +
Marital Status: +
Married +
Height: +
5'2" +
Weight: +
120 lbs. +
+

+

Department Information

+
+
Employee Number: +
000130 +
Dept Number: +
C01 +
Manager: +
Sally Kwan +
Position: +
Analyst +
Phone: +
(208) 385-4578 +
Hire Date: +
1971-07-28 +
+

+

Education

+
+

1965 +
Math and English, B.A. +
+Adelphi University +

1960 +
Dental Technician +
+Florida Institute of Technology +
+

+

Work History

+
+

10/91 - present +
Advisory Systems Analyst +
+Producing documentation tools for engineering department. +

12/85 - 9/91 +
Technical Writer +
+Writer, text programmer, and planner. +

1/79 - 11/85 +
COBOL Payroll Programmer +
+Writing payroll programs for a diesel fuel company. +
+

+

Interests

+
    +
  • Cooking +
  • Reading +
  • Sewing +
  • Remodeling +
+ + diff --git a/db2sampl/db200130.scr b/db2sampl/db200130.scr new file mode 100644 index 0000000..6859dab --- /dev/null +++ b/db2sampl/db200130.scr @@ -0,0 +1,86 @@ +:userdoc. +:prolog. +:docprof layout=1 pagenum=no style=ibmxagd. +:eprolog. +.********************************* +:h3.Resume: Delores M. Quintana +.********************************* +:h3.Personal Information +:dl compact tsize=20 termhi=0 break=fit. +:dt.Address: +:dd.1150 Eglinton Ave +.br +Mellonville, Idaho 83725 +:dt.Phone: +:dd.(208) 875-9933 +:dt.Birthdate: +:dd.September 15, 1925 +:dt.Sex: +:dd.Female +:dt.Marital Status: +:dd.Married +:dt.Height: +:dd.5'2" +:dt.Weight: +:dd.120 lbs. +:edl. +.********************************* +:h3.Department Information +:dl compact tsize=20 termhi=0 break=fit. +:dt.Employee Number: +:dd.000130 +:dt.Dept Number: +:dd.C01 +:dt.Manager: +:dd.Sally Kwan +:dt.Position: +:dd.Analyst +:dt.Phone: +:dd.(208) 385-4578 +:dt.Hire Date: +:dd.1971-07-28 +:edl. +.********************************* +:h3.Education +:dl tsize=20 termhi=0 break=fit. +:dt.1965 +:dd.Math and English, B.A. +.br +Adelphi University +.********************************* +:dt.1960 +:dd.Dental Technician +.br +Florida Institute of Technology +:edl. +.********************************* +:h3.Work History +:dl tsize=20 termhi=0 break=none. +.********************************* +:dt.10/91 - present +:dd.Advisory Systems Analyst +.br +Producing documentation tools for engineering department. +.********************************* +:dt.12/85 - 9/91 +:dd.Technical Writer +.br +Writer, text programmer, and planner. +.********************************* +:dt.1/79 - 11/85 +:dd.COBOL Payroll Programmer +.br +Writing payroll programs for a diesel fuel company. +:edl. +.********************************* +:h3.Interests +.********************************* +:ul compact. +:li.Cooking +:li.Reading +:li.Sewing +:li.Remodeling +:eul. +.********************************* +:euserdoc. +.********************************* diff --git a/db2sampl/db200130.xwd b/db2sampl/db200130.xwd new file mode 100644 index 0000000000000000000000000000000000000000..eb73bcc3c43d2ac7d329c2cf98316f0c48da5d3b GIT binary patch literal 45800 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 NU?4A~^8MF8{|ACxa8m#P literal 0 HcmV?d00001 diff --git a/db2sampl/db200140.gif b/db2sampl/db200140.gif new file mode 100644 index 0000000000000000000000000000000000000000..5bb20613d08474c61358287b2608381d20114d1c GIT binary patch literal 29143 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 aw_w%FG1T;{eHK6e|Cc7_kT3`Y(EC3=^3y5+ literal 0 HcmV?d00001 diff --git a/db2sampl/db200140.html b/db2sampl/db200140.html new file mode 100755 index 0000000..e00fc14 --- /dev/null +++ b/db2sampl/db200140.html @@ -0,0 +1,97 @@ + + +Resume: Heather A. Nicholls + + + + + + + + + +

Resume: Heather A. Nicholls

+

Table of Contents

+Resume: Heather A. Nicholls
+Personal Information
+Department Information
+Education
+Work History
+Interests
+

+

+

Resume: Heather A. Nicholls

+

+

Personal Information

+
+
Address: +
844 Don Mills Ave +
+Mellonville, Idaho 83734 +
Phone: +
(208) 610-2310 +
Birthdate: +
January 19, 1946 +
Sex: +
Female +
Marital Status: +
Single +
Height: +
5'8" +
Weight: +
130 lbs. +
+

+

Department Information

+
+
Employee Number: +
000140 +
Dept Number: +
C01 +
Manager: +
Sally Kwan +
Position: +
Analyst +
Phone: +
(208) 385-1793 +
Hire Date: +
1976-12-15 +
+

+

Education

+
+

1972 +
Computer Engineering, Ph.D. +
+University of Washington +

1969 +
Music and Physics, B.A. +
+Vassar College +
+

+

Work History

+
+

2/83 - present +
Architect, OCR Development +
+Designing the architecture of OCR products. +

12/76 - 1/83 +
Text Programmer +
+Optical character recognition (OCR) programming in PL/I. +

9/72 - 11/76 +
Punch Card Quality Analyst +
+Checking punch cards met quality specifications. +
+

+

Interests

+
    +
  • Model railroading +
  • Interior decorating +
  • Embroidery +
  • Knitting +
+ + diff --git a/db2sampl/db200140.scr b/db2sampl/db200140.scr new file mode 100644 index 0000000..3893bbe --- /dev/null +++ b/db2sampl/db200140.scr @@ -0,0 +1,87 @@ +:userdoc. +:prolog. +:docprof layout=1 pagenum=no style=ibmxagd. +:eprolog. +.********************************* +:h3.Resume: Heather A. Nicholls +.********************************* +:h3.Personal Information +:dl compact tsize=20 termhi=0 break=fit. +:dt.Address: +:dd.844 Don Mills Ave +.br +Mellonville, Idaho 83734 +:dt.Phone: +:dd.(208) 610-2310 +:dt.Birthdate: +:dd.January 19, 1946 +:dt.Sex: +:dd.Female +:dt.Marital Status: +:dd.Single +:dt.Height: +:dd.5'8" +:dt.Weight: +:dd.130 lbs. +:edl. +.********************************* +:h3.Department Information +:dl compact tsize=20 termhi=0 break=fit. +:dt.Employee Number: +:dd.000140 +:dt.Dept Number: +:dd.C01 +:dt.Manager: +:dd.Sally Kwan +:dt.Position: +:dd.Analyst +:dt.Phone: +:dd.(208) 385-1793 +:dt.Hire Date: +:dd.1976-12-15 +:edl. +.********************************* +:h3.Education +:dl tsize=20 termhi=0 break=fit. +:dt.1972 +:dd.Computer Engineering, Ph.D. +.br +University of Washington +.********************************* +:dt.1969 +:dd.Music and Physics, B.A. +.br +Vassar College +:edl. +.********************************* +:h3.Work History +:dl tsize=20 termhi=0 break=none. +.********************************* +:dt.2/83 - present +:dd.Architect, OCR Development +.br +Designing the architecture of OCR products. +.********************************* +:dt.12/76 - 1/83 +:dd.Text Programmer +.br +Optical character recognition (OCR) programming in PL/I. +.********************************* +:dt.9/72 - 11/76 +:dd.Punch Card Quality Analyst +.br +Checking punch cards met quality specifications. +.********************************* +:edl. +.********************************* +:h3.Interests +.********************************* +:ul compact. +:li.Model railroading +:li.Interior decorating +:li.Embroidery +:li.Knitting +:eul. +.********************************* +:euserdoc. +.********************************* diff --git a/db2sampl/db200140.xwd b/db2sampl/db200140.xwd new file mode 100644 index 0000000000000000000000000000000000000000..2fdc750b0b1b81e336f9840a3e17ec5e84b2e976 GIT binary patch literal 73908 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 literal 0 HcmV?d00001 diff --git a/db2sampl/db200150.asc b/db2sampl/db200150.asc new file mode 100644 index 0000000..60eff9e --- /dev/null +++ b/db2sampl/db200150.asc @@ -0,0 +1,55 @@ + + + Resume: Bruce Adamson + + + Personal Information + + Address: 3600 Steeles Ave + Mellonville, Idaho 83757 + Phone: (208) 725-4489 + Birthdate: May 17, 1947 + Sex: Male + Marital Status: Married + Height: 6'0" + Weight: 175 lbs. + + + Department Information + + Employee Number: 000150 + Dept Number: D11 + Manager: Irving Stern + Position: Designer + Phone: (208) 385-4510 + Hire Date: 1972-02-12 + + + Education + + 1971 Environmental Engineering, M.Sc. + Johns Hopkins University + + 1968 American History, B.A. + Northwestern University + + + Work History + + 8/79 - present Neural Network Design + Developing neural networks for machine + intelligence products. + + 2/72 - 7/79 Robot Vision Development + Developing rule-based systems to emulate sight. + + 9/71 - 1/72 Numerical Integration Specialist + Helping bank systems communicate with each other. + + + Interests + + o Racing motorcycles + o Building loudspeakers + o Assembling personal computers + o Sketching diff --git a/db2sampl/db200150.bmp b/db2sampl/db200150.bmp new file mode 100644 index 0000000000000000000000000000000000000000..208f2cf0130004c6ceb6a9eae7c732499c96b70f GIT binary patch literal 73438 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 PbMhiq6KdGldiMVTQF}Sp literal 0 HcmV?d00001 diff --git a/db2sampl/db200150.gif b/db2sampl/db200150.gif new file mode 100644 index 0000000000000000000000000000000000000000..02dee7c26c0e525e03542b5c6edb9ffa84c22d2a GIT binary patch literal 39795 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 literal 0 HcmV?d00001 diff --git a/db2sampl/db200150.html b/db2sampl/db200150.html new file mode 100755 index 0000000..124adcf --- /dev/null +++ b/db2sampl/db200150.html @@ -0,0 +1,97 @@ + + +Resume: Bruce Adamson + + + + + + + + + +

Resume: Bruce Adamson

+

Table of Contents

+Resume: Bruce Adamson
+Personal Information
+Department Information
+Education
+Work History
+Interests
+

+

+

Resume: Bruce Adamson

+

+

Personal Information

+
+
Address: +
3600 Steeles Ave +
+Mellonville, Idaho 83757 +
Phone: +
(208) 725-4489 +
Birthdate: +
May 17, 1947 +
Sex: +
Male +
Marital Status: +
Married +
Height: +
6'0" +
Weight: +
175 lbs. +
+

+

Department Information

+
+
Employee Number: +
000150 +
Dept Number: +
D11 +
Manager: +
Irving Stern +
Position: +
Designer +
Phone: +
(208) 385-4510 +
Hire Date: +
1972-02-12 +
+

+

Education

+
+

1971 +
Environmental Engineering, M.Sc. +
+Johns Hopkins University +

1968 +
American History, B.A. +
+Northwestern University +
+

+

Work History

+
+

8/79 - present +
Neural Network Design +
+Developing neural networks for machine intelligence products. +

2/72 - 7/79 +
Robot Vision Development +
+Developing rule-based systems to emulate sight. +

9/71 - 1/72 +
Numerical Integration Specialist +
+Helping bank systems communicate with each other. +
+

+

Interests

+
    +
  • Racing motorcycles +
  • Building loudspeakers +
  • Assembling personal computers +
  • Sketching +
+ + diff --git a/db2sampl/db200150.scr b/db2sampl/db200150.scr new file mode 100644 index 0000000..48fe335 --- /dev/null +++ b/db2sampl/db200150.scr @@ -0,0 +1,87 @@ +:userdoc. +:prolog. +:docprof layout=1 pagenum=no style=ibmxagd. +:eprolog. +.********************************* +:h3.Resume: Bruce Adamson +.********************************* +:h3.Personal Information +:dl compact tsize=20 termhi=0 break=fit. +:dt.Address: +:dd.3600 Steeles Ave +.br +Mellonville, Idaho 83757 +:dt.Phone: +:dd.(208) 725-4489 +:dt.Birthdate: +:dd.May 17, 1947 +:dt.Sex: +:dd.Male +:dt.Marital Status: +:dd.Married +:dt.Height: +:dd.6'0" +:dt.Weight: +:dd.175 lbs. +:edl. +.********************************* +:h3.Department Information +:dl compact tsize=20 termhi=0 break=fit. +:dt.Employee Number: +:dd.000150 +:dt.Dept Number: +:dd.D11 +:dt.Manager: +:dd.Irving Stern +:dt.Position: +:dd.Designer +:dt.Phone: +:dd.(208) 385-4510 +:dt.Hire Date: +:dd.1972-02-12 +:edl. +.********************************* +:h3.Education +:dl tsize=20 termhi=0 break=fit. +:dt.1971 +:dd.Environmental Engineering, M.Sc. +.br +Johns Hopkins University +.********************************* +:dt.1968 +:dd.American History, B.A. +.br +Northwestern University +:edl. +.********************************* +:h3.Work History +:dl tsize=20 termhi=0 break=none. +.********************************* +:dt.8/79 - present +:dd.Neural Network Design +.br +Developing neural networks for machine intelligence products. +.********************************* +:dt.2/72 - 7/79 +:dd.Robot Vision Development +.br +Developing rule-based systems to emulate sight. +.********************************* +:dt.9/71 - 1/72 +:dd.Numerical Integration Specialist +.br +Helping bank systems communicate with each other. +.********************************* +:edl. +.********************************* +:h3.Interests +.********************************* +:ul compact. +:li.Racing motorcycles +:li.Building loudspeakers +:li.Assembling personal computers +:li.Sketching +:eul. +.********************************* +:euserdoc. +.********************************* diff --git a/db2sampl/db200150.xwd b/db2sampl/db200150.xwd new file mode 100644 index 0000000000000000000000000000000000000000..eee8445ae3396e579181724ae9dda5475520e05f GIT binary patch literal 75547 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πIwf9!MQv#(b2jaVN)I!G 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 WP%>1E0pA9dRzkBUX)3(<$^Qq70~RR& literal 0 HcmV?d00001 diff --git a/db2sampl/db200190.asc b/db2sampl/db200190.asc new file mode 100644 index 0000000..9850bdc --- /dev/null +++ b/db2sampl/db200190.asc @@ -0,0 +1,55 @@ + + + Resume: James H. Walker + + + Personal Information + + Address: 3500 Steeles Ave + Mellonville, Idaho 83757 + Phone: (208) 725-7325 + Birthdate: June 25, 1952 + Sex: Male + Marital Status: Single + Height: 5'11" + Weight: 166 lbs. + + + Department Information + + Employee Number: 000190 + Dept Number: D11 + Manager: Irving Stern + Position: Designer + Phone: (208) 385-2986 + Hire Date: 1974-07-26 + + + Education + + 1974 Computer Studies, B.Sc. + University of Massachusetts + + 1972 Linguistic Anthropology, B.A. + University of Toronto + + + Work History + + 6/87 - present Microcode Design + Optimizing algorithms for mathematical functions. + + 4/77 - 5/87 Printer Technical Support + Installing and supporting laser printers. + + 9/74 - 3/77 Maintenance Programming + Patching assembly language compiler for + mainframes. + + + Interests + + o Wine tasting + o Skiing + o Swimming + o Dancing diff --git a/db2sampl/db200190.bmp b/db2sampl/db200190.bmp new file mode 100644 index 0000000000000000000000000000000000000000..11191fe1877092d76b13cdc965355b35cd37aa11 GIT binary patch literal 63542 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 ayc06z8A6AsP%m02o4M(UCt~n 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 + +Resume: James H. Walker + + + + + + + + + +

Resume: James H. Walker

+

Table of Contents

+Resume: James H. Walker
+Personal Information
+Department Information
+Education
+Work History
+Interests
+

+

+

Resume: James H. Walker

+

+

Personal Information

+
+
Address: +
3500 Steeles Ave +
+Mellonville, Idaho 83757 +
Phone: +
(208) 725-7325 +
Birthdate: +
June 25, 1952 +
Sex: +
Male +
Marital Status: +
Single +
Height: +
5'11" +
Weight: +
166 lbs. +
+

+

Department Information

+
+
Employee Number: +
000190 +
Dept Number: +
D11 +
Manager: +
Irving Stern +
Position: +
Designer +
Phone: +
(208) 385-2986 +
Hire Date: +
1974-07-26 +
+

+

Education

+
+

1974 +
Computer Studies, B.Sc. +
+University of Massachusetts +

1972 +
Linguistic Anthropology, B.A. +
+University of Toronto +
+

+

Work History

+
+

6/87 - present +
Microcode Design +
+Optimizing algorithms for mathematical functions. +

4/77 - 5/87 +
Printer Technical Support +
+Installing and supporting laser printers. +

9/74 - 3/77 +
Maintenance Programming +
+Patching assembly language compiler for mainframes. +
+

+

Interests

+
    +
  • Wine tasting +
  • Skiing +
  • Swimming +
  • Dancing +
+ + diff --git a/db2sampl/db200190.scr b/db2sampl/db200190.scr new file mode 100644 index 0000000..1be9491 --- /dev/null +++ b/db2sampl/db200190.scr @@ -0,0 +1,87 @@ +:userdoc. +:prolog. +:docprof layout=1 pagenum=no style=ibmxagd. +:eprolog. +.********************************* +:h3.Resume: James H. Walker +.********************************* +:h3.Personal Information +:dl compact tsize=20 termhi=0 break=fit. +:dt.Address: +:dd.3500 Steeles Ave +.br +Mellonville, Idaho 83757 +:dt.Phone: +:dd.(208) 725-7325 +:dt.Birthdate: +:dd.June 25, 1952 +:dt.Sex: +:dd.Male +:dt.Marital Status: +:dd.Single +:dt.Height: +:dd.5'11" +:dt.Weight: +:dd.166 lbs. +:edl. +.********************************* +:h3.Department Information +:dl compact tsize=20 termhi=0 break=fit. +:dt.Employee Number: +:dd.000190 +:dt.Dept Number: +:dd.D11 +:dt.Manager: +:dd.Irving Stern +:dt.Position: +:dd.Designer +:dt.Phone: +:dd.(208) 385-2986 +:dt.Hire Date: +:dd.1974-07-26 +:edl. +.********************************* +:h3.Education +:dl tsize=20 termhi=0 break=fit. +:dt.1974 +:dd.Computer Studies, B.Sc. +.br +University of Massachusetts +.********************************* +:dt.1972 +:dd.Linguistic Anthropology, B.A. +.br +University of Toronto +:edl. +.********************************* +:h3.Work History +:dl tsize=20 termhi=0 break=none. +.********************************* +:dt.6/87 - present +:dd.Microcode Design +.br +Optimizing algorithms for mathematical functions. +.********************************* +:dt.4/77 - 5/87 +:dd.Printer Technical Support +.br +Installing and supporting laser printers. +.********************************* +:dt.9/74 - 3/77 +:dd.Maintenance Programming +.br +Patching assembly language compiler for mainframes. +.********************************* +:edl. +.********************************* +:h3.Interests +.********************************* +:ul compact. +:li.Wine tasting +:li.Skiing +:li.Swimming +:li.Dancing +:eul. +.********************************* +:euserdoc. +.********************************* diff --git a/db2sampl/db200190.xwd b/db2sampl/db200190.xwd new file mode 100644 index 0000000000000000000000000000000000000000..6d0f0f736676e9b724599c1dcbb3ac9261dbd4ad GIT binary patch literal 65650 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 + + + + + + + + + + + + + diff --git a/db2sampl/mdcdata.del b/db2sampl/mdcdata.del new file mode 100644 index 0000000..f3d2057 --- /dev/null +++ b/db2sampl/mdcdata.del @@ -0,0 +1,10000 @@ +0,1,1 +1,2,2 +2,3,3 +3,4,4 +4,5,5 +5,1,6 +6,2,7 +7,3,8 +8,4,9 +9,5,10 +10,1,1 +11,2,2 +12,3,3 +13,4,4 +14,5,5 +15,1,6 +16,2,7 +17,3,8 +18,4,9 +19,5,10 +20,1,1 +21,2,2 +22,3,3 +23,4,4 +24,5,5 +25,1,6 +26,2,7 +27,3,8 +28,4,9 +29,5,10 +30,1,1 +31,2,2 +32,3,3 +33,4,4 +34,5,5 +35,1,6 +36,2,7 +37,3,8 +38,4,9 +39,5,10 +40,1,1 +41,2,2 +42,3,3 +43,4,4 +44,5,5 +45,1,6 +46,2,7 +47,3,8 +48,4,9 +49,5,10 +50,1,1 +51,2,2 +52,3,3 +53,4,4 +54,5,5 +55,1,6 +56,2,7 +57,3,8 +58,4,9 +59,5,10 +60,1,1 +61,2,2 +62,3,3 +63,4,4 +64,5,5 +65,1,6 +66,2,7 +67,3,8 +68,4,9 +69,5,10 +70,1,1 +71,2,2 +72,3,3 +73,4,4 +74,5,5 +75,1,6 +76,2,7 +77,3,8 +78,4,9 +79,5,10 +80,1,1 +81,2,2 +82,3,3 +83,4,4 +84,5,5 +85,1,6 +86,2,7 +87,3,8 +88,4,9 +89,5,10 +90,1,1 +91,2,2 +92,3,3 +93,4,4 +94,5,5 +95,1,6 +96,2,7 +97,3,8 +98,4,9 +99,5,10 +100,1,1 +101,2,2 +102,3,3 +103,4,4 +104,5,5 +105,1,6 +106,2,7 +107,3,8 +108,4,9 +109,5,10 +110,1,1 +111,2,2 +112,3,3 +113,4,4 +114,5,5 +115,1,6 +116,2,7 +117,3,8 +118,4,9 +119,5,10 +120,1,1 +121,2,2 +122,3,3 +123,4,4 +124,5,5 +125,1,6 +126,2,7 +127,3,8 +128,4,9 +129,5,10 +130,1,1 +131,2,2 +132,3,3 +133,4,4 +134,5,5 +135,1,6 +136,2,7 +137,3,8 +138,4,9 +139,5,10 +140,1,1 +141,2,2 +142,3,3 +143,4,4 +144,5,5 +145,1,6 +146,2,7 +147,3,8 +148,4,9 +149,5,10 +150,1,1 +151,2,2 +152,3,3 +153,4,4 +154,5,5 +155,1,6 +156,2,7 +157,3,8 +158,4,9 +159,5,10 +160,1,1 +161,2,2 +162,3,3 +163,4,4 +164,5,5 +165,1,6 +166,2,7 +167,3,8 +168,4,9 +169,5,10 +170,1,1 +171,2,2 +172,3,3 +173,4,4 +174,5,5 +175,1,6 +176,2,7 +177,3,8 +178,4,9 +179,5,10 +180,1,1 +181,2,2 +182,3,3 +183,4,4 +184,5,5 +185,1,6 +186,2,7 +187,3,8 +188,4,9 +189,5,10 +190,1,1 +191,2,2 +192,3,3 +193,4,4 +194,5,5 +195,1,6 +196,2,7 +197,3,8 +198,4,9 +199,5,10 +200,1,1 +201,2,2 +202,3,3 +203,4,4 +204,5,5 +205,1,6 +206,2,7 +207,3,8 +208,4,9 +209,5,10 +210,1,1 +211,2,2 +212,3,3 +213,4,4 +214,5,5 +215,1,6 +216,2,7 +217,3,8 +218,4,9 +219,5,10 +220,1,1 +221,2,2 +222,3,3 +223,4,4 +224,5,5 +225,1,6 +226,2,7 +227,3,8 +228,4,9 +229,5,10 +230,1,1 +231,2,2 +232,3,3 +233,4,4 +234,5,5 +235,1,6 +236,2,7 +237,3,8 +238,4,9 +239,5,10 +240,1,1 +241,2,2 +242,3,3 +243,4,4 +244,5,5 +245,1,6 +246,2,7 +247,3,8 +248,4,9 +249,5,10 +250,1,1 +251,2,2 +252,3,3 +253,4,4 +254,5,5 +255,1,6 +256,2,7 +257,3,8 +258,4,9 +259,5,10 +260,1,1 +261,2,2 +262,3,3 +263,4,4 +264,5,5 +265,1,6 +266,2,7 +267,3,8 +268,4,9 +269,5,10 +270,1,1 +271,2,2 +272,3,3 +273,4,4 +274,5,5 +275,1,6 +276,2,7 +277,3,8 +278,4,9 +279,5,10 +280,1,1 +281,2,2 +282,3,3 +283,4,4 +284,5,5 +285,1,6 +286,2,7 +287,3,8 +288,4,9 +289,5,10 +290,1,1 +291,2,2 +292,3,3 +293,4,4 +294,5,5 +295,1,6 +296,2,7 +297,3,8 +298,4,9 +299,5,10 +300,1,1 +301,2,2 +302,3,3 +303,4,4 +304,5,5 +305,1,6 +306,2,7 +307,3,8 +308,4,9 +309,5,10 +310,1,1 +311,2,2 +312,3,3 +313,4,4 +314,5,5 +315,1,6 +316,2,7 +317,3,8 +318,4,9 +319,5,10 +320,1,1 +321,2,2 +322,3,3 +323,4,4 +324,5,5 +325,1,6 +326,2,7 +327,3,8 +328,4,9 +329,5,10 +330,1,1 +331,2,2 +332,3,3 +333,4,4 +334,5,5 +335,1,6 +336,2,7 +337,3,8 +338,4,9 +339,5,10 +340,1,1 +341,2,2 +342,3,3 +343,4,4 +344,5,5 +345,1,6 +346,2,7 +347,3,8 +348,4,9 +349,5,10 +350,1,1 +351,2,2 +352,3,3 +353,4,4 +354,5,5 +355,1,6 +356,2,7 +357,3,8 +358,4,9 +359,5,10 +360,1,1 +361,2,2 +362,3,3 +363,4,4 +364,5,5 +365,1,6 +366,2,7 +367,3,8 +368,4,9 +369,5,10 +370,1,1 +371,2,2 +372,3,3 +373,4,4 +374,5,5 +375,1,6 +376,2,7 +377,3,8 +378,4,9 +379,5,10 +380,1,1 +381,2,2 +382,3,3 +383,4,4 +384,5,5 +385,1,6 +386,2,7 +387,3,8 +388,4,9 +389,5,10 +390,1,1 +391,2,2 +392,3,3 +393,4,4 +394,5,5 +395,1,6 +396,2,7 +397,3,8 +398,4,9 +399,5,10 +400,1,1 +401,2,2 +402,3,3 +403,4,4 +404,5,5 +405,1,6 +406,2,7 +407,3,8 +408,4,9 +409,5,10 +410,1,1 +411,2,2 +412,3,3 +413,4,4 +414,5,5 +415,1,6 +416,2,7 +417,3,8 +418,4,9 +419,5,10 +420,1,1 +421,2,2 +422,3,3 +423,4,4 +424,5,5 +425,1,6 +426,2,7 +427,3,8 +428,4,9 +429,5,10 +430,1,1 +431,2,2 +432,3,3 +433,4,4 +434,5,5 +435,1,6 +436,2,7 +437,3,8 +438,4,9 +439,5,10 +440,1,1 +441,2,2 +442,3,3 +443,4,4 +444,5,5 +445,1,6 +446,2,7 +447,3,8 +448,4,9 +449,5,10 +450,1,1 +451,2,2 +452,3,3 +453,4,4 +454,5,5 +455,1,6 +456,2,7 +457,3,8 +458,4,9 +459,5,10 +460,1,1 +461,2,2 +462,3,3 +463,4,4 +464,5,5 +465,1,6 +466,2,7 +467,3,8 +468,4,9 +469,5,10 +470,1,1 +471,2,2 +472,3,3 +473,4,4 +474,5,5 +475,1,6 +476,2,7 +477,3,8 +478,4,9 +479,5,10 +480,1,1 +481,2,2 +482,3,3 +483,4,4 +484,5,5 +485,1,6 +486,2,7 +487,3,8 +488,4,9 +489,5,10 +490,1,1 +491,2,2 +492,3,3 +493,4,4 +494,5,5 +495,1,6 +496,2,7 +497,3,8 +498,4,9 +499,5,10 +500,1,1 +501,2,2 +502,3,3 +503,4,4 +504,5,5 +505,1,6 +506,2,7 +507,3,8 +508,4,9 +509,5,10 +510,1,1 +511,2,2 +512,3,3 +513,4,4 +514,5,5 +515,1,6 +516,2,7 +517,3,8 +518,4,9 +519,5,10 +520,1,1 +521,2,2 +522,3,3 +523,4,4 +524,5,5 +525,1,6 +526,2,7 +527,3,8 +528,4,9 +529,5,10 +530,1,1 +531,2,2 +532,3,3 +533,4,4 +534,5,5 +535,1,6 +536,2,7 +537,3,8 +538,4,9 +539,5,10 +540,1,1 +541,2,2 +542,3,3 +543,4,4 +544,5,5 +545,1,6 +546,2,7 +547,3,8 +548,4,9 +549,5,10 +550,1,1 +551,2,2 +552,3,3 +553,4,4 +554,5,5 +555,1,6 +556,2,7 +557,3,8 +558,4,9 +559,5,10 +560,1,1 +561,2,2 +562,3,3 +563,4,4 +564,5,5 +565,1,6 +566,2,7 +567,3,8 +568,4,9 +569,5,10 +570,1,1 +571,2,2 +572,3,3 +573,4,4 +574,5,5 +575,1,6 +576,2,7 +577,3,8 +578,4,9 +579,5,10 +580,1,1 +581,2,2 +582,3,3 +583,4,4 +584,5,5 +585,1,6 +586,2,7 +587,3,8 +588,4,9 +589,5,10 +590,1,1 +591,2,2 +592,3,3 +593,4,4 +594,5,5 +595,1,6 +596,2,7 +597,3,8 +598,4,9 +599,5,10 +600,1,1 +601,2,2 +602,3,3 +603,4,4 +604,5,5 +605,1,6 +606,2,7 +607,3,8 +608,4,9 +609,5,10 +610,1,1 +611,2,2 +612,3,3 +613,4,4 +614,5,5 +615,1,6 +616,2,7 +617,3,8 +618,4,9 +619,5,10 +620,1,1 +621,2,2 +622,3,3 +623,4,4 +624,5,5 +625,1,6 +626,2,7 +627,3,8 +628,4,9 +629,5,10 +630,1,1 +631,2,2 +632,3,3 +633,4,4 +634,5,5 +635,1,6 +636,2,7 +637,3,8 +638,4,9 +639,5,10 +640,1,1 +641,2,2 +642,3,3 +643,4,4 +644,5,5 +645,1,6 +646,2,7 +647,3,8 +648,4,9 +649,5,10 +650,1,1 +651,2,2 +652,3,3 +653,4,4 +654,5,5 +655,1,6 +656,2,7 +657,3,8 +658,4,9 +659,5,10 +660,1,1 +661,2,2 +662,3,3 +663,4,4 +664,5,5 +665,1,6 +666,2,7 +667,3,8 +668,4,9 +669,5,10 +670,1,1 +671,2,2 +672,3,3 +673,4,4 +674,5,5 +675,1,6 +676,2,7 +677,3,8 +678,4,9 +679,5,10 +680,1,1 +681,2,2 +682,3,3 +683,4,4 +684,5,5 +685,1,6 +686,2,7 +687,3,8 +688,4,9 +689,5,10 +690,1,1 +691,2,2 +692,3,3 +693,4,4 +694,5,5 +695,1,6 +696,2,7 +697,3,8 +698,4,9 +699,5,10 +700,1,1 +701,2,2 +702,3,3 +703,4,4 +704,5,5 +705,1,6 +706,2,7 +707,3,8 +708,4,9 +709,5,10 +710,1,1 +711,2,2 +712,3,3 +713,4,4 +714,5,5 +715,1,6 +716,2,7 +717,3,8 +718,4,9 +719,5,10 +720,1,1 +721,2,2 +722,3,3 +723,4,4 +724,5,5 +725,1,6 +726,2,7 +727,3,8 +728,4,9 +729,5,10 +730,1,1 +731,2,2 +732,3,3 +733,4,4 +734,5,5 +735,1,6 +736,2,7 +737,3,8 +738,4,9 +739,5,10 +740,1,1 +741,2,2 +742,3,3 +743,4,4 +744,5,5 +745,1,6 +746,2,7 +747,3,8 +748,4,9 +749,5,10 +750,1,1 +751,2,2 +752,3,3 +753,4,4 +754,5,5 +755,1,6 +756,2,7 +757,3,8 +758,4,9 +759,5,10 +760,1,1 +761,2,2 +762,3,3 +763,4,4 +764,5,5 +765,1,6 +766,2,7 +767,3,8 +768,4,9 +769,5,10 +770,1,1 +771,2,2 +772,3,3 +773,4,4 +774,5,5 +775,1,6 +776,2,7 +777,3,8 +778,4,9 +779,5,10 +780,1,1 +781,2,2 +782,3,3 +783,4,4 +784,5,5 +785,1,6 +786,2,7 +787,3,8 +788,4,9 +789,5,10 +790,1,1 +791,2,2 +792,3,3 +793,4,4 +794,5,5 +795,1,6 +796,2,7 +797,3,8 +798,4,9 +799,5,10 +800,1,1 +801,2,2 +802,3,3 +803,4,4 +804,5,5 +805,1,6 +806,2,7 +807,3,8 +808,4,9 +809,5,10 +810,1,1 +811,2,2 +812,3,3 +813,4,4 +814,5,5 +815,1,6 +816,2,7 +817,3,8 +818,4,9 +819,5,10 +820,1,1 +821,2,2 +822,3,3 +823,4,4 +824,5,5 +825,1,6 +826,2,7 +827,3,8 +828,4,9 +829,5,10 +830,1,1 +831,2,2 +832,3,3 +833,4,4 +834,5,5 +835,1,6 +836,2,7 +837,3,8 +838,4,9 +839,5,10 +840,1,1 +841,2,2 +842,3,3 +843,4,4 +844,5,5 +845,1,6 +846,2,7 +847,3,8 +848,4,9 +849,5,10 +850,1,1 +851,2,2 +852,3,3 +853,4,4 +854,5,5 +855,1,6 +856,2,7 +857,3,8 +858,4,9 +859,5,10 +860,1,1 +861,2,2 +862,3,3 +863,4,4 +864,5,5 +865,1,6 +866,2,7 +867,3,8 +868,4,9 +869,5,10 +870,1,1 +871,2,2 +872,3,3 +873,4,4 +874,5,5 +875,1,6 +876,2,7 +877,3,8 +878,4,9 +879,5,10 +880,1,1 +881,2,2 +882,3,3 +883,4,4 +884,5,5 +885,1,6 +886,2,7 +887,3,8 +888,4,9 +889,5,10 +890,1,1 +891,2,2 +892,3,3 +893,4,4 +894,5,5 +895,1,6 +896,2,7 +897,3,8 +898,4,9 +899,5,10 +900,1,1 +901,2,2 +902,3,3 +903,4,4 +904,5,5 +905,1,6 +906,2,7 +907,3,8 +908,4,9 +909,5,10 +910,1,1 +911,2,2 +912,3,3 +913,4,4 +914,5,5 +915,1,6 +916,2,7 +917,3,8 +918,4,9 +919,5,10 +920,1,1 +921,2,2 +922,3,3 +923,4,4 +924,5,5 +925,1,6 +926,2,7 +927,3,8 +928,4,9 +929,5,10 +930,1,1 +931,2,2 +932,3,3 +933,4,4 +934,5,5 +935,1,6 +936,2,7 +937,3,8 +938,4,9 +939,5,10 +940,1,1 +941,2,2 +942,3,3 +943,4,4 +944,5,5 +945,1,6 +946,2,7 +947,3,8 +948,4,9 +949,5,10 +950,1,1 +951,2,2 +952,3,3 +953,4,4 +954,5,5 +955,1,6 +956,2,7 +957,3,8 +958,4,9 +959,5,10 +960,1,1 +961,2,2 +962,3,3 +963,4,4 +964,5,5 +965,1,6 +966,2,7 +967,3,8 +968,4,9 +969,5,10 +970,1,1 +971,2,2 +972,3,3 +973,4,4 +974,5,5 +975,1,6 +976,2,7 +977,3,8 +978,4,9 +979,5,10 +980,1,1 +981,2,2 +982,3,3 +983,4,4 +984,5,5 +985,1,6 +986,2,7 +987,3,8 +988,4,9 +989,5,10 +990,1,1 +991,2,2 +992,3,3 +993,4,4 +994,5,5 +995,1,6 +996,2,7 +997,3,8 +998,4,9 +999,5,10 +1000,1,1 +1001,2,2 +1002,3,3 +1003,4,4 +1004,5,5 +1005,1,6 +1006,2,7 +1007,3,8 +1008,4,9 +1009,5,10 +1010,1,1 +1011,2,2 +1012,3,3 +1013,4,4 +1014,5,5 +1015,1,6 +1016,2,7 +1017,3,8 +1018,4,9 +1019,5,10 +1020,1,1 +1021,2,2 +1022,3,3 +1023,4,4 +1024,5,5 +1025,1,6 +1026,2,7 +1027,3,8 +1028,4,9 +1029,5,10 +1030,1,1 +1031,2,2 +1032,3,3 +1033,4,4 +1034,5,5 +1035,1,6 +1036,2,7 +1037,3,8 +1038,4,9 +1039,5,10 +1040,1,1 +1041,2,2 +1042,3,3 +1043,4,4 +1044,5,5 +1045,1,6 +1046,2,7 +1047,3,8 +1048,4,9 +1049,5,10 +1050,1,1 +1051,2,2 +1052,3,3 +1053,4,4 +1054,5,5 +1055,1,6 +1056,2,7 +1057,3,8 +1058,4,9 +1059,5,10 +1060,1,1 +1061,2,2 +1062,3,3 +1063,4,4 +1064,5,5 +1065,1,6 +1066,2,7 +1067,3,8 +1068,4,9 +1069,5,10 +1070,1,1 +1071,2,2 +1072,3,3 +1073,4,4 +1074,5,5 +1075,1,6 +1076,2,7 +1077,3,8 +1078,4,9 +1079,5,10 +1080,1,1 +1081,2,2 +1082,3,3 +1083,4,4 +1084,5,5 +1085,1,6 +1086,2,7 +1087,3,8 +1088,4,9 +1089,5,10 +1090,1,1 +1091,2,2 +1092,3,3 +1093,4,4 +1094,5,5 +1095,1,6 +1096,2,7 +1097,3,8 +1098,4,9 +1099,5,10 +1100,1,1 +1101,2,2 +1102,3,3 +1103,4,4 +1104,5,5 +1105,1,6 +1106,2,7 +1107,3,8 +1108,4,9 +1109,5,10 +1110,1,1 +1111,2,2 +1112,3,3 +1113,4,4 +1114,5,5 +1115,1,6 +1116,2,7 +1117,3,8 +1118,4,9 +1119,5,10 +1120,1,1 +1121,2,2 +1122,3,3 +1123,4,4 +1124,5,5 +1125,1,6 +1126,2,7 +1127,3,8 +1128,4,9 +1129,5,10 +1130,1,1 +1131,2,2 +1132,3,3 +1133,4,4 +1134,5,5 +1135,1,6 +1136,2,7 +1137,3,8 +1138,4,9 +1139,5,10 +1140,1,1 +1141,2,2 +1142,3,3 +1143,4,4 +1144,5,5 +1145,1,6 +1146,2,7 +1147,3,8 +1148,4,9 +1149,5,10 +1150,1,1 +1151,2,2 +1152,3,3 +1153,4,4 +1154,5,5 +1155,1,6 +1156,2,7 +1157,3,8 +1158,4,9 +1159,5,10 +1160,1,1 +1161,2,2 +1162,3,3 +1163,4,4 +1164,5,5 +1165,1,6 +1166,2,7 +1167,3,8 +1168,4,9 +1169,5,10 +1170,1,1 +1171,2,2 +1172,3,3 +1173,4,4 +1174,5,5 +1175,1,6 +1176,2,7 +1177,3,8 +1178,4,9 +1179,5,10 +1180,1,1 +1181,2,2 +1182,3,3 +1183,4,4 +1184,5,5 +1185,1,6 +1186,2,7 +1187,3,8 +1188,4,9 +1189,5,10 +1190,1,1 +1191,2,2 +1192,3,3 +1193,4,4 +1194,5,5 +1195,1,6 +1196,2,7 +1197,3,8 +1198,4,9 +1199,5,10 +1200,1,1 +1201,2,2 +1202,3,3 +1203,4,4 +1204,5,5 +1205,1,6 +1206,2,7 +1207,3,8 +1208,4,9 +1209,5,10 +1210,1,1 +1211,2,2 +1212,3,3 +1213,4,4 +1214,5,5 +1215,1,6 +1216,2,7 +1217,3,8 +1218,4,9 +1219,5,10 +1220,1,1 +1221,2,2 +1222,3,3 +1223,4,4 +1224,5,5 +1225,1,6 +1226,2,7 +1227,3,8 +1228,4,9 +1229,5,10 +1230,1,1 +1231,2,2 +1232,3,3 +1233,4,4 +1234,5,5 +1235,1,6 +1236,2,7 +1237,3,8 +1238,4,9 +1239,5,10 +1240,1,1 +1241,2,2 +1242,3,3 +1243,4,4 +1244,5,5 +1245,1,6 +1246,2,7 +1247,3,8 +1248,4,9 +1249,5,10 +1250,1,1 +1251,2,2 +1252,3,3 +1253,4,4 +1254,5,5 +1255,1,6 +1256,2,7 +1257,3,8 +1258,4,9 +1259,5,10 +1260,1,1 +1261,2,2 +1262,3,3 +1263,4,4 +1264,5,5 +1265,1,6 +1266,2,7 +1267,3,8 +1268,4,9 +1269,5,10 +1270,1,1 +1271,2,2 +1272,3,3 +1273,4,4 +1274,5,5 +1275,1,6 +1276,2,7 +1277,3,8 +1278,4,9 +1279,5,10 +1280,1,1 +1281,2,2 +1282,3,3 +1283,4,4 +1284,5,5 +1285,1,6 +1286,2,7 +1287,3,8 +1288,4,9 +1289,5,10 +1290,1,1 +1291,2,2 +1292,3,3 +1293,4,4 +1294,5,5 +1295,1,6 +1296,2,7 +1297,3,8 +1298,4,9 +1299,5,10 +1300,1,1 +1301,2,2 +1302,3,3 +1303,4,4 +1304,5,5 +1305,1,6 +1306,2,7 +1307,3,8 +1308,4,9 +1309,5,10 +1310,1,1 +1311,2,2 +1312,3,3 +1313,4,4 +1314,5,5 +1315,1,6 +1316,2,7 +1317,3,8 +1318,4,9 +1319,5,10 +1320,1,1 +1321,2,2 +1322,3,3 +1323,4,4 +1324,5,5 +1325,1,6 +1326,2,7 +1327,3,8 +1328,4,9 +1329,5,10 +1330,1,1 +1331,2,2 +1332,3,3 +1333,4,4 +1334,5,5 +1335,1,6 +1336,2,7 +1337,3,8 +1338,4,9 +1339,5,10 +1340,1,1 +1341,2,2 +1342,3,3 +1343,4,4 +1344,5,5 +1345,1,6 +1346,2,7 +1347,3,8 +1348,4,9 +1349,5,10 +1350,1,1 +1351,2,2 +1352,3,3 +1353,4,4 +1354,5,5 +1355,1,6 +1356,2,7 +1357,3,8 +1358,4,9 +1359,5,10 +1360,1,1 +1361,2,2 +1362,3,3 +1363,4,4 +1364,5,5 +1365,1,6 +1366,2,7 +1367,3,8 +1368,4,9 +1369,5,10 +1370,1,1 +1371,2,2 +1372,3,3 +1373,4,4 +1374,5,5 +1375,1,6 +1376,2,7 +1377,3,8 +1378,4,9 +1379,5,10 +1380,1,1 +1381,2,2 +1382,3,3 +1383,4,4 +1384,5,5 +1385,1,6 +1386,2,7 +1387,3,8 +1388,4,9 +1389,5,10 +1390,1,1 +1391,2,2 +1392,3,3 +1393,4,4 +1394,5,5 +1395,1,6 +1396,2,7 +1397,3,8 +1398,4,9 +1399,5,10 +1400,1,1 +1401,2,2 +1402,3,3 +1403,4,4 +1404,5,5 +1405,1,6 +1406,2,7 +1407,3,8 +1408,4,9 +1409,5,10 +1410,1,1 +1411,2,2 +1412,3,3 +1413,4,4 +1414,5,5 +1415,1,6 +1416,2,7 +1417,3,8 +1418,4,9 +1419,5,10 +1420,1,1 +1421,2,2 +1422,3,3 +1423,4,4 +1424,5,5 +1425,1,6 +1426,2,7 +1427,3,8 +1428,4,9 +1429,5,10 +1430,1,1 +1431,2,2 +1432,3,3 +1433,4,4 +1434,5,5 +1435,1,6 +1436,2,7 +1437,3,8 +1438,4,9 +1439,5,10 +1440,1,1 +1441,2,2 +1442,3,3 +1443,4,4 +1444,5,5 +1445,1,6 +1446,2,7 +1447,3,8 +1448,4,9 +1449,5,10 +1450,1,1 +1451,2,2 +1452,3,3 +1453,4,4 +1454,5,5 +1455,1,6 +1456,2,7 +1457,3,8 +1458,4,9 +1459,5,10 +1460,1,1 +1461,2,2 +1462,3,3 +1463,4,4 +1464,5,5 +1465,1,6 +1466,2,7 +1467,3,8 +1468,4,9 +1469,5,10 +1470,1,1 +1471,2,2 +1472,3,3 +1473,4,4 +1474,5,5 +1475,1,6 +1476,2,7 +1477,3,8 +1478,4,9 +1479,5,10 +1480,1,1 +1481,2,2 +1482,3,3 +1483,4,4 +1484,5,5 +1485,1,6 +1486,2,7 +1487,3,8 +1488,4,9 +1489,5,10 +1490,1,1 +1491,2,2 +1492,3,3 +1493,4,4 +1494,5,5 +1495,1,6 +1496,2,7 +1497,3,8 +1498,4,9 +1499,5,10 +1500,1,1 +1501,2,2 +1502,3,3 +1503,4,4 +1504,5,5 +1505,1,6 +1506,2,7 +1507,3,8 +1508,4,9 +1509,5,10 +1510,1,1 +1511,2,2 +1512,3,3 +1513,4,4 +1514,5,5 +1515,1,6 +1516,2,7 +1517,3,8 +1518,4,9 +1519,5,10 +1520,1,1 +1521,2,2 +1522,3,3 +1523,4,4 +1524,5,5 +1525,1,6 +1526,2,7 +1527,3,8 +1528,4,9 +1529,5,10 +1530,1,1 +1531,2,2 +1532,3,3 +1533,4,4 +1534,5,5 +1535,1,6 +1536,2,7 +1537,3,8 +1538,4,9 +1539,5,10 +1540,1,1 +1541,2,2 +1542,3,3 +1543,4,4 +1544,5,5 +1545,1,6 +1546,2,7 +1547,3,8 +1548,4,9 +1549,5,10 +1550,1,1 +1551,2,2 +1552,3,3 +1553,4,4 +1554,5,5 +1555,1,6 +1556,2,7 +1557,3,8 +1558,4,9 +1559,5,10 +1560,1,1 +1561,2,2 +1562,3,3 +1563,4,4 +1564,5,5 +1565,1,6 +1566,2,7 +1567,3,8 +1568,4,9 +1569,5,10 +1570,1,1 +1571,2,2 +1572,3,3 +1573,4,4 +1574,5,5 +1575,1,6 +1576,2,7 +1577,3,8 +1578,4,9 +1579,5,10 +1580,1,1 +1581,2,2 +1582,3,3 +1583,4,4 +1584,5,5 +1585,1,6 +1586,2,7 +1587,3,8 +1588,4,9 +1589,5,10 +1590,1,1 +1591,2,2 +1592,3,3 +1593,4,4 +1594,5,5 +1595,1,6 +1596,2,7 +1597,3,8 +1598,4,9 +1599,5,10 +1600,1,1 +1601,2,2 +1602,3,3 +1603,4,4 +1604,5,5 +1605,1,6 +1606,2,7 +1607,3,8 +1608,4,9 +1609,5,10 +1610,1,1 +1611,2,2 +1612,3,3 +1613,4,4 +1614,5,5 +1615,1,6 +1616,2,7 +1617,3,8 +1618,4,9 +1619,5,10 +1620,1,1 +1621,2,2 +1622,3,3 +1623,4,4 +1624,5,5 +1625,1,6 +1626,2,7 +1627,3,8 +1628,4,9 +1629,5,10 +1630,1,1 +1631,2,2 +1632,3,3 +1633,4,4 +1634,5,5 +1635,1,6 +1636,2,7 +1637,3,8 +1638,4,9 +1639,5,10 +1640,1,1 +1641,2,2 +1642,3,3 +1643,4,4 +1644,5,5 +1645,1,6 +1646,2,7 +1647,3,8 +1648,4,9 +1649,5,10 +1650,1,1 +1651,2,2 +1652,3,3 +1653,4,4 +1654,5,5 +1655,1,6 +1656,2,7 +1657,3,8 +1658,4,9 +1659,5,10 +1660,1,1 +1661,2,2 +1662,3,3 +1663,4,4 +1664,5,5 +1665,1,6 +1666,2,7 +1667,3,8 +1668,4,9 +1669,5,10 +1670,1,1 +1671,2,2 +1672,3,3 +1673,4,4 +1674,5,5 +1675,1,6 +1676,2,7 +1677,3,8 +1678,4,9 +1679,5,10 +1680,1,1 +1681,2,2 +1682,3,3 +1683,4,4 +1684,5,5 +1685,1,6 +1686,2,7 +1687,3,8 +1688,4,9 +1689,5,10 +1690,1,1 +1691,2,2 +1692,3,3 +1693,4,4 +1694,5,5 +1695,1,6 +1696,2,7 +1697,3,8 +1698,4,9 +1699,5,10 +1700,1,1 +1701,2,2 +1702,3,3 +1703,4,4 +1704,5,5 +1705,1,6 +1706,2,7 +1707,3,8 +1708,4,9 +1709,5,10 +1710,1,1 +1711,2,2 +1712,3,3 +1713,4,4 +1714,5,5 +1715,1,6 +1716,2,7 +1717,3,8 +1718,4,9 +1719,5,10 +1720,1,1 +1721,2,2 +1722,3,3 +1723,4,4 +1724,5,5 +1725,1,6 +1726,2,7 +1727,3,8 +1728,4,9 +1729,5,10 +1730,1,1 +1731,2,2 +1732,3,3 +1733,4,4 +1734,5,5 +1735,1,6 +1736,2,7 +1737,3,8 +1738,4,9 +1739,5,10 +1740,1,1 +1741,2,2 +1742,3,3 +1743,4,4 +1744,5,5 +1745,1,6 +1746,2,7 +1747,3,8 +1748,4,9 +1749,5,10 +1750,1,1 +1751,2,2 +1752,3,3 +1753,4,4 +1754,5,5 +1755,1,6 +1756,2,7 +1757,3,8 +1758,4,9 +1759,5,10 +1760,1,1 +1761,2,2 +1762,3,3 +1763,4,4 +1764,5,5 +1765,1,6 +1766,2,7 +1767,3,8 +1768,4,9 +1769,5,10 +1770,1,1 +1771,2,2 +1772,3,3 +1773,4,4 +1774,5,5 +1775,1,6 +1776,2,7 +1777,3,8 +1778,4,9 +1779,5,10 +1780,1,1 +1781,2,2 +1782,3,3 +1783,4,4 +1784,5,5 +1785,1,6 +1786,2,7 +1787,3,8 +1788,4,9 +1789,5,10 +1790,1,1 +1791,2,2 +1792,3,3 +1793,4,4 +1794,5,5 +1795,1,6 +1796,2,7 +1797,3,8 +1798,4,9 +1799,5,10 +1800,1,1 +1801,2,2 +1802,3,3 +1803,4,4 +1804,5,5 +1805,1,6 +1806,2,7 +1807,3,8 +1808,4,9 +1809,5,10 +1810,1,1 +1811,2,2 +1812,3,3 +1813,4,4 +1814,5,5 +1815,1,6 +1816,2,7 +1817,3,8 +1818,4,9 +1819,5,10 +1820,1,1 +1821,2,2 +1822,3,3 +1823,4,4 +1824,5,5 +1825,1,6 +1826,2,7 +1827,3,8 +1828,4,9 +1829,5,10 +1830,1,1 +1831,2,2 +1832,3,3 +1833,4,4 +1834,5,5 +1835,1,6 +1836,2,7 +1837,3,8 +1838,4,9 +1839,5,10 +1840,1,1 +1841,2,2 +1842,3,3 +1843,4,4 +1844,5,5 +1845,1,6 +1846,2,7 +1847,3,8 +1848,4,9 +1849,5,10 +1850,1,1 +1851,2,2 +1852,3,3 +1853,4,4 +1854,5,5 +1855,1,6 +1856,2,7 +1857,3,8 +1858,4,9 +1859,5,10 +1860,1,1 +1861,2,2 +1862,3,3 +1863,4,4 +1864,5,5 +1865,1,6 +1866,2,7 +1867,3,8 +1868,4,9 +1869,5,10 +1870,1,1 +1871,2,2 +1872,3,3 +1873,4,4 +1874,5,5 +1875,1,6 +1876,2,7 +1877,3,8 +1878,4,9 +1879,5,10 +1880,1,1 +1881,2,2 +1882,3,3 +1883,4,4 +1884,5,5 +1885,1,6 +1886,2,7 +1887,3,8 +1888,4,9 +1889,5,10 +1890,1,1 +1891,2,2 +1892,3,3 +1893,4,4 +1894,5,5 +1895,1,6 +1896,2,7 +1897,3,8 +1898,4,9 +1899,5,10 +1900,1,1 +1901,2,2 +1902,3,3 +1903,4,4 +1904,5,5 +1905,1,6 +1906,2,7 +1907,3,8 +1908,4,9 +1909,5,10 +1910,1,1 +1911,2,2 +1912,3,3 +1913,4,4 +1914,5,5 +1915,1,6 +1916,2,7 +1917,3,8 +1918,4,9 +1919,5,10 +1920,1,1 +1921,2,2 +1922,3,3 +1923,4,4 +1924,5,5 +1925,1,6 +1926,2,7 +1927,3,8 +1928,4,9 +1929,5,10 +1930,1,1 +1931,2,2 +1932,3,3 +1933,4,4 +1934,5,5 +1935,1,6 +1936,2,7 +1937,3,8 +1938,4,9 +1939,5,10 +1940,1,1 +1941,2,2 +1942,3,3 +1943,4,4 +1944,5,5 +1945,1,6 +1946,2,7 +1947,3,8 +1948,4,9 +1949,5,10 +1950,1,1 +1951,2,2 +1952,3,3 +1953,4,4 +1954,5,5 +1955,1,6 +1956,2,7 +1957,3,8 +1958,4,9 +1959,5,10 +1960,1,1 +1961,2,2 +1962,3,3 +1963,4,4 +1964,5,5 +1965,1,6 +1966,2,7 +1967,3,8 +1968,4,9 +1969,5,10 +1970,1,1 +1971,2,2 +1972,3,3 +1973,4,4 +1974,5,5 +1975,1,6 +1976,2,7 +1977,3,8 +1978,4,9 +1979,5,10 +1980,1,1 +1981,2,2 +1982,3,3 +1983,4,4 +1984,5,5 +1985,1,6 +1986,2,7 +1987,3,8 +1988,4,9 +1989,5,10 +1990,1,1 +1991,2,2 +1992,3,3 +1993,4,4 +1994,5,5 +1995,1,6 +1996,2,7 +1997,3,8 +1998,4,9 +1999,5,10 +2000,1,1 +2001,2,2 +2002,3,3 +2003,4,4 +2004,5,5 +2005,1,6 +2006,2,7 +2007,3,8 +2008,4,9 +2009,5,10 +2010,1,1 +2011,2,2 +2012,3,3 +2013,4,4 +2014,5,5 +2015,1,6 +2016,2,7 +2017,3,8 +2018,4,9 +2019,5,10 +2020,1,1 +2021,2,2 +2022,3,3 +2023,4,4 +2024,5,5 +2025,1,6 +2026,2,7 +2027,3,8 +2028,4,9 +2029,5,10 +2030,1,1 +2031,2,2 +2032,3,3 +2033,4,4 +2034,5,5 +2035,1,6 +2036,2,7 +2037,3,8 +2038,4,9 +2039,5,10 +2040,1,1 +2041,2,2 +2042,3,3 +2043,4,4 +2044,5,5 +2045,1,6 +2046,2,7 +2047,3,8 +2048,4,9 +2049,5,10 +2050,1,1 +2051,2,2 +2052,3,3 +2053,4,4 +2054,5,5 +2055,1,6 +2056,2,7 +2057,3,8 +2058,4,9 +2059,5,10 +2060,1,1 +2061,2,2 +2062,3,3 +2063,4,4 +2064,5,5 +2065,1,6 +2066,2,7 +2067,3,8 +2068,4,9 +2069,5,10 +2070,1,1 +2071,2,2 +2072,3,3 +2073,4,4 +2074,5,5 +2075,1,6 +2076,2,7 +2077,3,8 +2078,4,9 +2079,5,10 +2080,1,1 +2081,2,2 +2082,3,3 +2083,4,4 +2084,5,5 +2085,1,6 +2086,2,7 +2087,3,8 +2088,4,9 +2089,5,10 +2090,1,1 +2091,2,2 +2092,3,3 +2093,4,4 +2094,5,5 +2095,1,6 +2096,2,7 +2097,3,8 +2098,4,9 +2099,5,10 +2100,1,1 +2101,2,2 +2102,3,3 +2103,4,4 +2104,5,5 +2105,1,6 +2106,2,7 +2107,3,8 +2108,4,9 +2109,5,10 +2110,1,1 +2111,2,2 +2112,3,3 +2113,4,4 +2114,5,5 +2115,1,6 +2116,2,7 +2117,3,8 +2118,4,9 +2119,5,10 +2120,1,1 +2121,2,2 +2122,3,3 +2123,4,4 +2124,5,5 +2125,1,6 +2126,2,7 +2127,3,8 +2128,4,9 +2129,5,10 +2130,1,1 +2131,2,2 +2132,3,3 +2133,4,4 +2134,5,5 +2135,1,6 +2136,2,7 +2137,3,8 +2138,4,9 +2139,5,10 +2140,1,1 +2141,2,2 +2142,3,3 +2143,4,4 +2144,5,5 +2145,1,6 +2146,2,7 +2147,3,8 +2148,4,9 +2149,5,10 +2150,1,1 +2151,2,2 +2152,3,3 +2153,4,4 +2154,5,5 +2155,1,6 +2156,2,7 +2157,3,8 +2158,4,9 +2159,5,10 +2160,1,1 +2161,2,2 +2162,3,3 +2163,4,4 +2164,5,5 +2165,1,6 +2166,2,7 +2167,3,8 +2168,4,9 +2169,5,10 +2170,1,1 +2171,2,2 +2172,3,3 +2173,4,4 +2174,5,5 +2175,1,6 +2176,2,7 +2177,3,8 +2178,4,9 +2179,5,10 +2180,1,1 +2181,2,2 +2182,3,3 +2183,4,4 +2184,5,5 +2185,1,6 +2186,2,7 +2187,3,8 +2188,4,9 +2189,5,10 +2190,1,1 +2191,2,2 +2192,3,3 +2193,4,4 +2194,5,5 +2195,1,6 +2196,2,7 +2197,3,8 +2198,4,9 +2199,5,10 +2200,1,1 +2201,2,2 +2202,3,3 +2203,4,4 +2204,5,5 +2205,1,6 +2206,2,7 +2207,3,8 +2208,4,9 +2209,5,10 +2210,1,1 +2211,2,2 +2212,3,3 +2213,4,4 +2214,5,5 +2215,1,6 +2216,2,7 +2217,3,8 +2218,4,9 +2219,5,10 +2220,1,1 +2221,2,2 +2222,3,3 +2223,4,4 +2224,5,5 +2225,1,6 +2226,2,7 +2227,3,8 +2228,4,9 +2229,5,10 +2230,1,1 +2231,2,2 +2232,3,3 +2233,4,4 +2234,5,5 +2235,1,6 +2236,2,7 +2237,3,8 +2238,4,9 +2239,5,10 +2240,1,1 +2241,2,2 +2242,3,3 +2243,4,4 +2244,5,5 +2245,1,6 +2246,2,7 +2247,3,8 +2248,4,9 +2249,5,10 +2250,1,1 +2251,2,2 +2252,3,3 +2253,4,4 +2254,5,5 +2255,1,6 +2256,2,7 +2257,3,8 +2258,4,9 +2259,5,10 +2260,1,1 +2261,2,2 +2262,3,3 +2263,4,4 +2264,5,5 +2265,1,6 +2266,2,7 +2267,3,8 +2268,4,9 +2269,5,10 +2270,1,1 +2271,2,2 +2272,3,3 +2273,4,4 +2274,5,5 +2275,1,6 +2276,2,7 +2277,3,8 +2278,4,9 +2279,5,10 +2280,1,1 +2281,2,2 +2282,3,3 +2283,4,4 +2284,5,5 +2285,1,6 +2286,2,7 +2287,3,8 +2288,4,9 +2289,5,10 +2290,1,1 +2291,2,2 +2292,3,3 +2293,4,4 +2294,5,5 +2295,1,6 +2296,2,7 +2297,3,8 +2298,4,9 +2299,5,10 +2300,1,1 +2301,2,2 +2302,3,3 +2303,4,4 +2304,5,5 +2305,1,6 +2306,2,7 +2307,3,8 +2308,4,9 +2309,5,10 +2310,1,1 +2311,2,2 +2312,3,3 +2313,4,4 +2314,5,5 +2315,1,6 +2316,2,7 +2317,3,8 +2318,4,9 +2319,5,10 +2320,1,1 +2321,2,2 +2322,3,3 +2323,4,4 +2324,5,5 +2325,1,6 +2326,2,7 +2327,3,8 +2328,4,9 +2329,5,10 +2330,1,1 +2331,2,2 +2332,3,3 +2333,4,4 +2334,5,5 +2335,1,6 +2336,2,7 +2337,3,8 +2338,4,9 +2339,5,10 +2340,1,1 +2341,2,2 +2342,3,3 +2343,4,4 +2344,5,5 +2345,1,6 +2346,2,7 +2347,3,8 +2348,4,9 +2349,5,10 +2350,1,1 +2351,2,2 +2352,3,3 +2353,4,4 +2354,5,5 +2355,1,6 +2356,2,7 +2357,3,8 +2358,4,9 +2359,5,10 +2360,1,1 +2361,2,2 +2362,3,3 +2363,4,4 +2364,5,5 +2365,1,6 +2366,2,7 +2367,3,8 +2368,4,9 +2369,5,10 +2370,1,1 +2371,2,2 +2372,3,3 +2373,4,4 +2374,5,5 +2375,1,6 +2376,2,7 +2377,3,8 +2378,4,9 +2379,5,10 +2380,1,1 +2381,2,2 +2382,3,3 +2383,4,4 +2384,5,5 +2385,1,6 +2386,2,7 +2387,3,8 +2388,4,9 +2389,5,10 +2390,1,1 +2391,2,2 +2392,3,3 +2393,4,4 +2394,5,5 +2395,1,6 +2396,2,7 +2397,3,8 +2398,4,9 +2399,5,10 +2400,1,1 +2401,2,2 +2402,3,3 +2403,4,4 +2404,5,5 +2405,1,6 +2406,2,7 +2407,3,8 +2408,4,9 +2409,5,10 +2410,1,1 +2411,2,2 +2412,3,3 +2413,4,4 +2414,5,5 +2415,1,6 +2416,2,7 +2417,3,8 +2418,4,9 +2419,5,10 +2420,1,1 +2421,2,2 +2422,3,3 +2423,4,4 +2424,5,5 +2425,1,6 +2426,2,7 +2427,3,8 +2428,4,9 +2429,5,10 +2430,1,1 +2431,2,2 +2432,3,3 +2433,4,4 +2434,5,5 +2435,1,6 +2436,2,7 +2437,3,8 +2438,4,9 +2439,5,10 +2440,1,1 +2441,2,2 +2442,3,3 +2443,4,4 +2444,5,5 +2445,1,6 +2446,2,7 +2447,3,8 +2448,4,9 +2449,5,10 +2450,1,1 +2451,2,2 +2452,3,3 +2453,4,4 +2454,5,5 +2455,1,6 +2456,2,7 +2457,3,8 +2458,4,9 +2459,5,10 +2460,1,1 +2461,2,2 +2462,3,3 +2463,4,4 +2464,5,5 +2465,1,6 +2466,2,7 +2467,3,8 +2468,4,9 +2469,5,10 +2470,1,1 +2471,2,2 +2472,3,3 +2473,4,4 +2474,5,5 +2475,1,6 +2476,2,7 +2477,3,8 +2478,4,9 +2479,5,10 +2480,1,1 +2481,2,2 +2482,3,3 +2483,4,4 +2484,5,5 +2485,1,6 +2486,2,7 +2487,3,8 +2488,4,9 +2489,5,10 +2490,1,1 +2491,2,2 +2492,3,3 +2493,4,4 +2494,5,5 +2495,1,6 +2496,2,7 +2497,3,8 +2498,4,9 +2499,5,10 +2500,1,1 +2501,2,2 +2502,3,3 +2503,4,4 +2504,5,5 +2505,1,6 +2506,2,7 +2507,3,8 +2508,4,9 +2509,5,10 +2510,1,1 +2511,2,2 +2512,3,3 +2513,4,4 +2514,5,5 +2515,1,6 +2516,2,7 +2517,3,8 +2518,4,9 +2519,5,10 +2520,1,1 +2521,2,2 +2522,3,3 +2523,4,4 +2524,5,5 +2525,1,6 +2526,2,7 +2527,3,8 +2528,4,9 +2529,5,10 +2530,1,1 +2531,2,2 +2532,3,3 +2533,4,4 +2534,5,5 +2535,1,6 +2536,2,7 +2537,3,8 +2538,4,9 +2539,5,10 +2540,1,1 +2541,2,2 +2542,3,3 +2543,4,4 +2544,5,5 +2545,1,6 +2546,2,7 +2547,3,8 +2548,4,9 +2549,5,10 +2550,1,1 +2551,2,2 +2552,3,3 +2553,4,4 +2554,5,5 +2555,1,6 +2556,2,7 +2557,3,8 +2558,4,9 +2559,5,10 +2560,1,1 +2561,2,2 +2562,3,3 +2563,4,4 +2564,5,5 +2565,1,6 +2566,2,7 +2567,3,8 +2568,4,9 +2569,5,10 +2570,1,1 +2571,2,2 +2572,3,3 +2573,4,4 +2574,5,5 +2575,1,6 +2576,2,7 +2577,3,8 +2578,4,9 +2579,5,10 +2580,1,1 +2581,2,2 +2582,3,3 +2583,4,4 +2584,5,5 +2585,1,6 +2586,2,7 +2587,3,8 +2588,4,9 +2589,5,10 +2590,1,1 +2591,2,2 +2592,3,3 +2593,4,4 +2594,5,5 +2595,1,6 +2596,2,7 +2597,3,8 +2598,4,9 +2599,5,10 +2600,1,1 +2601,2,2 +2602,3,3 +2603,4,4 +2604,5,5 +2605,1,6 +2606,2,7 +2607,3,8 +2608,4,9 +2609,5,10 +2610,1,1 +2611,2,2 +2612,3,3 +2613,4,4 +2614,5,5 +2615,1,6 +2616,2,7 +2617,3,8 +2618,4,9 +2619,5,10 +2620,1,1 +2621,2,2 +2622,3,3 +2623,4,4 +2624,5,5 +2625,1,6 +2626,2,7 +2627,3,8 +2628,4,9 +2629,5,10 +2630,1,1 +2631,2,2 +2632,3,3 +2633,4,4 +2634,5,5 +2635,1,6 +2636,2,7 +2637,3,8 +2638,4,9 +2639,5,10 +2640,1,1 +2641,2,2 +2642,3,3 +2643,4,4 +2644,5,5 +2645,1,6 +2646,2,7 +2647,3,8 +2648,4,9 +2649,5,10 +2650,1,1 +2651,2,2 +2652,3,3 +2653,4,4 +2654,5,5 +2655,1,6 +2656,2,7 +2657,3,8 +2658,4,9 +2659,5,10 +2660,1,1 +2661,2,2 +2662,3,3 +2663,4,4 +2664,5,5 +2665,1,6 +2666,2,7 +2667,3,8 +2668,4,9 +2669,5,10 +2670,1,1 +2671,2,2 +2672,3,3 +2673,4,4 +2674,5,5 +2675,1,6 +2676,2,7 +2677,3,8 +2678,4,9 +2679,5,10 +2680,1,1 +2681,2,2 +2682,3,3 +2683,4,4 +2684,5,5 +2685,1,6 +2686,2,7 +2687,3,8 +2688,4,9 +2689,5,10 +2690,1,1 +2691,2,2 +2692,3,3 +2693,4,4 +2694,5,5 +2695,1,6 +2696,2,7 +2697,3,8 +2698,4,9 +2699,5,10 +2700,1,1 +2701,2,2 +2702,3,3 +2703,4,4 +2704,5,5 +2705,1,6 +2706,2,7 +2707,3,8 +2708,4,9 +2709,5,10 +2710,1,1 +2711,2,2 +2712,3,3 +2713,4,4 +2714,5,5 +2715,1,6 +2716,2,7 +2717,3,8 +2718,4,9 +2719,5,10 +2720,1,1 +2721,2,2 +2722,3,3 +2723,4,4 +2724,5,5 +2725,1,6 +2726,2,7 +2727,3,8 +2728,4,9 +2729,5,10 +2730,1,1 +2731,2,2 +2732,3,3 +2733,4,4 +2734,5,5 +2735,1,6 +2736,2,7 +2737,3,8 +2738,4,9 +2739,5,10 +2740,1,1 +2741,2,2 +2742,3,3 +2743,4,4 +2744,5,5 +2745,1,6 +2746,2,7 +2747,3,8 +2748,4,9 +2749,5,10 +2750,1,1 +2751,2,2 +2752,3,3 +2753,4,4 +2754,5,5 +2755,1,6 +2756,2,7 +2757,3,8 +2758,4,9 +2759,5,10 +2760,1,1 +2761,2,2 +2762,3,3 +2763,4,4 +2764,5,5 +2765,1,6 +2766,2,7 +2767,3,8 +2768,4,9 +2769,5,10 +2770,1,1 +2771,2,2 +2772,3,3 +2773,4,4 +2774,5,5 +2775,1,6 +2776,2,7 +2777,3,8 +2778,4,9 +2779,5,10 +2780,1,1 +2781,2,2 +2782,3,3 +2783,4,4 +2784,5,5 +2785,1,6 +2786,2,7 +2787,3,8 +2788,4,9 +2789,5,10 +2790,1,1 +2791,2,2 +2792,3,3 +2793,4,4 +2794,5,5 +2795,1,6 +2796,2,7 +2797,3,8 +2798,4,9 +2799,5,10 +2800,1,1 +2801,2,2 +2802,3,3 +2803,4,4 +2804,5,5 +2805,1,6 +2806,2,7 +2807,3,8 +2808,4,9 +2809,5,10 +2810,1,1 +2811,2,2 +2812,3,3 +2813,4,4 +2814,5,5 +2815,1,6 +2816,2,7 +2817,3,8 +2818,4,9 +2819,5,10 +2820,1,1 +2821,2,2 +2822,3,3 +2823,4,4 +2824,5,5 +2825,1,6 +2826,2,7 +2827,3,8 +2828,4,9 +2829,5,10 +2830,1,1 +2831,2,2 +2832,3,3 +2833,4,4 +2834,5,5 +2835,1,6 +2836,2,7 +2837,3,8 +2838,4,9 +2839,5,10 +2840,1,1 +2841,2,2 +2842,3,3 +2843,4,4 +2844,5,5 +2845,1,6 +2846,2,7 +2847,3,8 +2848,4,9 +2849,5,10 +2850,1,1 +2851,2,2 +2852,3,3 +2853,4,4 +2854,5,5 +2855,1,6 +2856,2,7 +2857,3,8 +2858,4,9 +2859,5,10 +2860,1,1 +2861,2,2 +2862,3,3 +2863,4,4 +2864,5,5 +2865,1,6 +2866,2,7 +2867,3,8 +2868,4,9 +2869,5,10 +2870,1,1 +2871,2,2 +2872,3,3 +2873,4,4 +2874,5,5 +2875,1,6 +2876,2,7 +2877,3,8 +2878,4,9 +2879,5,10 +2880,1,1 +2881,2,2 +2882,3,3 +2883,4,4 +2884,5,5 +2885,1,6 +2886,2,7 +2887,3,8 +2888,4,9 +2889,5,10 +2890,1,1 +2891,2,2 +2892,3,3 +2893,4,4 +2894,5,5 +2895,1,6 +2896,2,7 +2897,3,8 +2898,4,9 +2899,5,10 +2900,1,1 +2901,2,2 +2902,3,3 +2903,4,4 +2904,5,5 +2905,1,6 +2906,2,7 +2907,3,8 +2908,4,9 +2909,5,10 +2910,1,1 +2911,2,2 +2912,3,3 +2913,4,4 +2914,5,5 +2915,1,6 +2916,2,7 +2917,3,8 +2918,4,9 +2919,5,10 +2920,1,1 +2921,2,2 +2922,3,3 +2923,4,4 +2924,5,5 +2925,1,6 +2926,2,7 +2927,3,8 +2928,4,9 +2929,5,10 +2930,1,1 +2931,2,2 +2932,3,3 +2933,4,4 +2934,5,5 +2935,1,6 +2936,2,7 +2937,3,8 +2938,4,9 +2939,5,10 +2940,1,1 +2941,2,2 +2942,3,3 +2943,4,4 +2944,5,5 +2945,1,6 +2946,2,7 +2947,3,8 +2948,4,9 +2949,5,10 +2950,1,1 +2951,2,2 +2952,3,3 +2953,4,4 +2954,5,5 +2955,1,6 +2956,2,7 +2957,3,8 +2958,4,9 +2959,5,10 +2960,1,1 +2961,2,2 +2962,3,3 +2963,4,4 +2964,5,5 +2965,1,6 +2966,2,7 +2967,3,8 +2968,4,9 +2969,5,10 +2970,1,1 +2971,2,2 +2972,3,3 +2973,4,4 +2974,5,5 +2975,1,6 +2976,2,7 +2977,3,8 +2978,4,9 +2979,5,10 +2980,1,1 +2981,2,2 +2982,3,3 +2983,4,4 +2984,5,5 +2985,1,6 +2986,2,7 +2987,3,8 +2988,4,9 +2989,5,10 +2990,1,1 +2991,2,2 +2992,3,3 +2993,4,4 +2994,5,5 +2995,1,6 +2996,2,7 +2997,3,8 +2998,4,9 +2999,5,10 +3000,1,1 +3001,2,2 +3002,3,3 +3003,4,4 +3004,5,5 +3005,1,6 +3006,2,7 +3007,3,8 +3008,4,9 +3009,5,10 +3010,1,1 +3011,2,2 +3012,3,3 +3013,4,4 +3014,5,5 +3015,1,6 +3016,2,7 +3017,3,8 +3018,4,9 +3019,5,10 +3020,1,1 +3021,2,2 +3022,3,3 +3023,4,4 +3024,5,5 +3025,1,6 +3026,2,7 +3027,3,8 +3028,4,9 +3029,5,10 +3030,1,1 +3031,2,2 +3032,3,3 +3033,4,4 +3034,5,5 +3035,1,6 +3036,2,7 +3037,3,8 +3038,4,9 +3039,5,10 +3040,1,1 +3041,2,2 +3042,3,3 +3043,4,4 +3044,5,5 +3045,1,6 +3046,2,7 +3047,3,8 +3048,4,9 +3049,5,10 +3050,1,1 +3051,2,2 +3052,3,3 +3053,4,4 +3054,5,5 +3055,1,6 +3056,2,7 +3057,3,8 +3058,4,9 +3059,5,10 +3060,1,1 +3061,2,2 +3062,3,3 +3063,4,4 +3064,5,5 +3065,1,6 +3066,2,7 +3067,3,8 +3068,4,9 +3069,5,10 +3070,1,1 +3071,2,2 +3072,3,3 +3073,4,4 +3074,5,5 +3075,1,6 +3076,2,7 +3077,3,8 +3078,4,9 +3079,5,10 +3080,1,1 +3081,2,2 +3082,3,3 +3083,4,4 +3084,5,5 +3085,1,6 +3086,2,7 +3087,3,8 +3088,4,9 +3089,5,10 +3090,1,1 +3091,2,2 +3092,3,3 +3093,4,4 +3094,5,5 +3095,1,6 +3096,2,7 +3097,3,8 +3098,4,9 +3099,5,10 +3100,1,1 +3101,2,2 +3102,3,3 +3103,4,4 +3104,5,5 +3105,1,6 +3106,2,7 +3107,3,8 +3108,4,9 +3109,5,10 +3110,1,1 +3111,2,2 +3112,3,3 +3113,4,4 +3114,5,5 +3115,1,6 +3116,2,7 +3117,3,8 +3118,4,9 +3119,5,10 +3120,1,1 +3121,2,2 +3122,3,3 +3123,4,4 +3124,5,5 +3125,1,6 +3126,2,7 +3127,3,8 +3128,4,9 +3129,5,10 +3130,1,1 +3131,2,2 +3132,3,3 +3133,4,4 +3134,5,5 +3135,1,6 +3136,2,7 +3137,3,8 +3138,4,9 +3139,5,10 +3140,1,1 +3141,2,2 +3142,3,3 +3143,4,4 +3144,5,5 +3145,1,6 +3146,2,7 +3147,3,8 +3148,4,9 +3149,5,10 +3150,1,1 +3151,2,2 +3152,3,3 +3153,4,4 +3154,5,5 +3155,1,6 +3156,2,7 +3157,3,8 +3158,4,9 +3159,5,10 +3160,1,1 +3161,2,2 +3162,3,3 +3163,4,4 +3164,5,5 +3165,1,6 +3166,2,7 +3167,3,8 +3168,4,9 +3169,5,10 +3170,1,1 +3171,2,2 +3172,3,3 +3173,4,4 +3174,5,5 +3175,1,6 +3176,2,7 +3177,3,8 +3178,4,9 +3179,5,10 +3180,1,1 +3181,2,2 +3182,3,3 +3183,4,4 +3184,5,5 +3185,1,6 +3186,2,7 +3187,3,8 +3188,4,9 +3189,5,10 +3190,1,1 +3191,2,2 +3192,3,3 +3193,4,4 +3194,5,5 +3195,1,6 +3196,2,7 +3197,3,8 +3198,4,9 +3199,5,10 +3200,1,1 +3201,2,2 +3202,3,3 +3203,4,4 +3204,5,5 +3205,1,6 +3206,2,7 +3207,3,8 +3208,4,9 +3209,5,10 +3210,1,1 +3211,2,2 +3212,3,3 +3213,4,4 +3214,5,5 +3215,1,6 +3216,2,7 +3217,3,8 +3218,4,9 +3219,5,10 +3220,1,1 +3221,2,2 +3222,3,3 +3223,4,4 +3224,5,5 +3225,1,6 +3226,2,7 +3227,3,8 +3228,4,9 +3229,5,10 +3230,1,1 +3231,2,2 +3232,3,3 +3233,4,4 +3234,5,5 +3235,1,6 +3236,2,7 +3237,3,8 +3238,4,9 +3239,5,10 +3240,1,1 +3241,2,2 +3242,3,3 +3243,4,4 +3244,5,5 +3245,1,6 +3246,2,7 +3247,3,8 +3248,4,9 +3249,5,10 +3250,1,1 +3251,2,2 +3252,3,3 +3253,4,4 +3254,5,5 +3255,1,6 +3256,2,7 +3257,3,8 +3258,4,9 +3259,5,10 +3260,1,1 +3261,2,2 +3262,3,3 +3263,4,4 +3264,5,5 +3265,1,6 +3266,2,7 +3267,3,8 +3268,4,9 +3269,5,10 +3270,1,1 +3271,2,2 +3272,3,3 +3273,4,4 +3274,5,5 +3275,1,6 +3276,2,7 +3277,3,8 +3278,4,9 +3279,5,10 +3280,1,1 +3281,2,2 +3282,3,3 +3283,4,4 +3284,5,5 +3285,1,6 +3286,2,7 +3287,3,8 +3288,4,9 +3289,5,10 +3290,1,1 +3291,2,2 +3292,3,3 +3293,4,4 +3294,5,5 +3295,1,6 +3296,2,7 +3297,3,8 +3298,4,9 +3299,5,10 +3300,1,1 +3301,2,2 +3302,3,3 +3303,4,4 +3304,5,5 +3305,1,6 +3306,2,7 +3307,3,8 +3308,4,9 +3309,5,10 +3310,1,1 +3311,2,2 +3312,3,3 +3313,4,4 +3314,5,5 +3315,1,6 +3316,2,7 +3317,3,8 +3318,4,9 +3319,5,10 +3320,1,1 +3321,2,2 +3322,3,3 +3323,4,4 +3324,5,5 +3325,1,6 +3326,2,7 +3327,3,8 +3328,4,9 +3329,5,10 +3330,1,1 +3331,2,2 +3332,3,3 +3333,4,4 +3334,5,5 +3335,1,6 +3336,2,7 +3337,3,8 +3338,4,9 +3339,5,10 +3340,1,1 +3341,2,2 +3342,3,3 +3343,4,4 +3344,5,5 +3345,1,6 +3346,2,7 +3347,3,8 +3348,4,9 +3349,5,10 +3350,1,1 +3351,2,2 +3352,3,3 +3353,4,4 +3354,5,5 +3355,1,6 +3356,2,7 +3357,3,8 +3358,4,9 +3359,5,10 +3360,1,1 +3361,2,2 +3362,3,3 +3363,4,4 +3364,5,5 +3365,1,6 +3366,2,7 +3367,3,8 +3368,4,9 +3369,5,10 +3370,1,1 +3371,2,2 +3372,3,3 +3373,4,4 +3374,5,5 +3375,1,6 +3376,2,7 +3377,3,8 +3378,4,9 +3379,5,10 +3380,1,1 +3381,2,2 +3382,3,3 +3383,4,4 +3384,5,5 +3385,1,6 +3386,2,7 +3387,3,8 +3388,4,9 +3389,5,10 +3390,1,1 +3391,2,2 +3392,3,3 +3393,4,4 +3394,5,5 +3395,1,6 +3396,2,7 +3397,3,8 +3398,4,9 +3399,5,10 +3400,1,1 +3401,2,2 +3402,3,3 +3403,4,4 +3404,5,5 +3405,1,6 +3406,2,7 +3407,3,8 +3408,4,9 +3409,5,10 +3410,1,1 +3411,2,2 +3412,3,3 +3413,4,4 +3414,5,5 +3415,1,6 +3416,2,7 +3417,3,8 +3418,4,9 +3419,5,10 +3420,1,1 +3421,2,2 +3422,3,3 +3423,4,4 +3424,5,5 +3425,1,6 +3426,2,7 +3427,3,8 +3428,4,9 +3429,5,10 +3430,1,1 +3431,2,2 +3432,3,3 +3433,4,4 +3434,5,5 +3435,1,6 +3436,2,7 +3437,3,8 +3438,4,9 +3439,5,10 +3440,1,1 +3441,2,2 +3442,3,3 +3443,4,4 +3444,5,5 +3445,1,6 +3446,2,7 +3447,3,8 +3448,4,9 +3449,5,10 +3450,1,1 +3451,2,2 +3452,3,3 +3453,4,4 +3454,5,5 +3455,1,6 +3456,2,7 +3457,3,8 +3458,4,9 +3459,5,10 +3460,1,1 +3461,2,2 +3462,3,3 +3463,4,4 +3464,5,5 +3465,1,6 +3466,2,7 +3467,3,8 +3468,4,9 +3469,5,10 +3470,1,1 +3471,2,2 +3472,3,3 +3473,4,4 +3474,5,5 +3475,1,6 +3476,2,7 +3477,3,8 +3478,4,9 +3479,5,10 +3480,1,1 +3481,2,2 +3482,3,3 +3483,4,4 +3484,5,5 +3485,1,6 +3486,2,7 +3487,3,8 +3488,4,9 +3489,5,10 +3490,1,1 +3491,2,2 +3492,3,3 +3493,4,4 +3494,5,5 +3495,1,6 +3496,2,7 +3497,3,8 +3498,4,9 +3499,5,10 +3500,1,1 +3501,2,2 +3502,3,3 +3503,4,4 +3504,5,5 +3505,1,6 +3506,2,7 +3507,3,8 +3508,4,9 +3509,5,10 +3510,1,1 +3511,2,2 +3512,3,3 +3513,4,4 +3514,5,5 +3515,1,6 +3516,2,7 +3517,3,8 +3518,4,9 +3519,5,10 +3520,1,1 +3521,2,2 +3522,3,3 +3523,4,4 +3524,5,5 +3525,1,6 +3526,2,7 +3527,3,8 +3528,4,9 +3529,5,10 +3530,1,1 +3531,2,2 +3532,3,3 +3533,4,4 +3534,5,5 +3535,1,6 +3536,2,7 +3537,3,8 +3538,4,9 +3539,5,10 +3540,1,1 +3541,2,2 +3542,3,3 +3543,4,4 +3544,5,5 +3545,1,6 +3546,2,7 +3547,3,8 +3548,4,9 +3549,5,10 +3550,1,1 +3551,2,2 +3552,3,3 +3553,4,4 +3554,5,5 +3555,1,6 +3556,2,7 +3557,3,8 +3558,4,9 +3559,5,10 +3560,1,1 +3561,2,2 +3562,3,3 +3563,4,4 +3564,5,5 +3565,1,6 +3566,2,7 +3567,3,8 +3568,4,9 +3569,5,10 +3570,1,1 +3571,2,2 +3572,3,3 +3573,4,4 +3574,5,5 +3575,1,6 +3576,2,7 +3577,3,8 +3578,4,9 +3579,5,10 +3580,1,1 +3581,2,2 +3582,3,3 +3583,4,4 +3584,5,5 +3585,1,6 +3586,2,7 +3587,3,8 +3588,4,9 +3589,5,10 +3590,1,1 +3591,2,2 +3592,3,3 +3593,4,4 +3594,5,5 +3595,1,6 +3596,2,7 +3597,3,8 +3598,4,9 +3599,5,10 +3600,1,1 +3601,2,2 +3602,3,3 +3603,4,4 +3604,5,5 +3605,1,6 +3606,2,7 +3607,3,8 +3608,4,9 +3609,5,10 +3610,1,1 +3611,2,2 +3612,3,3 +3613,4,4 +3614,5,5 +3615,1,6 +3616,2,7 +3617,3,8 +3618,4,9 +3619,5,10 +3620,1,1 +3621,2,2 +3622,3,3 +3623,4,4 +3624,5,5 +3625,1,6 +3626,2,7 +3627,3,8 +3628,4,9 +3629,5,10 +3630,1,1 +3631,2,2 +3632,3,3 +3633,4,4 +3634,5,5 +3635,1,6 +3636,2,7 +3637,3,8 +3638,4,9 +3639,5,10 +3640,1,1 +3641,2,2 +3642,3,3 +3643,4,4 +3644,5,5 +3645,1,6 +3646,2,7 +3647,3,8 +3648,4,9 +3649,5,10 +3650,1,1 +3651,2,2 +3652,3,3 +3653,4,4 +3654,5,5 +3655,1,6 +3656,2,7 +3657,3,8 +3658,4,9 +3659,5,10 +3660,1,1 +3661,2,2 +3662,3,3 +3663,4,4 +3664,5,5 +3665,1,6 +3666,2,7 +3667,3,8 +3668,4,9 +3669,5,10 +3670,1,1 +3671,2,2 +3672,3,3 +3673,4,4 +3674,5,5 +3675,1,6 +3676,2,7 +3677,3,8 +3678,4,9 +3679,5,10 +3680,1,1 +3681,2,2 +3682,3,3 +3683,4,4 +3684,5,5 +3685,1,6 +3686,2,7 +3687,3,8 +3688,4,9 +3689,5,10 +3690,1,1 +3691,2,2 +3692,3,3 +3693,4,4 +3694,5,5 +3695,1,6 +3696,2,7 +3697,3,8 +3698,4,9 +3699,5,10 +3700,1,1 +3701,2,2 +3702,3,3 +3703,4,4 +3704,5,5 +3705,1,6 +3706,2,7 +3707,3,8 +3708,4,9 +3709,5,10 +3710,1,1 +3711,2,2 +3712,3,3 +3713,4,4 +3714,5,5 +3715,1,6 +3716,2,7 +3717,3,8 +3718,4,9 +3719,5,10 +3720,1,1 +3721,2,2 +3722,3,3 +3723,4,4 +3724,5,5 +3725,1,6 +3726,2,7 +3727,3,8 +3728,4,9 +3729,5,10 +3730,1,1 +3731,2,2 +3732,3,3 +3733,4,4 +3734,5,5 +3735,1,6 +3736,2,7 +3737,3,8 +3738,4,9 +3739,5,10 +3740,1,1 +3741,2,2 +3742,3,3 +3743,4,4 +3744,5,5 +3745,1,6 +3746,2,7 +3747,3,8 +3748,4,9 +3749,5,10 +3750,1,1 +3751,2,2 +3752,3,3 +3753,4,4 +3754,5,5 +3755,1,6 +3756,2,7 +3757,3,8 +3758,4,9 +3759,5,10 +3760,1,1 +3761,2,2 +3762,3,3 +3763,4,4 +3764,5,5 +3765,1,6 +3766,2,7 +3767,3,8 +3768,4,9 +3769,5,10 +3770,1,1 +3771,2,2 +3772,3,3 +3773,4,4 +3774,5,5 +3775,1,6 +3776,2,7 +3777,3,8 +3778,4,9 +3779,5,10 +3780,1,1 +3781,2,2 +3782,3,3 +3783,4,4 +3784,5,5 +3785,1,6 +3786,2,7 +3787,3,8 +3788,4,9 +3789,5,10 +3790,1,1 +3791,2,2 +3792,3,3 +3793,4,4 +3794,5,5 +3795,1,6 +3796,2,7 +3797,3,8 +3798,4,9 +3799,5,10 +3800,1,1 +3801,2,2 +3802,3,3 +3803,4,4 +3804,5,5 +3805,1,6 +3806,2,7 +3807,3,8 +3808,4,9 +3809,5,10 +3810,1,1 +3811,2,2 +3812,3,3 +3813,4,4 +3814,5,5 +3815,1,6 +3816,2,7 +3817,3,8 +3818,4,9 +3819,5,10 +3820,1,1 +3821,2,2 +3822,3,3 +3823,4,4 +3824,5,5 +3825,1,6 +3826,2,7 +3827,3,8 +3828,4,9 +3829,5,10 +3830,1,1 +3831,2,2 +3832,3,3 +3833,4,4 +3834,5,5 +3835,1,6 +3836,2,7 +3837,3,8 +3838,4,9 +3839,5,10 +3840,1,1 +3841,2,2 +3842,3,3 +3843,4,4 +3844,5,5 +3845,1,6 +3846,2,7 +3847,3,8 +3848,4,9 +3849,5,10 +3850,1,1 +3851,2,2 +3852,3,3 +3853,4,4 +3854,5,5 +3855,1,6 +3856,2,7 +3857,3,8 +3858,4,9 +3859,5,10 +3860,1,1 +3861,2,2 +3862,3,3 +3863,4,4 +3864,5,5 +3865,1,6 +3866,2,7 +3867,3,8 +3868,4,9 +3869,5,10 +3870,1,1 +3871,2,2 +3872,3,3 +3873,4,4 +3874,5,5 +3875,1,6 +3876,2,7 +3877,3,8 +3878,4,9 +3879,5,10 +3880,1,1 +3881,2,2 +3882,3,3 +3883,4,4 +3884,5,5 +3885,1,6 +3886,2,7 +3887,3,8 +3888,4,9 +3889,5,10 +3890,1,1 +3891,2,2 +3892,3,3 +3893,4,4 +3894,5,5 +3895,1,6 +3896,2,7 +3897,3,8 +3898,4,9 +3899,5,10 +3900,1,1 +3901,2,2 +3902,3,3 +3903,4,4 +3904,5,5 +3905,1,6 +3906,2,7 +3907,3,8 +3908,4,9 +3909,5,10 +3910,1,1 +3911,2,2 +3912,3,3 +3913,4,4 +3914,5,5 +3915,1,6 +3916,2,7 +3917,3,8 +3918,4,9 +3919,5,10 +3920,1,1 +3921,2,2 +3922,3,3 +3923,4,4 +3924,5,5 +3925,1,6 +3926,2,7 +3927,3,8 +3928,4,9 +3929,5,10 +3930,1,1 +3931,2,2 +3932,3,3 +3933,4,4 +3934,5,5 +3935,1,6 +3936,2,7 +3937,3,8 +3938,4,9 +3939,5,10 +3940,1,1 +3941,2,2 +3942,3,3 +3943,4,4 +3944,5,5 +3945,1,6 +3946,2,7 +3947,3,8 +3948,4,9 +3949,5,10 +3950,1,1 +3951,2,2 +3952,3,3 +3953,4,4 +3954,5,5 +3955,1,6 +3956,2,7 +3957,3,8 +3958,4,9 +3959,5,10 +3960,1,1 +3961,2,2 +3962,3,3 +3963,4,4 +3964,5,5 +3965,1,6 +3966,2,7 +3967,3,8 +3968,4,9 +3969,5,10 +3970,1,1 +3971,2,2 +3972,3,3 +3973,4,4 +3974,5,5 +3975,1,6 +3976,2,7 +3977,3,8 +3978,4,9 +3979,5,10 +3980,1,1 +3981,2,2 +3982,3,3 +3983,4,4 +3984,5,5 +3985,1,6 +3986,2,7 +3987,3,8 +3988,4,9 +3989,5,10 +3990,1,1 +3991,2,2 +3992,3,3 +3993,4,4 +3994,5,5 +3995,1,6 +3996,2,7 +3997,3,8 +3998,4,9 +3999,5,10 +4000,1,1 +4001,2,2 +4002,3,3 +4003,4,4 +4004,5,5 +4005,1,6 +4006,2,7 +4007,3,8 +4008,4,9 +4009,5,10 +4010,1,1 +4011,2,2 +4012,3,3 +4013,4,4 +4014,5,5 +4015,1,6 +4016,2,7 +4017,3,8 +4018,4,9 +4019,5,10 +4020,1,1 +4021,2,2 +4022,3,3 +4023,4,4 +4024,5,5 +4025,1,6 +4026,2,7 +4027,3,8 +4028,4,9 +4029,5,10 +4030,1,1 +4031,2,2 +4032,3,3 +4033,4,4 +4034,5,5 +4035,1,6 +4036,2,7 +4037,3,8 +4038,4,9 +4039,5,10 +4040,1,1 +4041,2,2 +4042,3,3 +4043,4,4 +4044,5,5 +4045,1,6 +4046,2,7 +4047,3,8 +4048,4,9 +4049,5,10 +4050,1,1 +4051,2,2 +4052,3,3 +4053,4,4 +4054,5,5 +4055,1,6 +4056,2,7 +4057,3,8 +4058,4,9 +4059,5,10 +4060,1,1 +4061,2,2 +4062,3,3 +4063,4,4 +4064,5,5 +4065,1,6 +4066,2,7 +4067,3,8 +4068,4,9 +4069,5,10 +4070,1,1 +4071,2,2 +4072,3,3 +4073,4,4 +4074,5,5 +4075,1,6 +4076,2,7 +4077,3,8 +4078,4,9 +4079,5,10 +4080,1,1 +4081,2,2 +4082,3,3 +4083,4,4 +4084,5,5 +4085,1,6 +4086,2,7 +4087,3,8 +4088,4,9 +4089,5,10 +4090,1,1 +4091,2,2 +4092,3,3 +4093,4,4 +4094,5,5 +4095,1,6 +4096,2,7 +4097,3,8 +4098,4,9 +4099,5,10 +4100,1,1 +4101,2,2 +4102,3,3 +4103,4,4 +4104,5,5 +4105,1,6 +4106,2,7 +4107,3,8 +4108,4,9 +4109,5,10 +4110,1,1 +4111,2,2 +4112,3,3 +4113,4,4 +4114,5,5 +4115,1,6 +4116,2,7 +4117,3,8 +4118,4,9 +4119,5,10 +4120,1,1 +4121,2,2 +4122,3,3 +4123,4,4 +4124,5,5 +4125,1,6 +4126,2,7 +4127,3,8 +4128,4,9 +4129,5,10 +4130,1,1 +4131,2,2 +4132,3,3 +4133,4,4 +4134,5,5 +4135,1,6 +4136,2,7 +4137,3,8 +4138,4,9 +4139,5,10 +4140,1,1 +4141,2,2 +4142,3,3 +4143,4,4 +4144,5,5 +4145,1,6 +4146,2,7 +4147,3,8 +4148,4,9 +4149,5,10 +4150,1,1 +4151,2,2 +4152,3,3 +4153,4,4 +4154,5,5 +4155,1,6 +4156,2,7 +4157,3,8 +4158,4,9 +4159,5,10 +4160,1,1 +4161,2,2 +4162,3,3 +4163,4,4 +4164,5,5 +4165,1,6 +4166,2,7 +4167,3,8 +4168,4,9 +4169,5,10 +4170,1,1 +4171,2,2 +4172,3,3 +4173,4,4 +4174,5,5 +4175,1,6 +4176,2,7 +4177,3,8 +4178,4,9 +4179,5,10 +4180,1,1 +4181,2,2 +4182,3,3 +4183,4,4 +4184,5,5 +4185,1,6 +4186,2,7 +4187,3,8 +4188,4,9 +4189,5,10 +4190,1,1 +4191,2,2 +4192,3,3 +4193,4,4 +4194,5,5 +4195,1,6 +4196,2,7 +4197,3,8 +4198,4,9 +4199,5,10 +4200,1,1 +4201,2,2 +4202,3,3 +4203,4,4 +4204,5,5 +4205,1,6 +4206,2,7 +4207,3,8 +4208,4,9 +4209,5,10 +4210,1,1 +4211,2,2 +4212,3,3 +4213,4,4 +4214,5,5 +4215,1,6 +4216,2,7 +4217,3,8 +4218,4,9 +4219,5,10 +4220,1,1 +4221,2,2 +4222,3,3 +4223,4,4 +4224,5,5 +4225,1,6 +4226,2,7 +4227,3,8 +4228,4,9 +4229,5,10 +4230,1,1 +4231,2,2 +4232,3,3 +4233,4,4 +4234,5,5 +4235,1,6 +4236,2,7 +4237,3,8 +4238,4,9 +4239,5,10 +4240,1,1 +4241,2,2 +4242,3,3 +4243,4,4 +4244,5,5 +4245,1,6 +4246,2,7 +4247,3,8 +4248,4,9 +4249,5,10 +4250,1,1 +4251,2,2 +4252,3,3 +4253,4,4 +4254,5,5 +4255,1,6 +4256,2,7 +4257,3,8 +4258,4,9 +4259,5,10 +4260,1,1 +4261,2,2 +4262,3,3 +4263,4,4 +4264,5,5 +4265,1,6 +4266,2,7 +4267,3,8 +4268,4,9 +4269,5,10 +4270,1,1 +4271,2,2 +4272,3,3 +4273,4,4 +4274,5,5 +4275,1,6 +4276,2,7 +4277,3,8 +4278,4,9 +4279,5,10 +4280,1,1 +4281,2,2 +4282,3,3 +4283,4,4 +4284,5,5 +4285,1,6 +4286,2,7 +4287,3,8 +4288,4,9 +4289,5,10 +4290,1,1 +4291,2,2 +4292,3,3 +4293,4,4 +4294,5,5 +4295,1,6 +4296,2,7 +4297,3,8 +4298,4,9 +4299,5,10 +4300,1,1 +4301,2,2 +4302,3,3 +4303,4,4 +4304,5,5 +4305,1,6 +4306,2,7 +4307,3,8 +4308,4,9 +4309,5,10 +4310,1,1 +4311,2,2 +4312,3,3 +4313,4,4 +4314,5,5 +4315,1,6 +4316,2,7 +4317,3,8 +4318,4,9 +4319,5,10 +4320,1,1 +4321,2,2 +4322,3,3 +4323,4,4 +4324,5,5 +4325,1,6 +4326,2,7 +4327,3,8 +4328,4,9 +4329,5,10 +4330,1,1 +4331,2,2 +4332,3,3 +4333,4,4 +4334,5,5 +4335,1,6 +4336,2,7 +4337,3,8 +4338,4,9 +4339,5,10 +4340,1,1 +4341,2,2 +4342,3,3 +4343,4,4 +4344,5,5 +4345,1,6 +4346,2,7 +4347,3,8 +4348,4,9 +4349,5,10 +4350,1,1 +4351,2,2 +4352,3,3 +4353,4,4 +4354,5,5 +4355,1,6 +4356,2,7 +4357,3,8 +4358,4,9 +4359,5,10 +4360,1,1 +4361,2,2 +4362,3,3 +4363,4,4 +4364,5,5 +4365,1,6 +4366,2,7 +4367,3,8 +4368,4,9 +4369,5,10 +4370,1,1 +4371,2,2 +4372,3,3 +4373,4,4 +4374,5,5 +4375,1,6 +4376,2,7 +4377,3,8 +4378,4,9 +4379,5,10 +4380,1,1 +4381,2,2 +4382,3,3 +4383,4,4 +4384,5,5 +4385,1,6 +4386,2,7 +4387,3,8 +4388,4,9 +4389,5,10 +4390,1,1 +4391,2,2 +4392,3,3 +4393,4,4 +4394,5,5 +4395,1,6 +4396,2,7 +4397,3,8 +4398,4,9 +4399,5,10 +4400,1,1 +4401,2,2 +4402,3,3 +4403,4,4 +4404,5,5 +4405,1,6 +4406,2,7 +4407,3,8 +4408,4,9 +4409,5,10 +4410,1,1 +4411,2,2 +4412,3,3 +4413,4,4 +4414,5,5 +4415,1,6 +4416,2,7 +4417,3,8 +4418,4,9 +4419,5,10 +4420,1,1 +4421,2,2 +4422,3,3 +4423,4,4 +4424,5,5 +4425,1,6 +4426,2,7 +4427,3,8 +4428,4,9 +4429,5,10 +4430,1,1 +4431,2,2 +4432,3,3 +4433,4,4 +4434,5,5 +4435,1,6 +4436,2,7 +4437,3,8 +4438,4,9 +4439,5,10 +4440,1,1 +4441,2,2 +4442,3,3 +4443,4,4 +4444,5,5 +4445,1,6 +4446,2,7 +4447,3,8 +4448,4,9 +4449,5,10 +4450,1,1 +4451,2,2 +4452,3,3 +4453,4,4 +4454,5,5 +4455,1,6 +4456,2,7 +4457,3,8 +4458,4,9 +4459,5,10 +4460,1,1 +4461,2,2 +4462,3,3 +4463,4,4 +4464,5,5 +4465,1,6 +4466,2,7 +4467,3,8 +4468,4,9 +4469,5,10 +4470,1,1 +4471,2,2 +4472,3,3 +4473,4,4 +4474,5,5 +4475,1,6 +4476,2,7 +4477,3,8 +4478,4,9 +4479,5,10 +4480,1,1 +4481,2,2 +4482,3,3 +4483,4,4 +4484,5,5 +4485,1,6 +4486,2,7 +4487,3,8 +4488,4,9 +4489,5,10 +4490,1,1 +4491,2,2 +4492,3,3 +4493,4,4 +4494,5,5 +4495,1,6 +4496,2,7 +4497,3,8 +4498,4,9 +4499,5,10 +4500,1,1 +4501,2,2 +4502,3,3 +4503,4,4 +4504,5,5 +4505,1,6 +4506,2,7 +4507,3,8 +4508,4,9 +4509,5,10 +4510,1,1 +4511,2,2 +4512,3,3 +4513,4,4 +4514,5,5 +4515,1,6 +4516,2,7 +4517,3,8 +4518,4,9 +4519,5,10 +4520,1,1 +4521,2,2 +4522,3,3 +4523,4,4 +4524,5,5 +4525,1,6 +4526,2,7 +4527,3,8 +4528,4,9 +4529,5,10 +4530,1,1 +4531,2,2 +4532,3,3 +4533,4,4 +4534,5,5 +4535,1,6 +4536,2,7 +4537,3,8 +4538,4,9 +4539,5,10 +4540,1,1 +4541,2,2 +4542,3,3 +4543,4,4 +4544,5,5 +4545,1,6 +4546,2,7 +4547,3,8 +4548,4,9 +4549,5,10 +4550,1,1 +4551,2,2 +4552,3,3 +4553,4,4 +4554,5,5 +4555,1,6 +4556,2,7 +4557,3,8 +4558,4,9 +4559,5,10 +4560,1,1 +4561,2,2 +4562,3,3 +4563,4,4 +4564,5,5 +4565,1,6 +4566,2,7 +4567,3,8 +4568,4,9 +4569,5,10 +4570,1,1 +4571,2,2 +4572,3,3 +4573,4,4 +4574,5,5 +4575,1,6 +4576,2,7 +4577,3,8 +4578,4,9 +4579,5,10 +4580,1,1 +4581,2,2 +4582,3,3 +4583,4,4 +4584,5,5 +4585,1,6 +4586,2,7 +4587,3,8 +4588,4,9 +4589,5,10 +4590,1,1 +4591,2,2 +4592,3,3 +4593,4,4 +4594,5,5 +4595,1,6 +4596,2,7 +4597,3,8 +4598,4,9 +4599,5,10 +4600,1,1 +4601,2,2 +4602,3,3 +4603,4,4 +4604,5,5 +4605,1,6 +4606,2,7 +4607,3,8 +4608,4,9 +4609,5,10 +4610,1,1 +4611,2,2 +4612,3,3 +4613,4,4 +4614,5,5 +4615,1,6 +4616,2,7 +4617,3,8 +4618,4,9 +4619,5,10 +4620,1,1 +4621,2,2 +4622,3,3 +4623,4,4 +4624,5,5 +4625,1,6 +4626,2,7 +4627,3,8 +4628,4,9 +4629,5,10 +4630,1,1 +4631,2,2 +4632,3,3 +4633,4,4 +4634,5,5 +4635,1,6 +4636,2,7 +4637,3,8 +4638,4,9 +4639,5,10 +4640,1,1 +4641,2,2 +4642,3,3 +4643,4,4 +4644,5,5 +4645,1,6 +4646,2,7 +4647,3,8 +4648,4,9 +4649,5,10 +4650,1,1 +4651,2,2 +4652,3,3 +4653,4,4 +4654,5,5 +4655,1,6 +4656,2,7 +4657,3,8 +4658,4,9 +4659,5,10 +4660,1,1 +4661,2,2 +4662,3,3 +4663,4,4 +4664,5,5 +4665,1,6 +4666,2,7 +4667,3,8 +4668,4,9 +4669,5,10 +4670,1,1 +4671,2,2 +4672,3,3 +4673,4,4 +4674,5,5 +4675,1,6 +4676,2,7 +4677,3,8 +4678,4,9 +4679,5,10 +4680,1,1 +4681,2,2 +4682,3,3 +4683,4,4 +4684,5,5 +4685,1,6 +4686,2,7 +4687,3,8 +4688,4,9 +4689,5,10 +4690,1,1 +4691,2,2 +4692,3,3 +4693,4,4 +4694,5,5 +4695,1,6 +4696,2,7 +4697,3,8 +4698,4,9 +4699,5,10 +4700,1,1 +4701,2,2 +4702,3,3 +4703,4,4 +4704,5,5 +4705,1,6 +4706,2,7 +4707,3,8 +4708,4,9 +4709,5,10 +4710,1,1 +4711,2,2 +4712,3,3 +4713,4,4 +4714,5,5 +4715,1,6 +4716,2,7 +4717,3,8 +4718,4,9 +4719,5,10 +4720,1,1 +4721,2,2 +4722,3,3 +4723,4,4 +4724,5,5 +4725,1,6 +4726,2,7 +4727,3,8 +4728,4,9 +4729,5,10 +4730,1,1 +4731,2,2 +4732,3,3 +4733,4,4 +4734,5,5 +4735,1,6 +4736,2,7 +4737,3,8 +4738,4,9 +4739,5,10 +4740,1,1 +4741,2,2 +4742,3,3 +4743,4,4 +4744,5,5 +4745,1,6 +4746,2,7 +4747,3,8 +4748,4,9 +4749,5,10 +4750,1,1 +4751,2,2 +4752,3,3 +4753,4,4 +4754,5,5 +4755,1,6 +4756,2,7 +4757,3,8 +4758,4,9 +4759,5,10 +4760,1,1 +4761,2,2 +4762,3,3 +4763,4,4 +4764,5,5 +4765,1,6 +4766,2,7 +4767,3,8 +4768,4,9 +4769,5,10 +4770,1,1 +4771,2,2 +4772,3,3 +4773,4,4 +4774,5,5 +4775,1,6 +4776,2,7 +4777,3,8 +4778,4,9 +4779,5,10 +4780,1,1 +4781,2,2 +4782,3,3 +4783,4,4 +4784,5,5 +4785,1,6 +4786,2,7 +4787,3,8 +4788,4,9 +4789,5,10 +4790,1,1 +4791,2,2 +4792,3,3 +4793,4,4 +4794,5,5 +4795,1,6 +4796,2,7 +4797,3,8 +4798,4,9 +4799,5,10 +4800,1,1 +4801,2,2 +4802,3,3 +4803,4,4 +4804,5,5 +4805,1,6 +4806,2,7 +4807,3,8 +4808,4,9 +4809,5,10 +4810,1,1 +4811,2,2 +4812,3,3 +4813,4,4 +4814,5,5 +4815,1,6 +4816,2,7 +4817,3,8 +4818,4,9 +4819,5,10 +4820,1,1 +4821,2,2 +4822,3,3 +4823,4,4 +4824,5,5 +4825,1,6 +4826,2,7 +4827,3,8 +4828,4,9 +4829,5,10 +4830,1,1 +4831,2,2 +4832,3,3 +4833,4,4 +4834,5,5 +4835,1,6 +4836,2,7 +4837,3,8 +4838,4,9 +4839,5,10 +4840,1,1 +4841,2,2 +4842,3,3 +4843,4,4 +4844,5,5 +4845,1,6 +4846,2,7 +4847,3,8 +4848,4,9 +4849,5,10 +4850,1,1 +4851,2,2 +4852,3,3 +4853,4,4 +4854,5,5 +4855,1,6 +4856,2,7 +4857,3,8 +4858,4,9 +4859,5,10 +4860,1,1 +4861,2,2 +4862,3,3 +4863,4,4 +4864,5,5 +4865,1,6 +4866,2,7 +4867,3,8 +4868,4,9 +4869,5,10 +4870,1,1 +4871,2,2 +4872,3,3 +4873,4,4 +4874,5,5 +4875,1,6 +4876,2,7 +4877,3,8 +4878,4,9 +4879,5,10 +4880,1,1 +4881,2,2 +4882,3,3 +4883,4,4 +4884,5,5 +4885,1,6 +4886,2,7 +4887,3,8 +4888,4,9 +4889,5,10 +4890,1,1 +4891,2,2 +4892,3,3 +4893,4,4 +4894,5,5 +4895,1,6 +4896,2,7 +4897,3,8 +4898,4,9 +4899,5,10 +4900,1,1 +4901,2,2 +4902,3,3 +4903,4,4 +4904,5,5 +4905,1,6 +4906,2,7 +4907,3,8 +4908,4,9 +4909,5,10 +4910,1,1 +4911,2,2 +4912,3,3 +4913,4,4 +4914,5,5 +4915,1,6 +4916,2,7 +4917,3,8 +4918,4,9 +4919,5,10 +4920,1,1 +4921,2,2 +4922,3,3 +4923,4,4 +4924,5,5 +4925,1,6 +4926,2,7 +4927,3,8 +4928,4,9 +4929,5,10 +4930,1,1 +4931,2,2 +4932,3,3 +4933,4,4 +4934,5,5 +4935,1,6 +4936,2,7 +4937,3,8 +4938,4,9 +4939,5,10 +4940,1,1 +4941,2,2 +4942,3,3 +4943,4,4 +4944,5,5 +4945,1,6 +4946,2,7 +4947,3,8 +4948,4,9 +4949,5,10 +4950,1,1 +4951,2,2 +4952,3,3 +4953,4,4 +4954,5,5 +4955,1,6 +4956,2,7 +4957,3,8 +4958,4,9 +4959,5,10 +4960,1,1 +4961,2,2 +4962,3,3 +4963,4,4 +4964,5,5 +4965,1,6 +4966,2,7 +4967,3,8 +4968,4,9 +4969,5,10 +4970,1,1 +4971,2,2 +4972,3,3 +4973,4,4 +4974,5,5 +4975,1,6 +4976,2,7 +4977,3,8 +4978,4,9 +4979,5,10 +4980,1,1 +4981,2,2 +4982,3,3 +4983,4,4 +4984,5,5 +4985,1,6 +4986,2,7 +4987,3,8 +4988,4,9 +4989,5,10 +4990,1,1 +4991,2,2 +4992,3,3 +4993,4,4 +4994,5,5 +4995,1,6 +4996,2,7 +4997,3,8 +4998,4,9 +4999,5,10 +5000,1,1 +5001,2,2 +5002,3,3 +5003,4,4 +5004,5,5 +5005,1,6 +5006,2,7 +5007,3,8 +5008,4,9 +5009,5,10 +5010,1,1 +5011,2,2 +5012,3,3 +5013,4,4 +5014,5,5 +5015,1,6 +5016,2,7 +5017,3,8 +5018,4,9 +5019,5,10 +5020,1,1 +5021,2,2 +5022,3,3 +5023,4,4 +5024,5,5 +5025,1,6 +5026,2,7 +5027,3,8 +5028,4,9 +5029,5,10 +5030,1,1 +5031,2,2 +5032,3,3 +5033,4,4 +5034,5,5 +5035,1,6 +5036,2,7 +5037,3,8 +5038,4,9 +5039,5,10 +5040,1,1 +5041,2,2 +5042,3,3 +5043,4,4 +5044,5,5 +5045,1,6 +5046,2,7 +5047,3,8 +5048,4,9 +5049,5,10 +5050,1,1 +5051,2,2 +5052,3,3 +5053,4,4 +5054,5,5 +5055,1,6 +5056,2,7 +5057,3,8 +5058,4,9 +5059,5,10 +5060,1,1 +5061,2,2 +5062,3,3 +5063,4,4 +5064,5,5 +5065,1,6 +5066,2,7 +5067,3,8 +5068,4,9 +5069,5,10 +5070,1,1 +5071,2,2 +5072,3,3 +5073,4,4 +5074,5,5 +5075,1,6 +5076,2,7 +5077,3,8 +5078,4,9 +5079,5,10 +5080,1,1 +5081,2,2 +5082,3,3 +5083,4,4 +5084,5,5 +5085,1,6 +5086,2,7 +5087,3,8 +5088,4,9 +5089,5,10 +5090,1,1 +5091,2,2 +5092,3,3 +5093,4,4 +5094,5,5 +5095,1,6 +5096,2,7 +5097,3,8 +5098,4,9 +5099,5,10 +5100,1,1 +5101,2,2 +5102,3,3 +5103,4,4 +5104,5,5 +5105,1,6 +5106,2,7 +5107,3,8 +5108,4,9 +5109,5,10 +5110,1,1 +5111,2,2 +5112,3,3 +5113,4,4 +5114,5,5 +5115,1,6 +5116,2,7 +5117,3,8 +5118,4,9 +5119,5,10 +5120,1,1 +5121,2,2 +5122,3,3 +5123,4,4 +5124,5,5 +5125,1,6 +5126,2,7 +5127,3,8 +5128,4,9 +5129,5,10 +5130,1,1 +5131,2,2 +5132,3,3 +5133,4,4 +5134,5,5 +5135,1,6 +5136,2,7 +5137,3,8 +5138,4,9 +5139,5,10 +5140,1,1 +5141,2,2 +5142,3,3 +5143,4,4 +5144,5,5 +5145,1,6 +5146,2,7 +5147,3,8 +5148,4,9 +5149,5,10 +5150,1,1 +5151,2,2 +5152,3,3 +5153,4,4 +5154,5,5 +5155,1,6 +5156,2,7 +5157,3,8 +5158,4,9 +5159,5,10 +5160,1,1 +5161,2,2 +5162,3,3 +5163,4,4 +5164,5,5 +5165,1,6 +5166,2,7 +5167,3,8 +5168,4,9 +5169,5,10 +5170,1,1 +5171,2,2 +5172,3,3 +5173,4,4 +5174,5,5 +5175,1,6 +5176,2,7 +5177,3,8 +5178,4,9 +5179,5,10 +5180,1,1 +5181,2,2 +5182,3,3 +5183,4,4 +5184,5,5 +5185,1,6 +5186,2,7 +5187,3,8 +5188,4,9 +5189,5,10 +5190,1,1 +5191,2,2 +5192,3,3 +5193,4,4 +5194,5,5 +5195,1,6 +5196,2,7 +5197,3,8 +5198,4,9 +5199,5,10 +5200,1,1 +5201,2,2 +5202,3,3 +5203,4,4 +5204,5,5 +5205,1,6 +5206,2,7 +5207,3,8 +5208,4,9 +5209,5,10 +5210,1,1 +5211,2,2 +5212,3,3 +5213,4,4 +5214,5,5 +5215,1,6 +5216,2,7 +5217,3,8 +5218,4,9 +5219,5,10 +5220,1,1 +5221,2,2 +5222,3,3 +5223,4,4 +5224,5,5 +5225,1,6 +5226,2,7 +5227,3,8 +5228,4,9 +5229,5,10 +5230,1,1 +5231,2,2 +5232,3,3 +5233,4,4 +5234,5,5 +5235,1,6 +5236,2,7 +5237,3,8 +5238,4,9 +5239,5,10 +5240,1,1 +5241,2,2 +5242,3,3 +5243,4,4 +5244,5,5 +5245,1,6 +5246,2,7 +5247,3,8 +5248,4,9 +5249,5,10 +5250,1,1 +5251,2,2 +5252,3,3 +5253,4,4 +5254,5,5 +5255,1,6 +5256,2,7 +5257,3,8 +5258,4,9 +5259,5,10 +5260,1,1 +5261,2,2 +5262,3,3 +5263,4,4 +5264,5,5 +5265,1,6 +5266,2,7 +5267,3,8 +5268,4,9 +5269,5,10 +5270,1,1 +5271,2,2 +5272,3,3 +5273,4,4 +5274,5,5 +5275,1,6 +5276,2,7 +5277,3,8 +5278,4,9 +5279,5,10 +5280,1,1 +5281,2,2 +5282,3,3 +5283,4,4 +5284,5,5 +5285,1,6 +5286,2,7 +5287,3,8 +5288,4,9 +5289,5,10 +5290,1,1 +5291,2,2 +5292,3,3 +5293,4,4 +5294,5,5 +5295,1,6 +5296,2,7 +5297,3,8 +5298,4,9 +5299,5,10 +5300,1,1 +5301,2,2 +5302,3,3 +5303,4,4 +5304,5,5 +5305,1,6 +5306,2,7 +5307,3,8 +5308,4,9 +5309,5,10 +5310,1,1 +5311,2,2 +5312,3,3 +5313,4,4 +5314,5,5 +5315,1,6 +5316,2,7 +5317,3,8 +5318,4,9 +5319,5,10 +5320,1,1 +5321,2,2 +5322,3,3 +5323,4,4 +5324,5,5 +5325,1,6 +5326,2,7 +5327,3,8 +5328,4,9 +5329,5,10 +5330,1,1 +5331,2,2 +5332,3,3 +5333,4,4 +5334,5,5 +5335,1,6 +5336,2,7 +5337,3,8 +5338,4,9 +5339,5,10 +5340,1,1 +5341,2,2 +5342,3,3 +5343,4,4 +5344,5,5 +5345,1,6 +5346,2,7 +5347,3,8 +5348,4,9 +5349,5,10 +5350,1,1 +5351,2,2 +5352,3,3 +5353,4,4 +5354,5,5 +5355,1,6 +5356,2,7 +5357,3,8 +5358,4,9 +5359,5,10 +5360,1,1 +5361,2,2 +5362,3,3 +5363,4,4 +5364,5,5 +5365,1,6 +5366,2,7 +5367,3,8 +5368,4,9 +5369,5,10 +5370,1,1 +5371,2,2 +5372,3,3 +5373,4,4 +5374,5,5 +5375,1,6 +5376,2,7 +5377,3,8 +5378,4,9 +5379,5,10 +5380,1,1 +5381,2,2 +5382,3,3 +5383,4,4 +5384,5,5 +5385,1,6 +5386,2,7 +5387,3,8 +5388,4,9 +5389,5,10 +5390,1,1 +5391,2,2 +5392,3,3 +5393,4,4 +5394,5,5 +5395,1,6 +5396,2,7 +5397,3,8 +5398,4,9 +5399,5,10 +5400,1,1 +5401,2,2 +5402,3,3 +5403,4,4 +5404,5,5 +5405,1,6 +5406,2,7 +5407,3,8 +5408,4,9 +5409,5,10 +5410,1,1 +5411,2,2 +5412,3,3 +5413,4,4 +5414,5,5 +5415,1,6 +5416,2,7 +5417,3,8 +5418,4,9 +5419,5,10 +5420,1,1 +5421,2,2 +5422,3,3 +5423,4,4 +5424,5,5 +5425,1,6 +5426,2,7 +5427,3,8 +5428,4,9 +5429,5,10 +5430,1,1 +5431,2,2 +5432,3,3 +5433,4,4 +5434,5,5 +5435,1,6 +5436,2,7 +5437,3,8 +5438,4,9 +5439,5,10 +5440,1,1 +5441,2,2 +5442,3,3 +5443,4,4 +5444,5,5 +5445,1,6 +5446,2,7 +5447,3,8 +5448,4,9 +5449,5,10 +5450,1,1 +5451,2,2 +5452,3,3 +5453,4,4 +5454,5,5 +5455,1,6 +5456,2,7 +5457,3,8 +5458,4,9 +5459,5,10 +5460,1,1 +5461,2,2 +5462,3,3 +5463,4,4 +5464,5,5 +5465,1,6 +5466,2,7 +5467,3,8 +5468,4,9 +5469,5,10 +5470,1,1 +5471,2,2 +5472,3,3 +5473,4,4 +5474,5,5 +5475,1,6 +5476,2,7 +5477,3,8 +5478,4,9 +5479,5,10 +5480,1,1 +5481,2,2 +5482,3,3 +5483,4,4 +5484,5,5 +5485,1,6 +5486,2,7 +5487,3,8 +5488,4,9 +5489,5,10 +5490,1,1 +5491,2,2 +5492,3,3 +5493,4,4 +5494,5,5 +5495,1,6 +5496,2,7 +5497,3,8 +5498,4,9 +5499,5,10 +5500,1,1 +5501,2,2 +5502,3,3 +5503,4,4 +5504,5,5 +5505,1,6 +5506,2,7 +5507,3,8 +5508,4,9 +5509,5,10 +5510,1,1 +5511,2,2 +5512,3,3 +5513,4,4 +5514,5,5 +5515,1,6 +5516,2,7 +5517,3,8 +5518,4,9 +5519,5,10 +5520,1,1 +5521,2,2 +5522,3,3 +5523,4,4 +5524,5,5 +5525,1,6 +5526,2,7 +5527,3,8 +5528,4,9 +5529,5,10 +5530,1,1 +5531,2,2 +5532,3,3 +5533,4,4 +5534,5,5 +5535,1,6 +5536,2,7 +5537,3,8 +5538,4,9 +5539,5,10 +5540,1,1 +5541,2,2 +5542,3,3 +5543,4,4 +5544,5,5 +5545,1,6 +5546,2,7 +5547,3,8 +5548,4,9 +5549,5,10 +5550,1,1 +5551,2,2 +5552,3,3 +5553,4,4 +5554,5,5 +5555,1,6 +5556,2,7 +5557,3,8 +5558,4,9 +5559,5,10 +5560,1,1 +5561,2,2 +5562,3,3 +5563,4,4 +5564,5,5 +5565,1,6 +5566,2,7 +5567,3,8 +5568,4,9 +5569,5,10 +5570,1,1 +5571,2,2 +5572,3,3 +5573,4,4 +5574,5,5 +5575,1,6 +5576,2,7 +5577,3,8 +5578,4,9 +5579,5,10 +5580,1,1 +5581,2,2 +5582,3,3 +5583,4,4 +5584,5,5 +5585,1,6 +5586,2,7 +5587,3,8 +5588,4,9 +5589,5,10 +5590,1,1 +5591,2,2 +5592,3,3 +5593,4,4 +5594,5,5 +5595,1,6 +5596,2,7 +5597,3,8 +5598,4,9 +5599,5,10 +5600,1,1 +5601,2,2 +5602,3,3 +5603,4,4 +5604,5,5 +5605,1,6 +5606,2,7 +5607,3,8 +5608,4,9 +5609,5,10 +5610,1,1 +5611,2,2 +5612,3,3 +5613,4,4 +5614,5,5 +5615,1,6 +5616,2,7 +5617,3,8 +5618,4,9 +5619,5,10 +5620,1,1 +5621,2,2 +5622,3,3 +5623,4,4 +5624,5,5 +5625,1,6 +5626,2,7 +5627,3,8 +5628,4,9 +5629,5,10 +5630,1,1 +5631,2,2 +5632,3,3 +5633,4,4 +5634,5,5 +5635,1,6 +5636,2,7 +5637,3,8 +5638,4,9 +5639,5,10 +5640,1,1 +5641,2,2 +5642,3,3 +5643,4,4 +5644,5,5 +5645,1,6 +5646,2,7 +5647,3,8 +5648,4,9 +5649,5,10 +5650,1,1 +5651,2,2 +5652,3,3 +5653,4,4 +5654,5,5 +5655,1,6 +5656,2,7 +5657,3,8 +5658,4,9 +5659,5,10 +5660,1,1 +5661,2,2 +5662,3,3 +5663,4,4 +5664,5,5 +5665,1,6 +5666,2,7 +5667,3,8 +5668,4,9 +5669,5,10 +5670,1,1 +5671,2,2 +5672,3,3 +5673,4,4 +5674,5,5 +5675,1,6 +5676,2,7 +5677,3,8 +5678,4,9 +5679,5,10 +5680,1,1 +5681,2,2 +5682,3,3 +5683,4,4 +5684,5,5 +5685,1,6 +5686,2,7 +5687,3,8 +5688,4,9 +5689,5,10 +5690,1,1 +5691,2,2 +5692,3,3 +5693,4,4 +5694,5,5 +5695,1,6 +5696,2,7 +5697,3,8 +5698,4,9 +5699,5,10 +5700,1,1 +5701,2,2 +5702,3,3 +5703,4,4 +5704,5,5 +5705,1,6 +5706,2,7 +5707,3,8 +5708,4,9 +5709,5,10 +5710,1,1 +5711,2,2 +5712,3,3 +5713,4,4 +5714,5,5 +5715,1,6 +5716,2,7 +5717,3,8 +5718,4,9 +5719,5,10 +5720,1,1 +5721,2,2 +5722,3,3 +5723,4,4 +5724,5,5 +5725,1,6 +5726,2,7 +5727,3,8 +5728,4,9 +5729,5,10 +5730,1,1 +5731,2,2 +5732,3,3 +5733,4,4 +5734,5,5 +5735,1,6 +5736,2,7 +5737,3,8 +5738,4,9 +5739,5,10 +5740,1,1 +5741,2,2 +5742,3,3 +5743,4,4 +5744,5,5 +5745,1,6 +5746,2,7 +5747,3,8 +5748,4,9 +5749,5,10 +5750,1,1 +5751,2,2 +5752,3,3 +5753,4,4 +5754,5,5 +5755,1,6 +5756,2,7 +5757,3,8 +5758,4,9 +5759,5,10 +5760,1,1 +5761,2,2 +5762,3,3 +5763,4,4 +5764,5,5 +5765,1,6 +5766,2,7 +5767,3,8 +5768,4,9 +5769,5,10 +5770,1,1 +5771,2,2 +5772,3,3 +5773,4,4 +5774,5,5 +5775,1,6 +5776,2,7 +5777,3,8 +5778,4,9 +5779,5,10 +5780,1,1 +5781,2,2 +5782,3,3 +5783,4,4 +5784,5,5 +5785,1,6 +5786,2,7 +5787,3,8 +5788,4,9 +5789,5,10 +5790,1,1 +5791,2,2 +5792,3,3 +5793,4,4 +5794,5,5 +5795,1,6 +5796,2,7 +5797,3,8 +5798,4,9 +5799,5,10 +5800,1,1 +5801,2,2 +5802,3,3 +5803,4,4 +5804,5,5 +5805,1,6 +5806,2,7 +5807,3,8 +5808,4,9 +5809,5,10 +5810,1,1 +5811,2,2 +5812,3,3 +5813,4,4 +5814,5,5 +5815,1,6 +5816,2,7 +5817,3,8 +5818,4,9 +5819,5,10 +5820,1,1 +5821,2,2 +5822,3,3 +5823,4,4 +5824,5,5 +5825,1,6 +5826,2,7 +5827,3,8 +5828,4,9 +5829,5,10 +5830,1,1 +5831,2,2 +5832,3,3 +5833,4,4 +5834,5,5 +5835,1,6 +5836,2,7 +5837,3,8 +5838,4,9 +5839,5,10 +5840,1,1 +5841,2,2 +5842,3,3 +5843,4,4 +5844,5,5 +5845,1,6 +5846,2,7 +5847,3,8 +5848,4,9 +5849,5,10 +5850,1,1 +5851,2,2 +5852,3,3 +5853,4,4 +5854,5,5 +5855,1,6 +5856,2,7 +5857,3,8 +5858,4,9 +5859,5,10 +5860,1,1 +5861,2,2 +5862,3,3 +5863,4,4 +5864,5,5 +5865,1,6 +5866,2,7 +5867,3,8 +5868,4,9 +5869,5,10 +5870,1,1 +5871,2,2 +5872,3,3 +5873,4,4 +5874,5,5 +5875,1,6 +5876,2,7 +5877,3,8 +5878,4,9 +5879,5,10 +5880,1,1 +5881,2,2 +5882,3,3 +5883,4,4 +5884,5,5 +5885,1,6 +5886,2,7 +5887,3,8 +5888,4,9 +5889,5,10 +5890,1,1 +5891,2,2 +5892,3,3 +5893,4,4 +5894,5,5 +5895,1,6 +5896,2,7 +5897,3,8 +5898,4,9 +5899,5,10 +5900,1,1 +5901,2,2 +5902,3,3 +5903,4,4 +5904,5,5 +5905,1,6 +5906,2,7 +5907,3,8 +5908,4,9 +5909,5,10 +5910,1,1 +5911,2,2 +5912,3,3 +5913,4,4 +5914,5,5 +5915,1,6 +5916,2,7 +5917,3,8 +5918,4,9 +5919,5,10 +5920,1,1 +5921,2,2 +5922,3,3 +5923,4,4 +5924,5,5 +5925,1,6 +5926,2,7 +5927,3,8 +5928,4,9 +5929,5,10 +5930,1,1 +5931,2,2 +5932,3,3 +5933,4,4 +5934,5,5 +5935,1,6 +5936,2,7 +5937,3,8 +5938,4,9 +5939,5,10 +5940,1,1 +5941,2,2 +5942,3,3 +5943,4,4 +5944,5,5 +5945,1,6 +5946,2,7 +5947,3,8 +5948,4,9 +5949,5,10 +5950,1,1 +5951,2,2 +5952,3,3 +5953,4,4 +5954,5,5 +5955,1,6 +5956,2,7 +5957,3,8 +5958,4,9 +5959,5,10 +5960,1,1 +5961,2,2 +5962,3,3 +5963,4,4 +5964,5,5 +5965,1,6 +5966,2,7 +5967,3,8 +5968,4,9 +5969,5,10 +5970,1,1 +5971,2,2 +5972,3,3 +5973,4,4 +5974,5,5 +5975,1,6 +5976,2,7 +5977,3,8 +5978,4,9 +5979,5,10 +5980,1,1 +5981,2,2 +5982,3,3 +5983,4,4 +5984,5,5 +5985,1,6 +5986,2,7 +5987,3,8 +5988,4,9 +5989,5,10 +5990,1,1 +5991,2,2 +5992,3,3 +5993,4,4 +5994,5,5 +5995,1,6 +5996,2,7 +5997,3,8 +5998,4,9 +5999,5,10 +6000,1,1 +6001,2,2 +6002,3,3 +6003,4,4 +6004,5,5 +6005,1,6 +6006,2,7 +6007,3,8 +6008,4,9 +6009,5,10 +6010,1,1 +6011,2,2 +6012,3,3 +6013,4,4 +6014,5,5 +6015,1,6 +6016,2,7 +6017,3,8 +6018,4,9 +6019,5,10 +6020,1,1 +6021,2,2 +6022,3,3 +6023,4,4 +6024,5,5 +6025,1,6 +6026,2,7 +6027,3,8 +6028,4,9 +6029,5,10 +6030,1,1 +6031,2,2 +6032,3,3 +6033,4,4 +6034,5,5 +6035,1,6 +6036,2,7 +6037,3,8 +6038,4,9 +6039,5,10 +6040,1,1 +6041,2,2 +6042,3,3 +6043,4,4 +6044,5,5 +6045,1,6 +6046,2,7 +6047,3,8 +6048,4,9 +6049,5,10 +6050,1,1 +6051,2,2 +6052,3,3 +6053,4,4 +6054,5,5 +6055,1,6 +6056,2,7 +6057,3,8 +6058,4,9 +6059,5,10 +6060,1,1 +6061,2,2 +6062,3,3 +6063,4,4 +6064,5,5 +6065,1,6 +6066,2,7 +6067,3,8 +6068,4,9 +6069,5,10 +6070,1,1 +6071,2,2 +6072,3,3 +6073,4,4 +6074,5,5 +6075,1,6 +6076,2,7 +6077,3,8 +6078,4,9 +6079,5,10 +6080,1,1 +6081,2,2 +6082,3,3 +6083,4,4 +6084,5,5 +6085,1,6 +6086,2,7 +6087,3,8 +6088,4,9 +6089,5,10 +6090,1,1 +6091,2,2 +6092,3,3 +6093,4,4 +6094,5,5 +6095,1,6 +6096,2,7 +6097,3,8 +6098,4,9 +6099,5,10 +6100,1,1 +6101,2,2 +6102,3,3 +6103,4,4 +6104,5,5 +6105,1,6 +6106,2,7 +6107,3,8 +6108,4,9 +6109,5,10 +6110,1,1 +6111,2,2 +6112,3,3 +6113,4,4 +6114,5,5 +6115,1,6 +6116,2,7 +6117,3,8 +6118,4,9 +6119,5,10 +6120,1,1 +6121,2,2 +6122,3,3 +6123,4,4 +6124,5,5 +6125,1,6 +6126,2,7 +6127,3,8 +6128,4,9 +6129,5,10 +6130,1,1 +6131,2,2 +6132,3,3 +6133,4,4 +6134,5,5 +6135,1,6 +6136,2,7 +6137,3,8 +6138,4,9 +6139,5,10 +6140,1,1 +6141,2,2 +6142,3,3 +6143,4,4 +6144,5,5 +6145,1,6 +6146,2,7 +6147,3,8 +6148,4,9 +6149,5,10 +6150,1,1 +6151,2,2 +6152,3,3 +6153,4,4 +6154,5,5 +6155,1,6 +6156,2,7 +6157,3,8 +6158,4,9 +6159,5,10 +6160,1,1 +6161,2,2 +6162,3,3 +6163,4,4 +6164,5,5 +6165,1,6 +6166,2,7 +6167,3,8 +6168,4,9 +6169,5,10 +6170,1,1 +6171,2,2 +6172,3,3 +6173,4,4 +6174,5,5 +6175,1,6 +6176,2,7 +6177,3,8 +6178,4,9 +6179,5,10 +6180,1,1 +6181,2,2 +6182,3,3 +6183,4,4 +6184,5,5 +6185,1,6 +6186,2,7 +6187,3,8 +6188,4,9 +6189,5,10 +6190,1,1 +6191,2,2 +6192,3,3 +6193,4,4 +6194,5,5 +6195,1,6 +6196,2,7 +6197,3,8 +6198,4,9 +6199,5,10 +6200,1,1 +6201,2,2 +6202,3,3 +6203,4,4 +6204,5,5 +6205,1,6 +6206,2,7 +6207,3,8 +6208,4,9 +6209,5,10 +6210,1,1 +6211,2,2 +6212,3,3 +6213,4,4 +6214,5,5 +6215,1,6 +6216,2,7 +6217,3,8 +6218,4,9 +6219,5,10 +6220,1,1 +6221,2,2 +6222,3,3 +6223,4,4 +6224,5,5 +6225,1,6 +6226,2,7 +6227,3,8 +6228,4,9 +6229,5,10 +6230,1,1 +6231,2,2 +6232,3,3 +6233,4,4 +6234,5,5 +6235,1,6 +6236,2,7 +6237,3,8 +6238,4,9 +6239,5,10 +6240,1,1 +6241,2,2 +6242,3,3 +6243,4,4 +6244,5,5 +6245,1,6 +6246,2,7 +6247,3,8 +6248,4,9 +6249,5,10 +6250,1,1 +6251,2,2 +6252,3,3 +6253,4,4 +6254,5,5 +6255,1,6 +6256,2,7 +6257,3,8 +6258,4,9 +6259,5,10 +6260,1,1 +6261,2,2 +6262,3,3 +6263,4,4 +6264,5,5 +6265,1,6 +6266,2,7 +6267,3,8 +6268,4,9 +6269,5,10 +6270,1,1 +6271,2,2 +6272,3,3 +6273,4,4 +6274,5,5 +6275,1,6 +6276,2,7 +6277,3,8 +6278,4,9 +6279,5,10 +6280,1,1 +6281,2,2 +6282,3,3 +6283,4,4 +6284,5,5 +6285,1,6 +6286,2,7 +6287,3,8 +6288,4,9 +6289,5,10 +6290,1,1 +6291,2,2 +6292,3,3 +6293,4,4 +6294,5,5 +6295,1,6 +6296,2,7 +6297,3,8 +6298,4,9 +6299,5,10 +6300,1,1 +6301,2,2 +6302,3,3 +6303,4,4 +6304,5,5 +6305,1,6 +6306,2,7 +6307,3,8 +6308,4,9 +6309,5,10 +6310,1,1 +6311,2,2 +6312,3,3 +6313,4,4 +6314,5,5 +6315,1,6 +6316,2,7 +6317,3,8 +6318,4,9 +6319,5,10 +6320,1,1 +6321,2,2 +6322,3,3 +6323,4,4 +6324,5,5 +6325,1,6 +6326,2,7 +6327,3,8 +6328,4,9 +6329,5,10 +6330,1,1 +6331,2,2 +6332,3,3 +6333,4,4 +6334,5,5 +6335,1,6 +6336,2,7 +6337,3,8 +6338,4,9 +6339,5,10 +6340,1,1 +6341,2,2 +6342,3,3 +6343,4,4 +6344,5,5 +6345,1,6 +6346,2,7 +6347,3,8 +6348,4,9 +6349,5,10 +6350,1,1 +6351,2,2 +6352,3,3 +6353,4,4 +6354,5,5 +6355,1,6 +6356,2,7 +6357,3,8 +6358,4,9 +6359,5,10 +6360,1,1 +6361,2,2 +6362,3,3 +6363,4,4 +6364,5,5 +6365,1,6 +6366,2,7 +6367,3,8 +6368,4,9 +6369,5,10 +6370,1,1 +6371,2,2 +6372,3,3 +6373,4,4 +6374,5,5 +6375,1,6 +6376,2,7 +6377,3,8 +6378,4,9 +6379,5,10 +6380,1,1 +6381,2,2 +6382,3,3 +6383,4,4 +6384,5,5 +6385,1,6 +6386,2,7 +6387,3,8 +6388,4,9 +6389,5,10 +6390,1,1 +6391,2,2 +6392,3,3 +6393,4,4 +6394,5,5 +6395,1,6 +6396,2,7 +6397,3,8 +6398,4,9 +6399,5,10 +6400,1,1 +6401,2,2 +6402,3,3 +6403,4,4 +6404,5,5 +6405,1,6 +6406,2,7 +6407,3,8 +6408,4,9 +6409,5,10 +6410,1,1 +6411,2,2 +6412,3,3 +6413,4,4 +6414,5,5 +6415,1,6 +6416,2,7 +6417,3,8 +6418,4,9 +6419,5,10 +6420,1,1 +6421,2,2 +6422,3,3 +6423,4,4 +6424,5,5 +6425,1,6 +6426,2,7 +6427,3,8 +6428,4,9 +6429,5,10 +6430,1,1 +6431,2,2 +6432,3,3 +6433,4,4 +6434,5,5 +6435,1,6 +6436,2,7 +6437,3,8 +6438,4,9 +6439,5,10 +6440,1,1 +6441,2,2 +6442,3,3 +6443,4,4 +6444,5,5 +6445,1,6 +6446,2,7 +6447,3,8 +6448,4,9 +6449,5,10 +6450,1,1 +6451,2,2 +6452,3,3 +6453,4,4 +6454,5,5 +6455,1,6 +6456,2,7 +6457,3,8 +6458,4,9 +6459,5,10 +6460,1,1 +6461,2,2 +6462,3,3 +6463,4,4 +6464,5,5 +6465,1,6 +6466,2,7 +6467,3,8 +6468,4,9 +6469,5,10 +6470,1,1 +6471,2,2 +6472,3,3 +6473,4,4 +6474,5,5 +6475,1,6 +6476,2,7 +6477,3,8 +6478,4,9 +6479,5,10 +6480,1,1 +6481,2,2 +6482,3,3 +6483,4,4 +6484,5,5 +6485,1,6 +6486,2,7 +6487,3,8 +6488,4,9 +6489,5,10 +6490,1,1 +6491,2,2 +6492,3,3 +6493,4,4 +6494,5,5 +6495,1,6 +6496,2,7 +6497,3,8 +6498,4,9 +6499,5,10 +6500,1,1 +6501,2,2 +6502,3,3 +6503,4,4 +6504,5,5 +6505,1,6 +6506,2,7 +6507,3,8 +6508,4,9 +6509,5,10 +6510,1,1 +6511,2,2 +6512,3,3 +6513,4,4 +6514,5,5 +6515,1,6 +6516,2,7 +6517,3,8 +6518,4,9 +6519,5,10 +6520,1,1 +6521,2,2 +6522,3,3 +6523,4,4 +6524,5,5 +6525,1,6 +6526,2,7 +6527,3,8 +6528,4,9 +6529,5,10 +6530,1,1 +6531,2,2 +6532,3,3 +6533,4,4 +6534,5,5 +6535,1,6 +6536,2,7 +6537,3,8 +6538,4,9 +6539,5,10 +6540,1,1 +6541,2,2 +6542,3,3 +6543,4,4 +6544,5,5 +6545,1,6 +6546,2,7 +6547,3,8 +6548,4,9 +6549,5,10 +6550,1,1 +6551,2,2 +6552,3,3 +6553,4,4 +6554,5,5 +6555,1,6 +6556,2,7 +6557,3,8 +6558,4,9 +6559,5,10 +6560,1,1 +6561,2,2 +6562,3,3 +6563,4,4 +6564,5,5 +6565,1,6 +6566,2,7 +6567,3,8 +6568,4,9 +6569,5,10 +6570,1,1 +6571,2,2 +6572,3,3 +6573,4,4 +6574,5,5 +6575,1,6 +6576,2,7 +6577,3,8 +6578,4,9 +6579,5,10 +6580,1,1 +6581,2,2 +6582,3,3 +6583,4,4 +6584,5,5 +6585,1,6 +6586,2,7 +6587,3,8 +6588,4,9 +6589,5,10 +6590,1,1 +6591,2,2 +6592,3,3 +6593,4,4 +6594,5,5 +6595,1,6 +6596,2,7 +6597,3,8 +6598,4,9 +6599,5,10 +6600,1,1 +6601,2,2 +6602,3,3 +6603,4,4 +6604,5,5 +6605,1,6 +6606,2,7 +6607,3,8 +6608,4,9 +6609,5,10 +6610,1,1 +6611,2,2 +6612,3,3 +6613,4,4 +6614,5,5 +6615,1,6 +6616,2,7 +6617,3,8 +6618,4,9 +6619,5,10 +6620,1,1 +6621,2,2 +6622,3,3 +6623,4,4 +6624,5,5 +6625,1,6 +6626,2,7 +6627,3,8 +6628,4,9 +6629,5,10 +6630,1,1 +6631,2,2 +6632,3,3 +6633,4,4 +6634,5,5 +6635,1,6 +6636,2,7 +6637,3,8 +6638,4,9 +6639,5,10 +6640,1,1 +6641,2,2 +6642,3,3 +6643,4,4 +6644,5,5 +6645,1,6 +6646,2,7 +6647,3,8 +6648,4,9 +6649,5,10 +6650,1,1 +6651,2,2 +6652,3,3 +6653,4,4 +6654,5,5 +6655,1,6 +6656,2,7 +6657,3,8 +6658,4,9 +6659,5,10 +6660,1,1 +6661,2,2 +6662,3,3 +6663,4,4 +6664,5,5 +6665,1,6 +6666,2,7 +6667,3,8 +6668,4,9 +6669,5,10 +6670,1,1 +6671,2,2 +6672,3,3 +6673,4,4 +6674,5,5 +6675,1,6 +6676,2,7 +6677,3,8 +6678,4,9 +6679,5,10 +6680,1,1 +6681,2,2 +6682,3,3 +6683,4,4 +6684,5,5 +6685,1,6 +6686,2,7 +6687,3,8 +6688,4,9 +6689,5,10 +6690,1,1 +6691,2,2 +6692,3,3 +6693,4,4 +6694,5,5 +6695,1,6 +6696,2,7 +6697,3,8 +6698,4,9 +6699,5,10 +6700,1,1 +6701,2,2 +6702,3,3 +6703,4,4 +6704,5,5 +6705,1,6 +6706,2,7 +6707,3,8 +6708,4,9 +6709,5,10 +6710,1,1 +6711,2,2 +6712,3,3 +6713,4,4 +6714,5,5 +6715,1,6 +6716,2,7 +6717,3,8 +6718,4,9 +6719,5,10 +6720,1,1 +6721,2,2 +6722,3,3 +6723,4,4 +6724,5,5 +6725,1,6 +6726,2,7 +6727,3,8 +6728,4,9 +6729,5,10 +6730,1,1 +6731,2,2 +6732,3,3 +6733,4,4 +6734,5,5 +6735,1,6 +6736,2,7 +6737,3,8 +6738,4,9 +6739,5,10 +6740,1,1 +6741,2,2 +6742,3,3 +6743,4,4 +6744,5,5 +6745,1,6 +6746,2,7 +6747,3,8 +6748,4,9 +6749,5,10 +6750,1,1 +6751,2,2 +6752,3,3 +6753,4,4 +6754,5,5 +6755,1,6 +6756,2,7 +6757,3,8 +6758,4,9 +6759,5,10 +6760,1,1 +6761,2,2 +6762,3,3 +6763,4,4 +6764,5,5 +6765,1,6 +6766,2,7 +6767,3,8 +6768,4,9 +6769,5,10 +6770,1,1 +6771,2,2 +6772,3,3 +6773,4,4 +6774,5,5 +6775,1,6 +6776,2,7 +6777,3,8 +6778,4,9 +6779,5,10 +6780,1,1 +6781,2,2 +6782,3,3 +6783,4,4 +6784,5,5 +6785,1,6 +6786,2,7 +6787,3,8 +6788,4,9 +6789,5,10 +6790,1,1 +6791,2,2 +6792,3,3 +6793,4,4 +6794,5,5 +6795,1,6 +6796,2,7 +6797,3,8 +6798,4,9 +6799,5,10 +6800,1,1 +6801,2,2 +6802,3,3 +6803,4,4 +6804,5,5 +6805,1,6 +6806,2,7 +6807,3,8 +6808,4,9 +6809,5,10 +6810,1,1 +6811,2,2 +6812,3,3 +6813,4,4 +6814,5,5 +6815,1,6 +6816,2,7 +6817,3,8 +6818,4,9 +6819,5,10 +6820,1,1 +6821,2,2 +6822,3,3 +6823,4,4 +6824,5,5 +6825,1,6 +6826,2,7 +6827,3,8 +6828,4,9 +6829,5,10 +6830,1,1 +6831,2,2 +6832,3,3 +6833,4,4 +6834,5,5 +6835,1,6 +6836,2,7 +6837,3,8 +6838,4,9 +6839,5,10 +6840,1,1 +6841,2,2 +6842,3,3 +6843,4,4 +6844,5,5 +6845,1,6 +6846,2,7 +6847,3,8 +6848,4,9 +6849,5,10 +6850,1,1 +6851,2,2 +6852,3,3 +6853,4,4 +6854,5,5 +6855,1,6 +6856,2,7 +6857,3,8 +6858,4,9 +6859,5,10 +6860,1,1 +6861,2,2 +6862,3,3 +6863,4,4 +6864,5,5 +6865,1,6 +6866,2,7 +6867,3,8 +6868,4,9 +6869,5,10 +6870,1,1 +6871,2,2 +6872,3,3 +6873,4,4 +6874,5,5 +6875,1,6 +6876,2,7 +6877,3,8 +6878,4,9 +6879,5,10 +6880,1,1 +6881,2,2 +6882,3,3 +6883,4,4 +6884,5,5 +6885,1,6 +6886,2,7 +6887,3,8 +6888,4,9 +6889,5,10 +6890,1,1 +6891,2,2 +6892,3,3 +6893,4,4 +6894,5,5 +6895,1,6 +6896,2,7 +6897,3,8 +6898,4,9 +6899,5,10 +6900,1,1 +6901,2,2 +6902,3,3 +6903,4,4 +6904,5,5 +6905,1,6 +6906,2,7 +6907,3,8 +6908,4,9 +6909,5,10 +6910,1,1 +6911,2,2 +6912,3,3 +6913,4,4 +6914,5,5 +6915,1,6 +6916,2,7 +6917,3,8 +6918,4,9 +6919,5,10 +6920,1,1 +6921,2,2 +6922,3,3 +6923,4,4 +6924,5,5 +6925,1,6 +6926,2,7 +6927,3,8 +6928,4,9 +6929,5,10 +6930,1,1 +6931,2,2 +6932,3,3 +6933,4,4 +6934,5,5 +6935,1,6 +6936,2,7 +6937,3,8 +6938,4,9 +6939,5,10 +6940,1,1 +6941,2,2 +6942,3,3 +6943,4,4 +6944,5,5 +6945,1,6 +6946,2,7 +6947,3,8 +6948,4,9 +6949,5,10 +6950,1,1 +6951,2,2 +6952,3,3 +6953,4,4 +6954,5,5 +6955,1,6 +6956,2,7 +6957,3,8 +6958,4,9 +6959,5,10 +6960,1,1 +6961,2,2 +6962,3,3 +6963,4,4 +6964,5,5 +6965,1,6 +6966,2,7 +6967,3,8 +6968,4,9 +6969,5,10 +6970,1,1 +6971,2,2 +6972,3,3 +6973,4,4 +6974,5,5 +6975,1,6 +6976,2,7 +6977,3,8 +6978,4,9 +6979,5,10 +6980,1,1 +6981,2,2 +6982,3,3 +6983,4,4 +6984,5,5 +6985,1,6 +6986,2,7 +6987,3,8 +6988,4,9 +6989,5,10 +6990,1,1 +6991,2,2 +6992,3,3 +6993,4,4 +6994,5,5 +6995,1,6 +6996,2,7 +6997,3,8 +6998,4,9 +6999,5,10 +7000,1,1 +7001,2,2 +7002,3,3 +7003,4,4 +7004,5,5 +7005,1,6 +7006,2,7 +7007,3,8 +7008,4,9 +7009,5,10 +7010,1,1 +7011,2,2 +7012,3,3 +7013,4,4 +7014,5,5 +7015,1,6 +7016,2,7 +7017,3,8 +7018,4,9 +7019,5,10 +7020,1,1 +7021,2,2 +7022,3,3 +7023,4,4 +7024,5,5 +7025,1,6 +7026,2,7 +7027,3,8 +7028,4,9 +7029,5,10 +7030,1,1 +7031,2,2 +7032,3,3 +7033,4,4 +7034,5,5 +7035,1,6 +7036,2,7 +7037,3,8 +7038,4,9 +7039,5,10 +7040,1,1 +7041,2,2 +7042,3,3 +7043,4,4 +7044,5,5 +7045,1,6 +7046,2,7 +7047,3,8 +7048,4,9 +7049,5,10 +7050,1,1 +7051,2,2 +7052,3,3 +7053,4,4 +7054,5,5 +7055,1,6 +7056,2,7 +7057,3,8 +7058,4,9 +7059,5,10 +7060,1,1 +7061,2,2 +7062,3,3 +7063,4,4 +7064,5,5 +7065,1,6 +7066,2,7 +7067,3,8 +7068,4,9 +7069,5,10 +7070,1,1 +7071,2,2 +7072,3,3 +7073,4,4 +7074,5,5 +7075,1,6 +7076,2,7 +7077,3,8 +7078,4,9 +7079,5,10 +7080,1,1 +7081,2,2 +7082,3,3 +7083,4,4 +7084,5,5 +7085,1,6 +7086,2,7 +7087,3,8 +7088,4,9 +7089,5,10 +7090,1,1 +7091,2,2 +7092,3,3 +7093,4,4 +7094,5,5 +7095,1,6 +7096,2,7 +7097,3,8 +7098,4,9 +7099,5,10 +7100,1,1 +7101,2,2 +7102,3,3 +7103,4,4 +7104,5,5 +7105,1,6 +7106,2,7 +7107,3,8 +7108,4,9 +7109,5,10 +7110,1,1 +7111,2,2 +7112,3,3 +7113,4,4 +7114,5,5 +7115,1,6 +7116,2,7 +7117,3,8 +7118,4,9 +7119,5,10 +7120,1,1 +7121,2,2 +7122,3,3 +7123,4,4 +7124,5,5 +7125,1,6 +7126,2,7 +7127,3,8 +7128,4,9 +7129,5,10 +7130,1,1 +7131,2,2 +7132,3,3 +7133,4,4 +7134,5,5 +7135,1,6 +7136,2,7 +7137,3,8 +7138,4,9 +7139,5,10 +7140,1,1 +7141,2,2 +7142,3,3 +7143,4,4 +7144,5,5 +7145,1,6 +7146,2,7 +7147,3,8 +7148,4,9 +7149,5,10 +7150,1,1 +7151,2,2 +7152,3,3 +7153,4,4 +7154,5,5 +7155,1,6 +7156,2,7 +7157,3,8 +7158,4,9 +7159,5,10 +7160,1,1 +7161,2,2 +7162,3,3 +7163,4,4 +7164,5,5 +7165,1,6 +7166,2,7 +7167,3,8 +7168,4,9 +7169,5,10 +7170,1,1 +7171,2,2 +7172,3,3 +7173,4,4 +7174,5,5 +7175,1,6 +7176,2,7 +7177,3,8 +7178,4,9 +7179,5,10 +7180,1,1 +7181,2,2 +7182,3,3 +7183,4,4 +7184,5,5 +7185,1,6 +7186,2,7 +7187,3,8 +7188,4,9 +7189,5,10 +7190,1,1 +7191,2,2 +7192,3,3 +7193,4,4 +7194,5,5 +7195,1,6 +7196,2,7 +7197,3,8 +7198,4,9 +7199,5,10 +7200,1,1 +7201,2,2 +7202,3,3 +7203,4,4 +7204,5,5 +7205,1,6 +7206,2,7 +7207,3,8 +7208,4,9 +7209,5,10 +7210,1,1 +7211,2,2 +7212,3,3 +7213,4,4 +7214,5,5 +7215,1,6 +7216,2,7 +7217,3,8 +7218,4,9 +7219,5,10 +7220,1,1 +7221,2,2 +7222,3,3 +7223,4,4 +7224,5,5 +7225,1,6 +7226,2,7 +7227,3,8 +7228,4,9 +7229,5,10 +7230,1,1 +7231,2,2 +7232,3,3 +7233,4,4 +7234,5,5 +7235,1,6 +7236,2,7 +7237,3,8 +7238,4,9 +7239,5,10 +7240,1,1 +7241,2,2 +7242,3,3 +7243,4,4 +7244,5,5 +7245,1,6 +7246,2,7 +7247,3,8 +7248,4,9 +7249,5,10 +7250,1,1 +7251,2,2 +7252,3,3 +7253,4,4 +7254,5,5 +7255,1,6 +7256,2,7 +7257,3,8 +7258,4,9 +7259,5,10 +7260,1,1 +7261,2,2 +7262,3,3 +7263,4,4 +7264,5,5 +7265,1,6 +7266,2,7 +7267,3,8 +7268,4,9 +7269,5,10 +7270,1,1 +7271,2,2 +7272,3,3 +7273,4,4 +7274,5,5 +7275,1,6 +7276,2,7 +7277,3,8 +7278,4,9 +7279,5,10 +7280,1,1 +7281,2,2 +7282,3,3 +7283,4,4 +7284,5,5 +7285,1,6 +7286,2,7 +7287,3,8 +7288,4,9 +7289,5,10 +7290,1,1 +7291,2,2 +7292,3,3 +7293,4,4 +7294,5,5 +7295,1,6 +7296,2,7 +7297,3,8 +7298,4,9 +7299,5,10 +7300,1,1 +7301,2,2 +7302,3,3 +7303,4,4 +7304,5,5 +7305,1,6 +7306,2,7 +7307,3,8 +7308,4,9 +7309,5,10 +7310,1,1 +7311,2,2 +7312,3,3 +7313,4,4 +7314,5,5 +7315,1,6 +7316,2,7 +7317,3,8 +7318,4,9 +7319,5,10 +7320,1,1 +7321,2,2 +7322,3,3 +7323,4,4 +7324,5,5 +7325,1,6 +7326,2,7 +7327,3,8 +7328,4,9 +7329,5,10 +7330,1,1 +7331,2,2 +7332,3,3 +7333,4,4 +7334,5,5 +7335,1,6 +7336,2,7 +7337,3,8 +7338,4,9 +7339,5,10 +7340,1,1 +7341,2,2 +7342,3,3 +7343,4,4 +7344,5,5 +7345,1,6 +7346,2,7 +7347,3,8 +7348,4,9 +7349,5,10 +7350,1,1 +7351,2,2 +7352,3,3 +7353,4,4 +7354,5,5 +7355,1,6 +7356,2,7 +7357,3,8 +7358,4,9 +7359,5,10 +7360,1,1 +7361,2,2 +7362,3,3 +7363,4,4 +7364,5,5 +7365,1,6 +7366,2,7 +7367,3,8 +7368,4,9 +7369,5,10 +7370,1,1 +7371,2,2 +7372,3,3 +7373,4,4 +7374,5,5 +7375,1,6 +7376,2,7 +7377,3,8 +7378,4,9 +7379,5,10 +7380,1,1 +7381,2,2 +7382,3,3 +7383,4,4 +7384,5,5 +7385,1,6 +7386,2,7 +7387,3,8 +7388,4,9 +7389,5,10 +7390,1,1 +7391,2,2 +7392,3,3 +7393,4,4 +7394,5,5 +7395,1,6 +7396,2,7 +7397,3,8 +7398,4,9 +7399,5,10 +7400,1,1 +7401,2,2 +7402,3,3 +7403,4,4 +7404,5,5 +7405,1,6 +7406,2,7 +7407,3,8 +7408,4,9 +7409,5,10 +7410,1,1 +7411,2,2 +7412,3,3 +7413,4,4 +7414,5,5 +7415,1,6 +7416,2,7 +7417,3,8 +7418,4,9 +7419,5,10 +7420,1,1 +7421,2,2 +7422,3,3 +7423,4,4 +7424,5,5 +7425,1,6 +7426,2,7 +7427,3,8 +7428,4,9 +7429,5,10 +7430,1,1 +7431,2,2 +7432,3,3 +7433,4,4 +7434,5,5 +7435,1,6 +7436,2,7 +7437,3,8 +7438,4,9 +7439,5,10 +7440,1,1 +7441,2,2 +7442,3,3 +7443,4,4 +7444,5,5 +7445,1,6 +7446,2,7 +7447,3,8 +7448,4,9 +7449,5,10 +7450,1,1 +7451,2,2 +7452,3,3 +7453,4,4 +7454,5,5 +7455,1,6 +7456,2,7 +7457,3,8 +7458,4,9 +7459,5,10 +7460,1,1 +7461,2,2 +7462,3,3 +7463,4,4 +7464,5,5 +7465,1,6 +7466,2,7 +7467,3,8 +7468,4,9 +7469,5,10 +7470,1,1 +7471,2,2 +7472,3,3 +7473,4,4 +7474,5,5 +7475,1,6 +7476,2,7 +7477,3,8 +7478,4,9 +7479,5,10 +7480,1,1 +7481,2,2 +7482,3,3 +7483,4,4 +7484,5,5 +7485,1,6 +7486,2,7 +7487,3,8 +7488,4,9 +7489,5,10 +7490,1,1 +7491,2,2 +7492,3,3 +7493,4,4 +7494,5,5 +7495,1,6 +7496,2,7 +7497,3,8 +7498,4,9 +7499,5,10 +7500,1,1 +7501,2,2 +7502,3,3 +7503,4,4 +7504,5,5 +7505,1,6 +7506,2,7 +7507,3,8 +7508,4,9 +7509,5,10 +7510,1,1 +7511,2,2 +7512,3,3 +7513,4,4 +7514,5,5 +7515,1,6 +7516,2,7 +7517,3,8 +7518,4,9 +7519,5,10 +7520,1,1 +7521,2,2 +7522,3,3 +7523,4,4 +7524,5,5 +7525,1,6 +7526,2,7 +7527,3,8 +7528,4,9 +7529,5,10 +7530,1,1 +7531,2,2 +7532,3,3 +7533,4,4 +7534,5,5 +7535,1,6 +7536,2,7 +7537,3,8 +7538,4,9 +7539,5,10 +7540,1,1 +7541,2,2 +7542,3,3 +7543,4,4 +7544,5,5 +7545,1,6 +7546,2,7 +7547,3,8 +7548,4,9 +7549,5,10 +7550,1,1 +7551,2,2 +7552,3,3 +7553,4,4 +7554,5,5 +7555,1,6 +7556,2,7 +7557,3,8 +7558,4,9 +7559,5,10 +7560,1,1 +7561,2,2 +7562,3,3 +7563,4,4 +7564,5,5 +7565,1,6 +7566,2,7 +7567,3,8 +7568,4,9 +7569,5,10 +7570,1,1 +7571,2,2 +7572,3,3 +7573,4,4 +7574,5,5 +7575,1,6 +7576,2,7 +7577,3,8 +7578,4,9 +7579,5,10 +7580,1,1 +7581,2,2 +7582,3,3 +7583,4,4 +7584,5,5 +7585,1,6 +7586,2,7 +7587,3,8 +7588,4,9 +7589,5,10 +7590,1,1 +7591,2,2 +7592,3,3 +7593,4,4 +7594,5,5 +7595,1,6 +7596,2,7 +7597,3,8 +7598,4,9 +7599,5,10 +7600,1,1 +7601,2,2 +7602,3,3 +7603,4,4 +7604,5,5 +7605,1,6 +7606,2,7 +7607,3,8 +7608,4,9 +7609,5,10 +7610,1,1 +7611,2,2 +7612,3,3 +7613,4,4 +7614,5,5 +7615,1,6 +7616,2,7 +7617,3,8 +7618,4,9 +7619,5,10 +7620,1,1 +7621,2,2 +7622,3,3 +7623,4,4 +7624,5,5 +7625,1,6 +7626,2,7 +7627,3,8 +7628,4,9 +7629,5,10 +7630,1,1 +7631,2,2 +7632,3,3 +7633,4,4 +7634,5,5 +7635,1,6 +7636,2,7 +7637,3,8 +7638,4,9 +7639,5,10 +7640,1,1 +7641,2,2 +7642,3,3 +7643,4,4 +7644,5,5 +7645,1,6 +7646,2,7 +7647,3,8 +7648,4,9 +7649,5,10 +7650,1,1 +7651,2,2 +7652,3,3 +7653,4,4 +7654,5,5 +7655,1,6 +7656,2,7 +7657,3,8 +7658,4,9 +7659,5,10 +7660,1,1 +7661,2,2 +7662,3,3 +7663,4,4 +7664,5,5 +7665,1,6 +7666,2,7 +7667,3,8 +7668,4,9 +7669,5,10 +7670,1,1 +7671,2,2 +7672,3,3 +7673,4,4 +7674,5,5 +7675,1,6 +7676,2,7 +7677,3,8 +7678,4,9 +7679,5,10 +7680,1,1 +7681,2,2 +7682,3,3 +7683,4,4 +7684,5,5 +7685,1,6 +7686,2,7 +7687,3,8 +7688,4,9 +7689,5,10 +7690,1,1 +7691,2,2 +7692,3,3 +7693,4,4 +7694,5,5 +7695,1,6 +7696,2,7 +7697,3,8 +7698,4,9 +7699,5,10 +7700,1,1 +7701,2,2 +7702,3,3 +7703,4,4 +7704,5,5 +7705,1,6 +7706,2,7 +7707,3,8 +7708,4,9 +7709,5,10 +7710,1,1 +7711,2,2 +7712,3,3 +7713,4,4 +7714,5,5 +7715,1,6 +7716,2,7 +7717,3,8 +7718,4,9 +7719,5,10 +7720,1,1 +7721,2,2 +7722,3,3 +7723,4,4 +7724,5,5 +7725,1,6 +7726,2,7 +7727,3,8 +7728,4,9 +7729,5,10 +7730,1,1 +7731,2,2 +7732,3,3 +7733,4,4 +7734,5,5 +7735,1,6 +7736,2,7 +7737,3,8 +7738,4,9 +7739,5,10 +7740,1,1 +7741,2,2 +7742,3,3 +7743,4,4 +7744,5,5 +7745,1,6 +7746,2,7 +7747,3,8 +7748,4,9 +7749,5,10 +7750,1,1 +7751,2,2 +7752,3,3 +7753,4,4 +7754,5,5 +7755,1,6 +7756,2,7 +7757,3,8 +7758,4,9 +7759,5,10 +7760,1,1 +7761,2,2 +7762,3,3 +7763,4,4 +7764,5,5 +7765,1,6 +7766,2,7 +7767,3,8 +7768,4,9 +7769,5,10 +7770,1,1 +7771,2,2 +7772,3,3 +7773,4,4 +7774,5,5 +7775,1,6 +7776,2,7 +7777,3,8 +7778,4,9 +7779,5,10 +7780,1,1 +7781,2,2 +7782,3,3 +7783,4,4 +7784,5,5 +7785,1,6 +7786,2,7 +7787,3,8 +7788,4,9 +7789,5,10 +7790,1,1 +7791,2,2 +7792,3,3 +7793,4,4 +7794,5,5 +7795,1,6 +7796,2,7 +7797,3,8 +7798,4,9 +7799,5,10 +7800,1,1 +7801,2,2 +7802,3,3 +7803,4,4 +7804,5,5 +7805,1,6 +7806,2,7 +7807,3,8 +7808,4,9 +7809,5,10 +7810,1,1 +7811,2,2 +7812,3,3 +7813,4,4 +7814,5,5 +7815,1,6 +7816,2,7 +7817,3,8 +7818,4,9 +7819,5,10 +7820,1,1 +7821,2,2 +7822,3,3 +7823,4,4 +7824,5,5 +7825,1,6 +7826,2,7 +7827,3,8 +7828,4,9 +7829,5,10 +7830,1,1 +7831,2,2 +7832,3,3 +7833,4,4 +7834,5,5 +7835,1,6 +7836,2,7 +7837,3,8 +7838,4,9 +7839,5,10 +7840,1,1 +7841,2,2 +7842,3,3 +7843,4,4 +7844,5,5 +7845,1,6 +7846,2,7 +7847,3,8 +7848,4,9 +7849,5,10 +7850,1,1 +7851,2,2 +7852,3,3 +7853,4,4 +7854,5,5 +7855,1,6 +7856,2,7 +7857,3,8 +7858,4,9 +7859,5,10 +7860,1,1 +7861,2,2 +7862,3,3 +7863,4,4 +7864,5,5 +7865,1,6 +7866,2,7 +7867,3,8 +7868,4,9 +7869,5,10 +7870,1,1 +7871,2,2 +7872,3,3 +7873,4,4 +7874,5,5 +7875,1,6 +7876,2,7 +7877,3,8 +7878,4,9 +7879,5,10 +7880,1,1 +7881,2,2 +7882,3,3 +7883,4,4 +7884,5,5 +7885,1,6 +7886,2,7 +7887,3,8 +7888,4,9 +7889,5,10 +7890,1,1 +7891,2,2 +7892,3,3 +7893,4,4 +7894,5,5 +7895,1,6 +7896,2,7 +7897,3,8 +7898,4,9 +7899,5,10 +7900,1,1 +7901,2,2 +7902,3,3 +7903,4,4 +7904,5,5 +7905,1,6 +7906,2,7 +7907,3,8 +7908,4,9 +7909,5,10 +7910,1,1 +7911,2,2 +7912,3,3 +7913,4,4 +7914,5,5 +7915,1,6 +7916,2,7 +7917,3,8 +7918,4,9 +7919,5,10 +7920,1,1 +7921,2,2 +7922,3,3 +7923,4,4 +7924,5,5 +7925,1,6 +7926,2,7 +7927,3,8 +7928,4,9 +7929,5,10 +7930,1,1 +7931,2,2 +7932,3,3 +7933,4,4 +7934,5,5 +7935,1,6 +7936,2,7 +7937,3,8 +7938,4,9 +7939,5,10 +7940,1,1 +7941,2,2 +7942,3,3 +7943,4,4 +7944,5,5 +7945,1,6 +7946,2,7 +7947,3,8 +7948,4,9 +7949,5,10 +7950,1,1 +7951,2,2 +7952,3,3 +7953,4,4 +7954,5,5 +7955,1,6 +7956,2,7 +7957,3,8 +7958,4,9 +7959,5,10 +7960,1,1 +7961,2,2 +7962,3,3 +7963,4,4 +7964,5,5 +7965,1,6 +7966,2,7 +7967,3,8 +7968,4,9 +7969,5,10 +7970,1,1 +7971,2,2 +7972,3,3 +7973,4,4 +7974,5,5 +7975,1,6 +7976,2,7 +7977,3,8 +7978,4,9 +7979,5,10 +7980,1,1 +7981,2,2 +7982,3,3 +7983,4,4 +7984,5,5 +7985,1,6 +7986,2,7 +7987,3,8 +7988,4,9 +7989,5,10 +7990,1,1 +7991,2,2 +7992,3,3 +7993,4,4 +7994,5,5 +7995,1,6 +7996,2,7 +7997,3,8 +7998,4,9 +7999,5,10 +8000,1,1 +8001,2,2 +8002,3,3 +8003,4,4 +8004,5,5 +8005,1,6 +8006,2,7 +8007,3,8 +8008,4,9 +8009,5,10 +8010,1,1 +8011,2,2 +8012,3,3 +8013,4,4 +8014,5,5 +8015,1,6 +8016,2,7 +8017,3,8 +8018,4,9 +8019,5,10 +8020,1,1 +8021,2,2 +8022,3,3 +8023,4,4 +8024,5,5 +8025,1,6 +8026,2,7 +8027,3,8 +8028,4,9 +8029,5,10 +8030,1,1 +8031,2,2 +8032,3,3 +8033,4,4 +8034,5,5 +8035,1,6 +8036,2,7 +8037,3,8 +8038,4,9 +8039,5,10 +8040,1,1 +8041,2,2 +8042,3,3 +8043,4,4 +8044,5,5 +8045,1,6 +8046,2,7 +8047,3,8 +8048,4,9 +8049,5,10 +8050,1,1 +8051,2,2 +8052,3,3 +8053,4,4 +8054,5,5 +8055,1,6 +8056,2,7 +8057,3,8 +8058,4,9 +8059,5,10 +8060,1,1 +8061,2,2 +8062,3,3 +8063,4,4 +8064,5,5 +8065,1,6 +8066,2,7 +8067,3,8 +8068,4,9 +8069,5,10 +8070,1,1 +8071,2,2 +8072,3,3 +8073,4,4 +8074,5,5 +8075,1,6 +8076,2,7 +8077,3,8 +8078,4,9 +8079,5,10 +8080,1,1 +8081,2,2 +8082,3,3 +8083,4,4 +8084,5,5 +8085,1,6 +8086,2,7 +8087,3,8 +8088,4,9 +8089,5,10 +8090,1,1 +8091,2,2 +8092,3,3 +8093,4,4 +8094,5,5 +8095,1,6 +8096,2,7 +8097,3,8 +8098,4,9 +8099,5,10 +8100,1,1 +8101,2,2 +8102,3,3 +8103,4,4 +8104,5,5 +8105,1,6 +8106,2,7 +8107,3,8 +8108,4,9 +8109,5,10 +8110,1,1 +8111,2,2 +8112,3,3 +8113,4,4 +8114,5,5 +8115,1,6 +8116,2,7 +8117,3,8 +8118,4,9 +8119,5,10 +8120,1,1 +8121,2,2 +8122,3,3 +8123,4,4 +8124,5,5 +8125,1,6 +8126,2,7 +8127,3,8 +8128,4,9 +8129,5,10 +8130,1,1 +8131,2,2 +8132,3,3 +8133,4,4 +8134,5,5 +8135,1,6 +8136,2,7 +8137,3,8 +8138,4,9 +8139,5,10 +8140,1,1 +8141,2,2 +8142,3,3 +8143,4,4 +8144,5,5 +8145,1,6 +8146,2,7 +8147,3,8 +8148,4,9 +8149,5,10 +8150,1,1 +8151,2,2 +8152,3,3 +8153,4,4 +8154,5,5 +8155,1,6 +8156,2,7 +8157,3,8 +8158,4,9 +8159,5,10 +8160,1,1 +8161,2,2 +8162,3,3 +8163,4,4 +8164,5,5 +8165,1,6 +8166,2,7 +8167,3,8 +8168,4,9 +8169,5,10 +8170,1,1 +8171,2,2 +8172,3,3 +8173,4,4 +8174,5,5 +8175,1,6 +8176,2,7 +8177,3,8 +8178,4,9 +8179,5,10 +8180,1,1 +8181,2,2 +8182,3,3 +8183,4,4 +8184,5,5 +8185,1,6 +8186,2,7 +8187,3,8 +8188,4,9 +8189,5,10 +8190,1,1 +8191,2,2 +8192,3,3 +8193,4,4 +8194,5,5 +8195,1,6 +8196,2,7 +8197,3,8 +8198,4,9 +8199,5,10 +8200,1,1 +8201,2,2 +8202,3,3 +8203,4,4 +8204,5,5 +8205,1,6 +8206,2,7 +8207,3,8 +8208,4,9 +8209,5,10 +8210,1,1 +8211,2,2 +8212,3,3 +8213,4,4 +8214,5,5 +8215,1,6 +8216,2,7 +8217,3,8 +8218,4,9 +8219,5,10 +8220,1,1 +8221,2,2 +8222,3,3 +8223,4,4 +8224,5,5 +8225,1,6 +8226,2,7 +8227,3,8 +8228,4,9 +8229,5,10 +8230,1,1 +8231,2,2 +8232,3,3 +8233,4,4 +8234,5,5 +8235,1,6 +8236,2,7 +8237,3,8 +8238,4,9 +8239,5,10 +8240,1,1 +8241,2,2 +8242,3,3 +8243,4,4 +8244,5,5 +8245,1,6 +8246,2,7 +8247,3,8 +8248,4,9 +8249,5,10 +8250,1,1 +8251,2,2 +8252,3,3 +8253,4,4 +8254,5,5 +8255,1,6 +8256,2,7 +8257,3,8 +8258,4,9 +8259,5,10 +8260,1,1 +8261,2,2 +8262,3,3 +8263,4,4 +8264,5,5 +8265,1,6 +8266,2,7 +8267,3,8 +8268,4,9 +8269,5,10 +8270,1,1 +8271,2,2 +8272,3,3 +8273,4,4 +8274,5,5 +8275,1,6 +8276,2,7 +8277,3,8 +8278,4,9 +8279,5,10 +8280,1,1 +8281,2,2 +8282,3,3 +8283,4,4 +8284,5,5 +8285,1,6 +8286,2,7 +8287,3,8 +8288,4,9 +8289,5,10 +8290,1,1 +8291,2,2 +8292,3,3 +8293,4,4 +8294,5,5 +8295,1,6 +8296,2,7 +8297,3,8 +8298,4,9 +8299,5,10 +8300,1,1 +8301,2,2 +8302,3,3 +8303,4,4 +8304,5,5 +8305,1,6 +8306,2,7 +8307,3,8 +8308,4,9 +8309,5,10 +8310,1,1 +8311,2,2 +8312,3,3 +8313,4,4 +8314,5,5 +8315,1,6 +8316,2,7 +8317,3,8 +8318,4,9 +8319,5,10 +8320,1,1 +8321,2,2 +8322,3,3 +8323,4,4 +8324,5,5 +8325,1,6 +8326,2,7 +8327,3,8 +8328,4,9 +8329,5,10 +8330,1,1 +8331,2,2 +8332,3,3 +8333,4,4 +8334,5,5 +8335,1,6 +8336,2,7 +8337,3,8 +8338,4,9 +8339,5,10 +8340,1,1 +8341,2,2 +8342,3,3 +8343,4,4 +8344,5,5 +8345,1,6 +8346,2,7 +8347,3,8 +8348,4,9 +8349,5,10 +8350,1,1 +8351,2,2 +8352,3,3 +8353,4,4 +8354,5,5 +8355,1,6 +8356,2,7 +8357,3,8 +8358,4,9 +8359,5,10 +8360,1,1 +8361,2,2 +8362,3,3 +8363,4,4 +8364,5,5 +8365,1,6 +8366,2,7 +8367,3,8 +8368,4,9 +8369,5,10 +8370,1,1 +8371,2,2 +8372,3,3 +8373,4,4 +8374,5,5 +8375,1,6 +8376,2,7 +8377,3,8 +8378,4,9 +8379,5,10 +8380,1,1 +8381,2,2 +8382,3,3 +8383,4,4 +8384,5,5 +8385,1,6 +8386,2,7 +8387,3,8 +8388,4,9 +8389,5,10 +8390,1,1 +8391,2,2 +8392,3,3 +8393,4,4 +8394,5,5 +8395,1,6 +8396,2,7 +8397,3,8 +8398,4,9 +8399,5,10 +8400,1,1 +8401,2,2 +8402,3,3 +8403,4,4 +8404,5,5 +8405,1,6 +8406,2,7 +8407,3,8 +8408,4,9 +8409,5,10 +8410,1,1 +8411,2,2 +8412,3,3 +8413,4,4 +8414,5,5 +8415,1,6 +8416,2,7 +8417,3,8 +8418,4,9 +8419,5,10 +8420,1,1 +8421,2,2 +8422,3,3 +8423,4,4 +8424,5,5 +8425,1,6 +8426,2,7 +8427,3,8 +8428,4,9 +8429,5,10 +8430,1,1 +8431,2,2 +8432,3,3 +8433,4,4 +8434,5,5 +8435,1,6 +8436,2,7 +8437,3,8 +8438,4,9 +8439,5,10 +8440,1,1 +8441,2,2 +8442,3,3 +8443,4,4 +8444,5,5 +8445,1,6 +8446,2,7 +8447,3,8 +8448,4,9 +8449,5,10 +8450,1,1 +8451,2,2 +8452,3,3 +8453,4,4 +8454,5,5 +8455,1,6 +8456,2,7 +8457,3,8 +8458,4,9 +8459,5,10 +8460,1,1 +8461,2,2 +8462,3,3 +8463,4,4 +8464,5,5 +8465,1,6 +8466,2,7 +8467,3,8 +8468,4,9 +8469,5,10 +8470,1,1 +8471,2,2 +8472,3,3 +8473,4,4 +8474,5,5 +8475,1,6 +8476,2,7 +8477,3,8 +8478,4,9 +8479,5,10 +8480,1,1 +8481,2,2 +8482,3,3 +8483,4,4 +8484,5,5 +8485,1,6 +8486,2,7 +8487,3,8 +8488,4,9 +8489,5,10 +8490,1,1 +8491,2,2 +8492,3,3 +8493,4,4 +8494,5,5 +8495,1,6 +8496,2,7 +8497,3,8 +8498,4,9 +8499,5,10 +8500,1,1 +8501,2,2 +8502,3,3 +8503,4,4 +8504,5,5 +8505,1,6 +8506,2,7 +8507,3,8 +8508,4,9 +8509,5,10 +8510,1,1 +8511,2,2 +8512,3,3 +8513,4,4 +8514,5,5 +8515,1,6 +8516,2,7 +8517,3,8 +8518,4,9 +8519,5,10 +8520,1,1 +8521,2,2 +8522,3,3 +8523,4,4 +8524,5,5 +8525,1,6 +8526,2,7 +8527,3,8 +8528,4,9 +8529,5,10 +8530,1,1 +8531,2,2 +8532,3,3 +8533,4,4 +8534,5,5 +8535,1,6 +8536,2,7 +8537,3,8 +8538,4,9 +8539,5,10 +8540,1,1 +8541,2,2 +8542,3,3 +8543,4,4 +8544,5,5 +8545,1,6 +8546,2,7 +8547,3,8 +8548,4,9 +8549,5,10 +8550,1,1 +8551,2,2 +8552,3,3 +8553,4,4 +8554,5,5 +8555,1,6 +8556,2,7 +8557,3,8 +8558,4,9 +8559,5,10 +8560,1,1 +8561,2,2 +8562,3,3 +8563,4,4 +8564,5,5 +8565,1,6 +8566,2,7 +8567,3,8 +8568,4,9 +8569,5,10 +8570,1,1 +8571,2,2 +8572,3,3 +8573,4,4 +8574,5,5 +8575,1,6 +8576,2,7 +8577,3,8 +8578,4,9 +8579,5,10 +8580,1,1 +8581,2,2 +8582,3,3 +8583,4,4 +8584,5,5 +8585,1,6 +8586,2,7 +8587,3,8 +8588,4,9 +8589,5,10 +8590,1,1 +8591,2,2 +8592,3,3 +8593,4,4 +8594,5,5 +8595,1,6 +8596,2,7 +8597,3,8 +8598,4,9 +8599,5,10 +8600,1,1 +8601,2,2 +8602,3,3 +8603,4,4 +8604,5,5 +8605,1,6 +8606,2,7 +8607,3,8 +8608,4,9 +8609,5,10 +8610,1,1 +8611,2,2 +8612,3,3 +8613,4,4 +8614,5,5 +8615,1,6 +8616,2,7 +8617,3,8 +8618,4,9 +8619,5,10 +8620,1,1 +8621,2,2 +8622,3,3 +8623,4,4 +8624,5,5 +8625,1,6 +8626,2,7 +8627,3,8 +8628,4,9 +8629,5,10 +8630,1,1 +8631,2,2 +8632,3,3 +8633,4,4 +8634,5,5 +8635,1,6 +8636,2,7 +8637,3,8 +8638,4,9 +8639,5,10 +8640,1,1 +8641,2,2 +8642,3,3 +8643,4,4 +8644,5,5 +8645,1,6 +8646,2,7 +8647,3,8 +8648,4,9 +8649,5,10 +8650,1,1 +8651,2,2 +8652,3,3 +8653,4,4 +8654,5,5 +8655,1,6 +8656,2,7 +8657,3,8 +8658,4,9 +8659,5,10 +8660,1,1 +8661,2,2 +8662,3,3 +8663,4,4 +8664,5,5 +8665,1,6 +8666,2,7 +8667,3,8 +8668,4,9 +8669,5,10 +8670,1,1 +8671,2,2 +8672,3,3 +8673,4,4 +8674,5,5 +8675,1,6 +8676,2,7 +8677,3,8 +8678,4,9 +8679,5,10 +8680,1,1 +8681,2,2 +8682,3,3 +8683,4,4 +8684,5,5 +8685,1,6 +8686,2,7 +8687,3,8 +8688,4,9 +8689,5,10 +8690,1,1 +8691,2,2 +8692,3,3 +8693,4,4 +8694,5,5 +8695,1,6 +8696,2,7 +8697,3,8 +8698,4,9 +8699,5,10 +8700,1,1 +8701,2,2 +8702,3,3 +8703,4,4 +8704,5,5 +8705,1,6 +8706,2,7 +8707,3,8 +8708,4,9 +8709,5,10 +8710,1,1 +8711,2,2 +8712,3,3 +8713,4,4 +8714,5,5 +8715,1,6 +8716,2,7 +8717,3,8 +8718,4,9 +8719,5,10 +8720,1,1 +8721,2,2 +8722,3,3 +8723,4,4 +8724,5,5 +8725,1,6 +8726,2,7 +8727,3,8 +8728,4,9 +8729,5,10 +8730,1,1 +8731,2,2 +8732,3,3 +8733,4,4 +8734,5,5 +8735,1,6 +8736,2,7 +8737,3,8 +8738,4,9 +8739,5,10 +8740,1,1 +8741,2,2 +8742,3,3 +8743,4,4 +8744,5,5 +8745,1,6 +8746,2,7 +8747,3,8 +8748,4,9 +8749,5,10 +8750,1,1 +8751,2,2 +8752,3,3 +8753,4,4 +8754,5,5 +8755,1,6 +8756,2,7 +8757,3,8 +8758,4,9 +8759,5,10 +8760,1,1 +8761,2,2 +8762,3,3 +8763,4,4 +8764,5,5 +8765,1,6 +8766,2,7 +8767,3,8 +8768,4,9 +8769,5,10 +8770,1,1 +8771,2,2 +8772,3,3 +8773,4,4 +8774,5,5 +8775,1,6 +8776,2,7 +8777,3,8 +8778,4,9 +8779,5,10 +8780,1,1 +8781,2,2 +8782,3,3 +8783,4,4 +8784,5,5 +8785,1,6 +8786,2,7 +8787,3,8 +8788,4,9 +8789,5,10 +8790,1,1 +8791,2,2 +8792,3,3 +8793,4,4 +8794,5,5 +8795,1,6 +8796,2,7 +8797,3,8 +8798,4,9 +8799,5,10 +8800,1,1 +8801,2,2 +8802,3,3 +8803,4,4 +8804,5,5 +8805,1,6 +8806,2,7 +8807,3,8 +8808,4,9 +8809,5,10 +8810,1,1 +8811,2,2 +8812,3,3 +8813,4,4 +8814,5,5 +8815,1,6 +8816,2,7 +8817,3,8 +8818,4,9 +8819,5,10 +8820,1,1 +8821,2,2 +8822,3,3 +8823,4,4 +8824,5,5 +8825,1,6 +8826,2,7 +8827,3,8 +8828,4,9 +8829,5,10 +8830,1,1 +8831,2,2 +8832,3,3 +8833,4,4 +8834,5,5 +8835,1,6 +8836,2,7 +8837,3,8 +8838,4,9 +8839,5,10 +8840,1,1 +8841,2,2 +8842,3,3 +8843,4,4 +8844,5,5 +8845,1,6 +8846,2,7 +8847,3,8 +8848,4,9 +8849,5,10 +8850,1,1 +8851,2,2 +8852,3,3 +8853,4,4 +8854,5,5 +8855,1,6 +8856,2,7 +8857,3,8 +8858,4,9 +8859,5,10 +8860,1,1 +8861,2,2 +8862,3,3 +8863,4,4 +8864,5,5 +8865,1,6 +8866,2,7 +8867,3,8 +8868,4,9 +8869,5,10 +8870,1,1 +8871,2,2 +8872,3,3 +8873,4,4 +8874,5,5 +8875,1,6 +8876,2,7 +8877,3,8 +8878,4,9 +8879,5,10 +8880,1,1 +8881,2,2 +8882,3,3 +8883,4,4 +8884,5,5 +8885,1,6 +8886,2,7 +8887,3,8 +8888,4,9 +8889,5,10 +8890,1,1 +8891,2,2 +8892,3,3 +8893,4,4 +8894,5,5 +8895,1,6 +8896,2,7 +8897,3,8 +8898,4,9 +8899,5,10 +8900,1,1 +8901,2,2 +8902,3,3 +8903,4,4 +8904,5,5 +8905,1,6 +8906,2,7 +8907,3,8 +8908,4,9 +8909,5,10 +8910,1,1 +8911,2,2 +8912,3,3 +8913,4,4 +8914,5,5 +8915,1,6 +8916,2,7 +8917,3,8 +8918,4,9 +8919,5,10 +8920,1,1 +8921,2,2 +8922,3,3 +8923,4,4 +8924,5,5 +8925,1,6 +8926,2,7 +8927,3,8 +8928,4,9 +8929,5,10 +8930,1,1 +8931,2,2 +8932,3,3 +8933,4,4 +8934,5,5 +8935,1,6 +8936,2,7 +8937,3,8 +8938,4,9 +8939,5,10 +8940,1,1 +8941,2,2 +8942,3,3 +8943,4,4 +8944,5,5 +8945,1,6 +8946,2,7 +8947,3,8 +8948,4,9 +8949,5,10 +8950,1,1 +8951,2,2 +8952,3,3 +8953,4,4 +8954,5,5 +8955,1,6 +8956,2,7 +8957,3,8 +8958,4,9 +8959,5,10 +8960,1,1 +8961,2,2 +8962,3,3 +8963,4,4 +8964,5,5 +8965,1,6 +8966,2,7 +8967,3,8 +8968,4,9 +8969,5,10 +8970,1,1 +8971,2,2 +8972,3,3 +8973,4,4 +8974,5,5 +8975,1,6 +8976,2,7 +8977,3,8 +8978,4,9 +8979,5,10 +8980,1,1 +8981,2,2 +8982,3,3 +8983,4,4 +8984,5,5 +8985,1,6 +8986,2,7 +8987,3,8 +8988,4,9 +8989,5,10 +8990,1,1 +8991,2,2 +8992,3,3 +8993,4,4 +8994,5,5 +8995,1,6 +8996,2,7 +8997,3,8 +8998,4,9 +8999,5,10 +9000,1,1 +9001,2,2 +9002,3,3 +9003,4,4 +9004,5,5 +9005,1,6 +9006,2,7 +9007,3,8 +9008,4,9 +9009,5,10 +9010,1,1 +9011,2,2 +9012,3,3 +9013,4,4 +9014,5,5 +9015,1,6 +9016,2,7 +9017,3,8 +9018,4,9 +9019,5,10 +9020,1,1 +9021,2,2 +9022,3,3 +9023,4,4 +9024,5,5 +9025,1,6 +9026,2,7 +9027,3,8 +9028,4,9 +9029,5,10 +9030,1,1 +9031,2,2 +9032,3,3 +9033,4,4 +9034,5,5 +9035,1,6 +9036,2,7 +9037,3,8 +9038,4,9 +9039,5,10 +9040,1,1 +9041,2,2 +9042,3,3 +9043,4,4 +9044,5,5 +9045,1,6 +9046,2,7 +9047,3,8 +9048,4,9 +9049,5,10 +9050,1,1 +9051,2,2 +9052,3,3 +9053,4,4 +9054,5,5 +9055,1,6 +9056,2,7 +9057,3,8 +9058,4,9 +9059,5,10 +9060,1,1 +9061,2,2 +9062,3,3 +9063,4,4 +9064,5,5 +9065,1,6 +9066,2,7 +9067,3,8 +9068,4,9 +9069,5,10 +9070,1,1 +9071,2,2 +9072,3,3 +9073,4,4 +9074,5,5 +9075,1,6 +9076,2,7 +9077,3,8 +9078,4,9 +9079,5,10 +9080,1,1 +9081,2,2 +9082,3,3 +9083,4,4 +9084,5,5 +9085,1,6 +9086,2,7 +9087,3,8 +9088,4,9 +9089,5,10 +9090,1,1 +9091,2,2 +9092,3,3 +9093,4,4 +9094,5,5 +9095,1,6 +9096,2,7 +9097,3,8 +9098,4,9 +9099,5,10 +9100,1,1 +9101,2,2 +9102,3,3 +9103,4,4 +9104,5,5 +9105,1,6 +9106,2,7 +9107,3,8 +9108,4,9 +9109,5,10 +9110,1,1 +9111,2,2 +9112,3,3 +9113,4,4 +9114,5,5 +9115,1,6 +9116,2,7 +9117,3,8 +9118,4,9 +9119,5,10 +9120,1,1 +9121,2,2 +9122,3,3 +9123,4,4 +9124,5,5 +9125,1,6 +9126,2,7 +9127,3,8 +9128,4,9 +9129,5,10 +9130,1,1 +9131,2,2 +9132,3,3 +9133,4,4 +9134,5,5 +9135,1,6 +9136,2,7 +9137,3,8 +9138,4,9 +9139,5,10 +9140,1,1 +9141,2,2 +9142,3,3 +9143,4,4 +9144,5,5 +9145,1,6 +9146,2,7 +9147,3,8 +9148,4,9 +9149,5,10 +9150,1,1 +9151,2,2 +9152,3,3 +9153,4,4 +9154,5,5 +9155,1,6 +9156,2,7 +9157,3,8 +9158,4,9 +9159,5,10 +9160,1,1 +9161,2,2 +9162,3,3 +9163,4,4 +9164,5,5 +9165,1,6 +9166,2,7 +9167,3,8 +9168,4,9 +9169,5,10 +9170,1,1 +9171,2,2 +9172,3,3 +9173,4,4 +9174,5,5 +9175,1,6 +9176,2,7 +9177,3,8 +9178,4,9 +9179,5,10 +9180,1,1 +9181,2,2 +9182,3,3 +9183,4,4 +9184,5,5 +9185,1,6 +9186,2,7 +9187,3,8 +9188,4,9 +9189,5,10 +9190,1,1 +9191,2,2 +9192,3,3 +9193,4,4 +9194,5,5 +9195,1,6 +9196,2,7 +9197,3,8 +9198,4,9 +9199,5,10 +9200,1,1 +9201,2,2 +9202,3,3 +9203,4,4 +9204,5,5 +9205,1,6 +9206,2,7 +9207,3,8 +9208,4,9 +9209,5,10 +9210,1,1 +9211,2,2 +9212,3,3 +9213,4,4 +9214,5,5 +9215,1,6 +9216,2,7 +9217,3,8 +9218,4,9 +9219,5,10 +9220,1,1 +9221,2,2 +9222,3,3 +9223,4,4 +9224,5,5 +9225,1,6 +9226,2,7 +9227,3,8 +9228,4,9 +9229,5,10 +9230,1,1 +9231,2,2 +9232,3,3 +9233,4,4 +9234,5,5 +9235,1,6 +9236,2,7 +9237,3,8 +9238,4,9 +9239,5,10 +9240,1,1 +9241,2,2 +9242,3,3 +9243,4,4 +9244,5,5 +9245,1,6 +9246,2,7 +9247,3,8 +9248,4,9 +9249,5,10 +9250,1,1 +9251,2,2 +9252,3,3 +9253,4,4 +9254,5,5 +9255,1,6 +9256,2,7 +9257,3,8 +9258,4,9 +9259,5,10 +9260,1,1 +9261,2,2 +9262,3,3 +9263,4,4 +9264,5,5 +9265,1,6 +9266,2,7 +9267,3,8 +9268,4,9 +9269,5,10 +9270,1,1 +9271,2,2 +9272,3,3 +9273,4,4 +9274,5,5 +9275,1,6 +9276,2,7 +9277,3,8 +9278,4,9 +9279,5,10 +9280,1,1 +9281,2,2 +9282,3,3 +9283,4,4 +9284,5,5 +9285,1,6 +9286,2,7 +9287,3,8 +9288,4,9 +9289,5,10 +9290,1,1 +9291,2,2 +9292,3,3 +9293,4,4 +9294,5,5 +9295,1,6 +9296,2,7 +9297,3,8 +9298,4,9 +9299,5,10 +9300,1,1 +9301,2,2 +9302,3,3 +9303,4,4 +9304,5,5 +9305,1,6 +9306,2,7 +9307,3,8 +9308,4,9 +9309,5,10 +9310,1,1 +9311,2,2 +9312,3,3 +9313,4,4 +9314,5,5 +9315,1,6 +9316,2,7 +9317,3,8 +9318,4,9 +9319,5,10 +9320,1,1 +9321,2,2 +9322,3,3 +9323,4,4 +9324,5,5 +9325,1,6 +9326,2,7 +9327,3,8 +9328,4,9 +9329,5,10 +9330,1,1 +9331,2,2 +9332,3,3 +9333,4,4 +9334,5,5 +9335,1,6 +9336,2,7 +9337,3,8 +9338,4,9 +9339,5,10 +9340,1,1 +9341,2,2 +9342,3,3 +9343,4,4 +9344,5,5 +9345,1,6 +9346,2,7 +9347,3,8 +9348,4,9 +9349,5,10 +9350,1,1 +9351,2,2 +9352,3,3 +9353,4,4 +9354,5,5 +9355,1,6 +9356,2,7 +9357,3,8 +9358,4,9 +9359,5,10 +9360,1,1 +9361,2,2 +9362,3,3 +9363,4,4 +9364,5,5 +9365,1,6 +9366,2,7 +9367,3,8 +9368,4,9 +9369,5,10 +9370,1,1 +9371,2,2 +9372,3,3 +9373,4,4 +9374,5,5 +9375,1,6 +9376,2,7 +9377,3,8 +9378,4,9 +9379,5,10 +9380,1,1 +9381,2,2 +9382,3,3 +9383,4,4 +9384,5,5 +9385,1,6 +9386,2,7 +9387,3,8 +9388,4,9 +9389,5,10 +9390,1,1 +9391,2,2 +9392,3,3 +9393,4,4 +9394,5,5 +9395,1,6 +9396,2,7 +9397,3,8 +9398,4,9 +9399,5,10 +9400,1,1 +9401,2,2 +9402,3,3 +9403,4,4 +9404,5,5 +9405,1,6 +9406,2,7 +9407,3,8 +9408,4,9 +9409,5,10 +9410,1,1 +9411,2,2 +9412,3,3 +9413,4,4 +9414,5,5 +9415,1,6 +9416,2,7 +9417,3,8 +9418,4,9 +9419,5,10 +9420,1,1 +9421,2,2 +9422,3,3 +9423,4,4 +9424,5,5 +9425,1,6 +9426,2,7 +9427,3,8 +9428,4,9 +9429,5,10 +9430,1,1 +9431,2,2 +9432,3,3 +9433,4,4 +9434,5,5 +9435,1,6 +9436,2,7 +9437,3,8 +9438,4,9 +9439,5,10 +9440,1,1 +9441,2,2 +9442,3,3 +9443,4,4 +9444,5,5 +9445,1,6 +9446,2,7 +9447,3,8 +9448,4,9 +9449,5,10 +9450,1,1 +9451,2,2 +9452,3,3 +9453,4,4 +9454,5,5 +9455,1,6 +9456,2,7 +9457,3,8 +9458,4,9 +9459,5,10 +9460,1,1 +9461,2,2 +9462,3,3 +9463,4,4 +9464,5,5 +9465,1,6 +9466,2,7 +9467,3,8 +9468,4,9 +9469,5,10 +9470,1,1 +9471,2,2 +9472,3,3 +9473,4,4 +9474,5,5 +9475,1,6 +9476,2,7 +9477,3,8 +9478,4,9 +9479,5,10 +9480,1,1 +9481,2,2 +9482,3,3 +9483,4,4 +9484,5,5 +9485,1,6 +9486,2,7 +9487,3,8 +9488,4,9 +9489,5,10 +9490,1,1 +9491,2,2 +9492,3,3 +9493,4,4 +9494,5,5 +9495,1,6 +9496,2,7 +9497,3,8 +9498,4,9 +9499,5,10 +9500,1,1 +9501,2,2 +9502,3,3 +9503,4,4 +9504,5,5 +9505,1,6 +9506,2,7 +9507,3,8 +9508,4,9 +9509,5,10 +9510,1,1 +9511,2,2 +9512,3,3 +9513,4,4 +9514,5,5 +9515,1,6 +9516,2,7 +9517,3,8 +9518,4,9 +9519,5,10 +9520,1,1 +9521,2,2 +9522,3,3 +9523,4,4 +9524,5,5 +9525,1,6 +9526,2,7 +9527,3,8 +9528,4,9 +9529,5,10 +9530,1,1 +9531,2,2 +9532,3,3 +9533,4,4 +9534,5,5 +9535,1,6 +9536,2,7 +9537,3,8 +9538,4,9 +9539,5,10 +9540,1,1 +9541,2,2 +9542,3,3 +9543,4,4 +9544,5,5 +9545,1,6 +9546,2,7 +9547,3,8 +9548,4,9 +9549,5,10 +9550,1,1 +9551,2,2 +9552,3,3 +9553,4,4 +9554,5,5 +9555,1,6 +9556,2,7 +9557,3,8 +9558,4,9 +9559,5,10 +9560,1,1 +9561,2,2 +9562,3,3 +9563,4,4 +9564,5,5 +9565,1,6 +9566,2,7 +9567,3,8 +9568,4,9 +9569,5,10 +9570,1,1 +9571,2,2 +9572,3,3 +9573,4,4 +9574,5,5 +9575,1,6 +9576,2,7 +9577,3,8 +9578,4,9 +9579,5,10 +9580,1,1 +9581,2,2 +9582,3,3 +9583,4,4 +9584,5,5 +9585,1,6 +9586,2,7 +9587,3,8 +9588,4,9 +9589,5,10 +9590,1,1 +9591,2,2 +9592,3,3 +9593,4,4 +9594,5,5 +9595,1,6 +9596,2,7 +9597,3,8 +9598,4,9 +9599,5,10 +9600,1,1 +9601,2,2 +9602,3,3 +9603,4,4 +9604,5,5 +9605,1,6 +9606,2,7 +9607,3,8 +9608,4,9 +9609,5,10 +9610,1,1 +9611,2,2 +9612,3,3 +9613,4,4 +9614,5,5 +9615,1,6 +9616,2,7 +9617,3,8 +9618,4,9 +9619,5,10 +9620,1,1 +9621,2,2 +9622,3,3 +9623,4,4 +9624,5,5 +9625,1,6 +9626,2,7 +9627,3,8 +9628,4,9 +9629,5,10 +9630,1,1 +9631,2,2 +9632,3,3 +9633,4,4 +9634,5,5 +9635,1,6 +9636,2,7 +9637,3,8 +9638,4,9 +9639,5,10 +9640,1,1 +9641,2,2 +9642,3,3 +9643,4,4 +9644,5,5 +9645,1,6 +9646,2,7 +9647,3,8 +9648,4,9 +9649,5,10 +9650,1,1 +9651,2,2 +9652,3,3 +9653,4,4 +9654,5,5 +9655,1,6 +9656,2,7 +9657,3,8 +9658,4,9 +9659,5,10 +9660,1,1 +9661,2,2 +9662,3,3 +9663,4,4 +9664,5,5 +9665,1,6 +9666,2,7 +9667,3,8 +9668,4,9 +9669,5,10 +9670,1,1 +9671,2,2 +9672,3,3 +9673,4,4 +9674,5,5 +9675,1,6 +9676,2,7 +9677,3,8 +9678,4,9 +9679,5,10 +9680,1,1 +9681,2,2 +9682,3,3 +9683,4,4 +9684,5,5 +9685,1,6 +9686,2,7 +9687,3,8 +9688,4,9 +9689,5,10 +9690,1,1 +9691,2,2 +9692,3,3 +9693,4,4 +9694,5,5 +9695,1,6 +9696,2,7 +9697,3,8 +9698,4,9 +9699,5,10 +9700,1,1 +9701,2,2 +9702,3,3 +9703,4,4 +9704,5,5 +9705,1,6 +9706,2,7 +9707,3,8 +9708,4,9 +9709,5,10 +9710,1,1 +9711,2,2 +9712,3,3 +9713,4,4 +9714,5,5 +9715,1,6 +9716,2,7 +9717,3,8 +9718,4,9 +9719,5,10 +9720,1,1 +9721,2,2 +9722,3,3 +9723,4,4 +9724,5,5 +9725,1,6 +9726,2,7 +9727,3,8 +9728,4,9 +9729,5,10 +9730,1,1 +9731,2,2 +9732,3,3 +9733,4,4 +9734,5,5 +9735,1,6 +9736,2,7 +9737,3,8 +9738,4,9 +9739,5,10 +9740,1,1 +9741,2,2 +9742,3,3 +9743,4,4 +9744,5,5 +9745,1,6 +9746,2,7 +9747,3,8 +9748,4,9 +9749,5,10 +9750,1,1 +9751,2,2 +9752,3,3 +9753,4,4 +9754,5,5 +9755,1,6 +9756,2,7 +9757,3,8 +9758,4,9 +9759,5,10 +9760,1,1 +9761,2,2 +9762,3,3 +9763,4,4 +9764,5,5 +9765,1,6 +9766,2,7 +9767,3,8 +9768,4,9 +9769,5,10 +9770,1,1 +9771,2,2 +9772,3,3 +9773,4,4 +9774,5,5 +9775,1,6 +9776,2,7 +9777,3,8 +9778,4,9 +9779,5,10 +9780,1,1 +9781,2,2 +9782,3,3 +9783,4,4 +9784,5,5 +9785,1,6 +9786,2,7 +9787,3,8 +9788,4,9 +9789,5,10 +9790,1,1 +9791,2,2 +9792,3,3 +9793,4,4 +9794,5,5 +9795,1,6 +9796,2,7 +9797,3,8 +9798,4,9 +9799,5,10 +9800,1,1 +9801,2,2 +9802,3,3 +9803,4,4 +9804,5,5 +9805,1,6 +9806,2,7 +9807,3,8 +9808,4,9 +9809,5,10 +9810,1,1 +9811,2,2 +9812,3,3 +9813,4,4 +9814,5,5 +9815,1,6 +9816,2,7 +9817,3,8 +9818,4,9 +9819,5,10 +9820,1,1 +9821,2,2 +9822,3,3 +9823,4,4 +9824,5,5 +9825,1,6 +9826,2,7 +9827,3,8 +9828,4,9 +9829,5,10 +9830,1,1 +9831,2,2 +9832,3,3 +9833,4,4 +9834,5,5 +9835,1,6 +9836,2,7 +9837,3,8 +9838,4,9 +9839,5,10 +9840,1,1 +9841,2,2 +9842,3,3 +9843,4,4 +9844,5,5 +9845,1,6 +9846,2,7 +9847,3,8 +9848,4,9 +9849,5,10 +9850,1,1 +9851,2,2 +9852,3,3 +9853,4,4 +9854,5,5 +9855,1,6 +9856,2,7 +9857,3,8 +9858,4,9 +9859,5,10 +9860,1,1 +9861,2,2 +9862,3,3 +9863,4,4 +9864,5,5 +9865,1,6 +9866,2,7 +9867,3,8 +9868,4,9 +9869,5,10 +9870,1,1 +9871,2,2 +9872,3,3 +9873,4,4 +9874,5,5 +9875,1,6 +9876,2,7 +9877,3,8 +9878,4,9 +9879,5,10 +9880,1,1 +9881,2,2 +9882,3,3 +9883,4,4 +9884,5,5 +9885,1,6 +9886,2,7 +9887,3,8 +9888,4,9 +9889,5,10 +9890,1,1 +9891,2,2 +9892,3,3 +9893,4,4 +9894,5,5 +9895,1,6 +9896,2,7 +9897,3,8 +9898,4,9 +9899,5,10 +9900,1,1 +9901,2,2 +9902,3,3 +9903,4,4 +9904,5,5 +9905,1,6 +9906,2,7 +9907,3,8 +9908,4,9 +9909,5,10 +9910,1,1 +9911,2,2 +9912,3,3 +9913,4,4 +9914,5,5 +9915,1,6 +9916,2,7 +9917,3,8 +9918,4,9 +9919,5,10 +9920,1,1 +9921,2,2 +9922,3,3 +9923,4,4 +9924,5,5 +9925,1,6 +9926,2,7 +9927,3,8 +9928,4,9 +9929,5,10 +9930,1,1 +9931,2,2 +9932,3,3 +9933,4,4 +9934,5,5 +9935,1,6 +9936,2,7 +9937,3,8 +9938,4,9 +9939,5,10 +9940,1,1 +9941,2,2 +9942,3,3 +9943,4,4 +9944,5,5 +9945,1,6 +9946,2,7 +9947,3,8 +9948,4,9 +9949,5,10 +9950,1,1 +9951,2,2 +9952,3,3 +9953,4,4 +9954,5,5 +9955,1,6 +9956,2,7 +9957,3,8 +9958,4,9 +9959,5,10 +9960,1,1 +9961,2,2 +9962,3,3 +9963,4,4 +9964,5,5 +9965,1,6 +9966,2,7 +9967,3,8 +9968,4,9 +9969,5,10 +9970,1,1 +9971,2,2 +9972,3,3 +9973,4,4 +9974,5,5 +9975,1,6 +9976,2,7 +9977,3,8 +9978,4,9 +9979,5,10 +9980,1,1 +9981,2,2 +9982,3,3 +9983,4,4 +9984,5,5 +9985,1,6 +9986,2,7 +9987,3,8 +9988,4,9 +9989,5,10 +9990,1,1 +9991,2,2 +9992,3,3 +9993,4,4 +9994,5,5 +9995,1,6 +9996,2,7 +9997,3,8 +9998,4,9 +9999,5,10 diff --git a/db2sampl/p1.xml b/db2sampl/p1.xml new file mode 100755 index 0000000..1313458 --- /dev/null +++ b/db2sampl/p1.xml @@ -0,0 +1,8 @@ + + +Snow Shovel, Basic 22 inch +
Basic Snow Shovel, 22 inches wide, straight handle with D-Grip
+9.99 +1 kg +
+
diff --git a/db2sampl/p2.xml b/db2sampl/p2.xml new file mode 100755 index 0000000..3337e11 --- /dev/null +++ b/db2sampl/p2.xml @@ -0,0 +1,8 @@ + + +Snow Shovel, Deluxe 24 inch +
A Deluxe Snow Shovel, 24 inches wide, ergonomic curved handle with D-Grip
+19.99 +2 kg +
+
diff --git a/db2sampl/p3.xml b/db2sampl/p3.xml new file mode 100755 index 0000000..e3757e6 --- /dev/null +++ b/db2sampl/p3.xml @@ -0,0 +1,8 @@ + + +Snow Shovel, Super Deluxe 26 inch +
Super Deluxe Snow Shovel, 26 inches wide, ergonomic battery heated curved handle with upgraded D-Grip
+49.99 +3 kg +
+
diff --git a/db2sampl/p4.xml b/db2sampl/p4.xml new file mode 100755 index 0000000..e1103f0 --- /dev/null +++ b/db2sampl/p4.xml @@ -0,0 +1,7 @@ + + +Ice Scraper, Windshield 4 inch +
Basic Ice Scraper 4 inches wide, foam handle
+3.99 +
+
diff --git a/db2sampl/po1.xml b/db2sampl/po1.xml new file mode 100644 index 0000000..f35b84d --- /dev/null +++ b/db2sampl/po1.xml @@ -0,0 +1,15 @@ + + + 100-100-01 + Snow Shovel, Basic 22 inch + 3 + 9.99 + + + 100-103-01 + Snow Shovel, Super Deluxe 26 inch + 5 + 49.99 + + + diff --git a/db2sampl/po2.xml b/db2sampl/po2.xml new file mode 100644 index 0000000..54495bc --- /dev/null +++ b/db2sampl/po2.xml @@ -0,0 +1,20 @@ + + + 100-101-01 + Snow Shovel, Deluxe 24 inch + 1 + 19.99 + + + 100-103-01 + Snow Shovel, Super Deluxe 26 inch + 2 + 49.99 + + + 100-201-01 + Ice Scraper, Windshield 4 inch + 1 + 3.99 + + diff --git a/db2sampl/po3.xml b/db2sampl/po3.xml new file mode 100644 index 0000000..26f09c9 --- /dev/null +++ b/db2sampl/po3.xml @@ -0,0 +1,20 @@ + + + 100-100-01 + Snow Shovel, Basic 22 inch + 3 + 9.99 + + + 100-101-01 + Snow Shovel, Deluxe 24 inch + 5 + 19.99 + + + 100-201-01 + Ice Scraper, Windshield 4 inch + 5 + 3.99 + + diff --git a/db2sampl/po4.xml b/db2sampl/po4.xml new file mode 100644 index 0000000..3a1bd16 --- /dev/null +++ b/db2sampl/po4.xml @@ -0,0 +1,8 @@ + + + 100-100-01 + Snow Shovel, Basic 22 inch + 1 + 9.99 + + diff --git a/db2sampl/po5.xml b/db2sampl/po5.xml new file mode 100644 index 0000000..c2d14f1 --- /dev/null +++ b/db2sampl/po5.xml @@ -0,0 +1,14 @@ + + + 100-100-01 + Snow Shovel, Basic 22 inch + 4 + 9.99 + + + 100-103-01 + Snow Shovel, Super Deluxe 26 inch + 2 + 49.99 + + diff --git a/db2sampl/po6.xml b/db2sampl/po6.xml new file mode 100644 index 0000000..420e6cd --- /dev/null +++ b/db2sampl/po6.xml @@ -0,0 +1,21 @@ + + + 100-100-01 + Snow Shovel, Basic 22 inch + 3 + 9.99 + + + 100-101-01 + Snow Shovel, Deluxe 24 inch + 5 + 19.99 + + + 100-201-01 + Ice Scraper, Windshield 4 inch + 5 + 3.99 + + + diff --git a/db2sampl/porder.xsd b/db2sampl/porder.xsd new file mode 100644 index 0000000..cb407ac --- /dev/null +++ b/db2sampl/porder.xsd @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/db2sampl/product.xsd b/db2sampl/product.xsd new file mode 100644 index 0000000..649f7fc --- /dev/null +++ b/db2sampl/product.xsd @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/db2sampl/supplier.xsd b/db2sampl/supplier.xsd new file mode 100644 index 0000000..12acb67 --- /dev/null +++ b/db2sampl/supplier.xsd @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extenders/spatial/README_spatial_samples.txt b/extenders/spatial/README_spatial_samples.txt new file mode 100644 index 0000000..c828932 --- /dev/null +++ b/extenders/spatial/README_spatial_samples.txt @@ -0,0 +1,107 @@ +README file for DB2 Spatial Extender Samples + +* +* +* (C) COPYRIGHT INTERNATIONAL BUSINESS MACHINES CORPORATION 2005, 2011. +* + ALL RIGHTS RESERVED. +* + + +File: sqllib/samples/extenders/spatial/README_spatial_samples.txt + +The DB2 Spatial Extender samples consist of two different demo programs. + - One sample is based on banking (branches, customers, employees). + This banking demo is written in SQL scripts run by the command-line + processor (CLP). + - The other sample is based on property parcels and natural features + (flood zones, regions, and so on). This property parcel demo + is written in C and is compiled and linked into an executable program. +This file briefly introduces each demo and indicates where to look for +further information. + + += = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +The Banking Demo is implemented in SQL scripts that are run with the DB2 +command line processor. You can use the demo and scripts as a tutorial. +The scripts and README file "seBankDemoREADME.txt" are located in the +"bank" subdirectory (sqllib/extenders/samples/spatial/bank). +The following excerpt from that file gives an introduction to the demo: +***************************************************************************** + Banking Customer Analysis Sample + + This demo illustrates adding a spatial dimension to an existing + information system. The existing system did not contain any explicit + location (spatial) data. However, the existing system did contain implicit + location data in the form of addresses. By spatially enabling the existing + database, the user expands the business analysis capabilities of the system. + + A bank that has customers with accounts at two branches needs to use the + spatial attribute of the existing data along with census demographic data + to perform various kinds of spatial analysis. The analysis consists of + comparing customer, branch, and demographic data, as well as profiling + customers and doing market analysis. The bank looks for prospective + customers by finding average balances for customers within three miles of + the branch, determining what areas the primary customers live in, and + searching for similar areas. + + Note: Although this demo focuses on a banking application, it is equally + applicable to different businesses such as retail, insurance, and so on. +***************************************************************************** + +For UNIX, the Banking Demo is driven by a Korn shell script called +"seBankDemoRunBankDemo". To display usage information, enter + seBankDemoRunBankDemo -h + +For Windows, the Banking Demo is driven by a batch file called +"seBankDemoRunBankDemo.bat". To display usage information, enter + seBankDemoRunBankDemo -h + +Before you run the demo, look at the "seBankDemoREADME.txt" file. This +README file describes the prerequisites and explains how to run the demo. + +After the Banking Demo runs, the complete record of its actions can be found +in the file "se_bank.log" which is in the "tmp", subdirectory under the home +directory of the user who ran the demo. + + += = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +The Property Parcel Demo is implemented in C code using the DB2 CLI interface. +The "Spatial and geodetic data" section of the DB2 Info Center provides more +information: + + - "Getting started with DB2 Spatial Extender" -> "Verifying the Spatial Extender + installation" gives information about running "runGseDemo" to verify your + installation. Read that section carefully. + + - "Writing applications and using the sample program" -> "The DB2 Spatial Extender + sample program" provides a step-by-step overview of all the operations of this + Demo. + +The Property Parcel Demo is located in the sqllib/extenders/samples/spatial +directory and the executable file is "runGseDemo". + +To display usage information, enter the following command: + runGseDemo -h + +After you install Spatial Extender on Windows the "runGseDemo" program is +ready to execute. On Linux or UNIX platforms, you create an instance after +you install Spatial Extender. + +Modifying and Rebuilding "runGseDemo" +------------------------------------- +The source code for the "runGseDemo" program is included in the distribution +in case you would like to make modifications or additions to the program. +To modify the program, create a new directory that is not under sqllib and +copy the source and header files (samputil.h, samputil.c, runGseDemo.c) there. +On Windows, you also need the "makefile.nt" file. +On any UNIX platform, you also need the "bldDemo" file. + +To recompile and relink the "runGseDemo" program, enter the following command: +For UNIX, + "bldDemo" +For Windows, + "nmake -f makefile.nt" + + + diff --git a/extenders/spatial/bank/seBankDemoConversion.db2 b/extenders/spatial/bank/seBankDemoConversion.db2 new file mode 100644 index 0000000..8d8cdc2 --- /dev/null +++ b/extenders/spatial/bank/seBankDemoConversion.db2 @@ -0,0 +1,47 @@ +----------------------------------------------------------------------------- +-- Licensed Materials - Property of IBM +-- Governed under the terms of the IBM Public License +-- +-- (C) COPYRIGHT International Business Machines Corp. 2000 - 2010 +-- All Rights Reserved. +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +----------------------------------------------------------------------------- +-- +-- Product Name: DB2 Spatial Extender v9.7 +-- +-- Source File Name: seBankDemoConversion.db2 +-- +-- Version: 9.7.3 +-- +-- Description: Create temporary table space and bufferpool for Grid +-- Index Advisor (gseidx). +-- +-- SQL STATEMENTS USED: +-- CREATE BUFFERPOOL +-- CREATE TEMPORARY TABLESPACE +-- +-- +-- For more information about the DB2 Spatial Extender Bank Demo scripts, +-- see the seBankDemoREADME.txt file. +-- +-- For more information about DB2 Spatial Extender, refer to the DB2 Spatial +-- Extender User's Guide and Reference. +-- +-- For the latest information on DB2 Spatial Extender and the Bank Demo +-- refer to the DB2 Spatial Extender website at +-- http://www.software.ibm.com/software/data/spatial/db2spatial +----------------------------------------------------------------------------- + +CONNECT RESET +CONNECT TO se_bank +CREATE BUFFERPOOL se_bank_32k_bp SIZE 1024 PAGESIZE 32 K +CREATE BUFFERPOOL se_bank_8k_bp SIZE 1024 PAGESIZE 8 K +CREATE TEMPORARY TABLESPACE se_bank_temp_ts PAGESIZE 32 K MANAGED BY SYSTEM USING ('se_bank_container_32k_tt') EXTENTSIZE 64 PREFETCHSIZE 32 BUFFERPOOL se_bank_32k_bp +CREATE USER TEMPORARY TABLESPACE se_bank_u_temp_ts PAGESIZE 32 K MANAGED BY SYSTEM USING ('se_bank_container_32k_utt') EXTENTSIZE 64 PREFETCHSIZE 32 BUFFERPOOL se_bank_32k_bp +CREATE TABLESPACE se_bank_8k_ts PAGESIZE 8 K MANAGED BY SYSTEM USING ('se_bank_container_8k') EXTENTSIZE 16 PREFETCHSIZE 8 BUFFERPOOL se_bank_8k_bp +GRANT USE OF TABLESPACE se_bank_u_temp_ts TO PUBLIC +GRANT USE OF TABLESPACE se_bank_8k_ts TO PUBLIC +CONNECT RESET + diff --git a/extenders/spatial/bank/seBankDemoDDL.db2 b/extenders/spatial/bank/seBankDemoDDL.db2 new file mode 100644 index 0000000..d3fd47c --- /dev/null +++ b/extenders/spatial/bank/seBankDemoDDL.db2 @@ -0,0 +1,95 @@ +---------------------------------------------------------------------------- +-- Licensed Materials - Property of IBM +-- Governed under the terms of the IBM Public License +-- +-- (C) COPYRIGHT International Business Machines Corp. 2000 - 2014 +-- All Rights Reserved. +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +---------------------------------------------------------------------------- +-- +-- Product Name: DB2 Spatial Extender v10.0 +-- +-- Source File Name: seBankDemoDDL.db2 +-- +-- Version: 10.5.0 +-- +-- Description: Load non-spatial data into the sample database. +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- CREATE TABLE +-- +-- +-- For more information about the DB2 Spatial Extender Bank Demo scripts, +-- see the seBankDemoREADME.txt file. +-- +-- For more information about DB2 Spatial Extender, refer to the DB2 Spatial +-- Extender User's Guide and Reference. +-- +-- For the latest information on DB2 Spatial Extender and the Bank Demo +-- refer to the DB2 Spatial Extender website at +-- http://www.software.ibm.com/software/data/spatial/db2spatial +---------------------------------------------------------------------------- +CREATE TABLE se_demo.customers ( + customer_id INTEGER NOT NULL + PRIMARY KEY, + se_row_id INTEGER, + name VARCHAR (20), + street VARCHAR (25), + city VARCHAR (10), + state VARCHAR (2), + zip VARCHAR (5), + phone VARCHAR (20) , + email VARCHAR (50) , + customer_type VARCHAR (10) , + date_billed DATE , + notes VARCHAR (100), + date_entered DATE, + latitude DOUBLE, + longitude DOUBLE + ) DATA CAPTURE NONE ORGANIZE BY ROW ; + +CREATE TABLE se_demo.branches ( + branch_id INTEGER NOT NULL + PRIMARY KEY, + se_row_id INTEGER, + name VARCHAR (12), + manager VARCHAR (20), + street VARCHAR (20), + city VARCHAR (10), + state VARCHAR (2), + zip VARCHAR (5), + phone VARCHAR (30), + fax VARCHAR (30), + latitude DOUBLE, + longitude DOUBLE + ) DATA CAPTURE NONE ORGANIZE BY ROW ; + +CREATE TABLE se_demo.accounts ( + customer_id INTEGER NOT NULL, + branch_id INTEGER NOT NULL, + account_id INTEGER NOT NULL + PRIMARY KEY, + type VARCHAR (10) NOT NULL, + balance DECIMAL (14, 2) NOT NULL, + routing_number integer NOT NULL, + CONSTRAINT fk_branches FOREIGN KEY(branch_id) + REFERENCES se_demo.branches(branch_id) ON DELETE CASCADE, + CONSTRAINT fk_customers FOREIGN KEY(customer_id) + REFERENCES se_demo.customers(customer_id) ON DELETE CASCADE + ) ORGANIZE BY ROW; + +CREATE TABLE se_demo.transactions ( + transaction_id INTEGER NOT NULL + PRIMARY KEY, + transaction_date DATE NOT NULL, + description VARCHAR (100), + account_id INTEGER NOT NULL , + amount DECIMAL (14, 2) NOT NULL, + notes VARCHAR (100), + classification VARCHAR (30), + CONSTRAINT fk_accounts FOREIGN KEY(account_id) + REFERENCES se_demo.accounts(account_id) ON DELETE CASCADE + ) ORGANIZE BY ROW; diff --git a/extenders/spatial/bank/seBankDemoREADME.txt b/extenders/spatial/bank/seBankDemoREADME.txt new file mode 100644 index 0000000..7a2b6e3 --- /dev/null +++ b/extenders/spatial/bank/seBankDemoREADME.txt @@ -0,0 +1,263 @@ +README file for DB2 Spatial Extender Bank Demo +DB2 LUW + + +* +* +* (C) COPYRIGHT INTERNATIONAL BUSINESS MACHINES CORPORATION 2002 - 2011. +* ALL RIGHTS RESERVED. +* + + +This sample script demonstrates DB2 Spatial Extender administration, + +SQL stored procedures, and spatial functions. + +***************************************************************************** + +WARNING: Some of these samples may change your database or database manager + configuration. Run the samples against a "test" database only, + such as the DB2 SAMPLE database. + +***************************************************************************** + +QUICKSTART + + 1. Start the database manager (with the db2start command). + + 2. Start the sample (with the seBankDemoRunBankDemo command). + +***************************************************************************** + +Documentation + + + +For more information about DB2 Spatial Extender, see either of the following +sources. The scripts in this Bank Demo use the term "User's Guide" to refer +to both of these sources of information: + +- The "DB2 Spatial Extender and Geodetic Extender User's Guide and Reference" +- The equivalent Spatial Extender topics in the DB2 Information Center. + + +For the latest information about programming, compiling, and running DB2 +Spatial Extender applications, refer to the DB2 Spatial Extender Web site at +http://www.ibm.com/software/data/spatial/db2spatial + + + +***************************************************************************** + +Command syntax + + + seBankDemoRunBankDemo [-i | -n | -c | -b | -h] [] + + -i Interactive mode: A description of each step is shown before + you are prompted to execute the step. Explains the story + board of the bank scenario and the spatial administrative + actions necessary to set up the database. After the database + is set up, you are prompted to perform several queries. + + -n Non-interactive mode: Follows the same steps as the + interactive mode but does not prompt you at each step. + This mode can be used to set up a database for visualization + or for further spatial analysis with SQL. + + -c Completion mode: All the demo steps run in non-interactive + mode. At the end, the script notifies you of success or + failure. + + -b Basic mode: This mode is tutorial oriented, in which you + follow a written script to perform all the database setup + steps on the db2gse command-line processor (CLP) or DB2 + Command Editor. + The database is spatially enabled and only non-spatial data is + loaded. You perform the remaining steps. You also construct + a series of spatial queries using the DB2 CLP or the + DB2 Command Editor. + + If database does not exist, the demo creates it. The + default database name is se_bank. + The schema name is se_demo (you cannot modify the schema name). + + + +***************************************************************************** + +Prerequisites + + + + 1. Before you start the sample program, ensure that the following steps have + been done in advance: + + - DB2 Spatial Extender is installed. + + - The DB2 default instance is created. + + - The Database manager is started (with the db2start command). + + - The DB2PATH environment variable points to the sqllib directory. + + - The user ID under which this demo is invoked has either SYSADM + or DBADM authority. + + + 2. If you are going to create a new database or use an existing database, + ensure that the following parameters are updated to at least the listed + values: + + Parameter Min value CO Explanation/Description + ------------ --------- -- ------------------------------------------ + APPLHEAPSZ 10242 no various (also for enable_db) + STMTHEAP 16384 yes Various platforms raise "query too complex" + warnings + + CO => Configurable Online + + Note: Some of these parameters are not online configurable, and you must + stop and restart the DB2 instance for the new values to take effect. + + If these parameters are not set to the values listed above, the demo will + prompt you to ask if you want the demo to update these values for + the database. If you reply "yes," the demo stops and restarts the DB2 + instance. + + + 3. This demo requires larger buffer pools and table spaces than provided by + the default buffer pool and table space. + + CREATE object Page size Explanation/Description + -------------------------- --------- -------------------------------- + TABLESPACE 8K Import a shapefile with more columns + than fit on a 4K page size + TEMPORARY TABLESPACE 32K Complex ad hoc queries + USER TEMPORARY TABLESPACE 32K Spatial grid index advisor + BUFFERPOOL 8K Use with 8K table space + BUFFERPOOL 32K Use with 32K table space + + If these database objects do not exist, the demo will prompt you to + ask if you want the demo to create them. If you reply "yes," the demo + stops and restarts the DB2 instance for them to take effect. + + + 4. If you are running this demo a second time, delete all of the previous + message and exception files that have the following form: + On UNIX, + ~/tmp/*.msg and ~/tmp/*.shp + + On Windows, + %TEMP%\*.msg and %TEMP%\*.shp + +***************************************************************************** + +File descriptions + +seBankDemoREADME.txt - This file +seBankDemoRunBankDemo - Main demo script (Korn Shell) +seBankDemoRunBankDemo.bat - Main demo script (Windows batch file) +seBankDemoDDL.db2 - Creates non-spatial data tables +seBankDemoTableData.db2 - Loads non-spatialdata +seBankDemoConversion.db2 - Sample commands for creating a temporary + table space and bufferpool for Grid Index Advisor +seBankDemoSpatialSQL.db2 - Miscellaneous spatial queries +seBankDemoViewDDL.db2 - Creates spatial analysis views +seBankDemoRefresh.db2 - Drops all the tables and views and + spatially disables the current database + +***************************************************************************** + +Background + +Time and space will become the cornerstone of 21st-century data warehouses. +The time dimension is already frequently used in OLAP and multidimensional +analysis tools. The next frontier is to add the space dimension to +data to discover and exploit the spatial intelligence of the data warehouse. + +Spatial data (also called location data and geographic data) consists of +values that denote the location of objects and areas with respect to one +another. Spatial objects include those that comprise the Earth's surface +and those that occupy it. They make up both the natural environment (for +example rivers, forests, hills and deserts) and the cultural environment +(cities, residences, office buildings, landmarks, and so on). + +Virtually every database already has spatial data -- addresses -- and +virtually every business can benefit from making their data spatially aware. + +It is estimated that 80% of the world's databases have a spatial element. +This data, however, is not usable because it is stored in text form, and +SQL does not know if 12 Main Street is close to 141 Langdon Street. This +address data is at the core of most commercial enterprises, yet the semantic +content is not exploited. The ability to leverage the value of this +existing data asset is central to spatial analysis. + +IBM has focused research efforts on creating an extensible data management +infrastructure for more than a decade. The results of these efforts have +become a major component of IBM's DB2 Database, which includes +access to heterogeneous data and to non-IBM, non-relational data sources. + +The ability to model complex data and objects (geospatial data, text, images +and other user-defined data types) directly in the database gives users +four key benefits: + +- Enhances the business value of existing applications and data +- Improves business intelligence with integrated searching across all data + types +- Facilitates the development of new applications and queries +- Improves overall application performance + + +***************************************************************************** + +Banking customer analysis sample + +This demo illustrates adding a spatial dimension to an existing information +system. The existing system did not contain any explicit location (spatial) +data. However, the existing system did contain implicit location data in the +form of addresses. By spatially enabling the existing database, the user +expands the business analysis capabilities of the system. + +Note: Although this demo focuses on a banking application, it is equally +applicable to different businesses such as retail, insurance, and so on. + +A bank that has customers with accounts at two branches needs to use the +spatial attribute of the existing data along with census demographic data +to perform various kinds of spatial analysis. The analysis consists of +comparing customer, branch, and demographic data, as well as profiling +customers and doing market analysis. The bank looks for prospective +customers by finding average balances for customers within three miles of +the branch, determining what areas the primary customers live in, and +searching for similar areas. + +The demographic and spatial reference data has an explicit spatial component. +The initial data is in shapefile format. Shapefile format is an ESRI standard +for storing spatial information and has become an industry standard. For more +information, see the ESRI Web site at +http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf. + +The customer, branch and employee tables contain the address information +and corresponding latitude and longitude values. + +The demo script illustrates how to use the spatial administration commands +and prepare a database for spatial data visualization using ESRI's +ArcExplorer. The sample also explains how to use the spatial UDFs, and +outlines how spatial analysis can be used in a banking scenario. + +The demo script runs in four modes that are described in the command syntax. + +***************************************************************************** + +Duration + +Most of the demo steps take seconds to run, but the steps below might +take several minutes: + +- Creating the database + +- Spatially enabling the database + +- Importing shapefile data + +***************************************************************************** diff --git a/extenders/spatial/bank/seBankDemoRefresh.db2 b/extenders/spatial/bank/seBankDemoRefresh.db2 new file mode 100644 index 0000000..a1de321 --- /dev/null +++ b/extenders/spatial/bank/seBankDemoRefresh.db2 @@ -0,0 +1,60 @@ +---------------------------------------------------------------------------- +-- Licensed Materials - Property of IBM +-- Governed under the terms of the IBM Public License +-- +-- (C) COPYRIGHT International Business Machines Corp. 2000 - 2010 +-- All Rights Reserved. +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +---------------------------------------------------------------------------- +-- +-- Product Name: DB2 Spatial Extender v9.7 +-- +-- Source File Name: seBankDemoRefresh.db2 +-- +-- Version: 9.7.3 +-- +-- Description: Drops all the tables and views, and spatially disables the +-- current database. +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- DROP VIEW +-- CALL db2gse.ST_disable_db(1,?,?) +-- +-- For more information about the DB2 Spatial Extender Bank Demo scripts, +-- see the seBankDemoREADME.txt file. +-- +-- For more information about DB2 Spatial Extender, refer to the DB2 Spatial +-- Extender User's Guide and Reference. +-- +-- For the latest information on DB2 Spatial Extender and the Bank Demo +-- refer to the DB2 Spatial Extender website at +-- http://www.software.ibm.com/software/data/spatial/db2spatial +---------------------------------------------------------------------------- + +DROP VIEW se_demo.meridian_customers ; +DROP VIEW se_demo.sancarlos_customers; +DROP VIEW se_demo.closest_branch; +DROP VIEW se_demo.customers_savings ; +DROP VIEW se_demo.customers_checkings ; +DROP VIEW se_demo.customers_totals ; +DROP VIEW se_demo.closest_savings ; +DROP VIEW se_demo.closest_checking; +DROP VIEW se_demo.overlap_zone; +DROP VIEW se_demo.avg_savings_block; +DROP VIEW se_demo.prospects; +DROP TABLE se_demo.branch_buffers ; + +DROP TABLE se_demo.customers ; +DROP TABLE se_demo.branches ; +DROP TABLE se_demo.accounts ; +DROP TABLE se_demo.transactions ; +DROP TABLE se_demo.city_limits; +DROP TABLE se_demo.sales_regions; +DROP TABLE se_demo.sj_census_blocks; +DROP TABLE se_demo.sj_zipcodes; +DROP TABLE se_demo.sj_main_streets; + +CALL db2gse.ST_disable_db(1,?,?); diff --git a/extenders/spatial/bank/seBankDemoRunBankDemo b/extenders/spatial/bank/seBankDemoRunBankDemo new file mode 100755 index 0000000..0b4671c --- /dev/null +++ b/extenders/spatial/bank/seBankDemoRunBankDemo @@ -0,0 +1,1698 @@ +########################################################################## +# Licensed Materials - Property of IBM * +# 5765-478 * +# (c) Copyright IBM Corporation 2000-2011. * +# All rights reserved. * +# * +# US Government Users Restricted Rights - Use, duplication or * +# disclosure restricted by GSA ADP Schedule Contract with * +# IBM Corporation. * +#************************************************************************* +# Permission Notice * +# * +# Permission is granted to copy, use, modify, and merge this sample * +# software into your applications and to permit others to do any of the * +# foregoing. You may further distribute this software for * +# commercial purposes only as part of your application that adds * +# significant value and function beyond that provided by these * +# samples. * +# You must include this permission statement and retain the copyright * +# notice in all copies and modified versions of this software. * +# * +#************************************************************************* +# * +# DISCLAIMER OF WARRANTIES * +# * +# The sample software is provided to you by IBM to assist you in * +# developing your applications. THIS SOFTWARE IS PROVIDED AS-IS, * +# WITHOUT WARRANTY OF ANY KIND. IBM SHALL NOT BE LIABLE FOR ANY * +# DAMAGES ARISING OUT OF YOUR USE OR THE USE BY ANY THIRD PARTY * +# OF THE SAMPLE SOFTWARE EVEN IF IT HAS BEEN ADVISED OF THE POSSIBILITY * +# OF SUCH DAMAGES. IN ADDITION, IBM SHALL NOT BE LIABLE FOR ANY THIRD * +# PARTY CLAIMS AGAINST YOU. * +# * +#************************************************************************* +# * +# WARNING * +# * +# This sample may change your database or database manager * +# configuration. Execute the samples against a 'test' database only, * +# such as the DB2 se_bank database. * +# * +#************************************************************************* +# Product Name: DB2 Spatial Extender v10.0 +# +# Source File Name: seBankDemoRunBankDemo +# +# Version: 10.0.0 +# +# Description: This script creates a sample bank database, +# ------------ creates a sample tables, insert rows into tables, +# spatially enables the database, sets up geocoder, +# runs geocoder, imports spatial data, run grid +# index advisor. +# +# S Y N T A X: +# ------------ +# seBankDemoRunBankDemo [-i | -n | -c | -b | -h] [] +# +# If database does not exist it will be created. +# The default name that will be used is se_bank. +# +#************************************************************************* +# +# Notes: +# ------ +# 0. Before proceeding, the following steps have been done in advance: +# - DB2 UDB Spatial Extender has been installed. +# - DB2 default instance has been created. +# - Start the database manager (with the db2start command). +# - DB2PATH environment variable points to the sqllib directory +# - The user ID under which this demo is invoked must have either SYSADM +# or DBADM authority. +# 1. If you are going to create a new database or use an existing database +# certain database configuration parameters must be updated. +# The following parameters must be updated to at least the listed +# values: +# Parameter min value CO description +# ------------ --------- -- ------------------------------------------- +# APPLHEAPSZ 2048 no various (also for enable_db) +# STMTHEAP 4096 yes Various platforms raise "query too complex" +# warnings +# CO => Configurable Online +# If these parameters are not to the values listed above the demo will +# prompt the user if they would like the demo to update these values for +# the database. NOTE, that some of the values are not online +# configurable which requires a db2stop and db2start for these values to +# take effect. +# 2. This demo Creates buffer pool and temporary table space which requires +# the database manager to be stopped(db2stop) and started(db2start) for +# them to take effect. +# 3. If you are running this demo for the second time make sure all the +# previous messages files in the ~/tmp/msg* are deleted. +# +#************************************************************************* +# +# Environment: Unix +# +#************************************************************************* +# +# For more information about the DB2 Spatial Extender Bank demo script, +# see the file: seBankDemoREADME.txt +# +# For information on using DB2 SE, see the [DB2 Spatial Extender and +# Geodetic Extender User's Guide and Reference]. In this Demo, this +# document is referred to simply as the [User's Guide]. +# +# For the latest information on programming, building, and running DB2 SE +# applications, visit the DB2 Spatial Extender website: +# http://www.software.ibm.com/data/spatial/db2spatial +# +########################################################################## + +#========================================================================= +# Environment settings: +# +# This is a Korn Shell script. It can not be interpreted on all platforms +# with a Bourne Shell interpreter. We will only proceed below this point +# if ksh is found in /usr/bin or /bin for compatibility reasons. +# +# If only sh exists the script might still work. You might then try to +# comment the lines below and run the script again. +#======================================================================== +if [[ $PPID -eq $BANK_ID ]] ; then + exit $? +fi + +export BANK_ID=$$ + +if [[ -x $(which ksh) ]] ; then + $(which ksh) $0 $@ +else + echo "This script requires a Korn-Shell to run. Please make sure that 'ksh' is installed." + exit 1 +fi + +#===================================================================== +# Name: create_db +# Purpose: Create Database for bank spatial sample +# Input: +# $1 => mode +# $2 => db_name +#===================================================================== +function create_db { + # local function variables + typeset mode=$1 + typeset db_name=$2 + + typeset result='' # result of executing statement + typeset rc='' + typeset first='' # SQL error message number + + # Init log file + outfile=~/tmp/create_db.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Create database" $db_name and introduction + + echo "========================================================================" + echo " Welcome to DB2 Spatial Extender Bank Demo!" + echo " " + echo " This demo will present the commands to create a banking database " + echo " and perform some basic spatial administration. " + echo " " + echo " During the demo you will be presented with the command and also " + echo " an explanation of the command and hints and tips." + echo " " + echo " The following is a list of places to find out more information " + echo " about DB2 Spatial Extender:" + echo " - For more information about this demo please refer to the " + echo " readme seBankDemoREADME.txt. " + echo " - For more information about the commands used in this " + echo " demo please refer to the [DB2 Spatial Extender and Geodetic " + echo " Extender User's Guide and Reference] or the DB2 Information Center." + echo " In the demo, we refer" + echo " to this document simply as the [User's Guide]. " + echo " http://www.ibm.com/software/data/spatial/library.html" + echo " - For the latest information about DB2 SE please refer to our " + echo " website: http://www.ibm.com/software/data/spatial/db2spatial. " + echo " - If you have a question about using DB2 SE and the manual is " + echo " not sufficient try the DB2 Spatial Extender forum: " + echo " http://www.ibm.com/developerworks/forums/forum.jspa?forumID=296" + echo " - For technical articles about DB2 Spatial Extender search" + echo " DB2's Developer Domain at: " + echo " http://www.ibm.com/software/data/developer" + echo " " + echo " This demo is a shell script and can be stopped at any time by " + echo " pressing Control-C." + echo "------------------------------------------------------------------------" + echo "db2 create database" $db_name ". Please wait ..." + fi + + result=$(db2 create db $db_name) + rc=$? + echo "db2 create db $db_name" >>$outfile ; echo $result >>$outfile + + first=`expr "$result" | cut -d" " -f1` + + if [[ $rc = 0 ]] ; then + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo $result "\n" + press_any_key_to_continue + fi + else + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "* Create database was not successful" + echo $result + fi + # Check if the database already exists + if [[ $first = SQL1005* ]]; then + if [[ $mode = i ]] || [[ $mode = b ]]; then + press_any_key_to_continue + fi + else # The error message is not 'database already exists' + return 1 + fi + fi + + if [[ $rc = 0 ]] || [[ $first = SQL1005* ]] ; then + return 0 + else + return 1 + fi +} #//end of create_db function + + +#===================================================================== +# Name: update_cfg +# Purpose: Update database and database management configuration +# parameters necessary for the sample +# +# Parameter min value CO description +# ------------ --------- -- ------------------------------------------- +# APPLHEAPSZ 2048 no various and for enable_db +# STMTHEAP 4096 yes Various platforms raise "query too complex" +# warnings +# CO => Configurable Online +# << TO DO >> +# 1) It might be good to add a force application all if the disconnect failed +# 2) Add a refresh option +# 3) Add all the samples to the seBankDemoSpatialSQL.db2 +#===================================================================== +function update_cfg { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + + #return codes of executing statements + typeset rc1=0 ; typeset rc2=0 ; typeset rc3=0 + typeset rc4=0 ; typeset rc5=0 + typeset rc_reset=0 ; rc_terminate=0 + typeset ans='' + + # Init log file + outfile=~/tmp/update_cfg.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Update Database configuration parameters" + echo "========================================================================" + echo " For this demo to operate correctly certain database configuration" + echo " parameters may need to be updated. The suggested values are:" + echo + echo " Parameter min value CO reason" + echo " ------------ --------- -- -------------------------------------------" + echo " APPLHEAPSZ 2048 no various SE commands, in particular enable_db" + echo " STMTHEAP 4096 yes Various platforms raise \"query too complex\"" + echo " warnings with some spatial queries" + echo " CO => Configurable Online" + echo + echo " Parameters that are NOT online configurable require all applications" + echo " to be disconnected from the database before they take effect." + echo + echo " This demo expects that you are the only one connected to this database" + echo " while this demo is running. If you elected for this demo to create" + echo " the database, you will be the only user connected to the database." + echo + echo " For more information about the parameters above and tuning your database " + echo " please refer to the DB2 Performance Tuning Guide. Please note that" + echo " the suggested parameters above are not a complete set of parameters" + echo " to be considering for tuning your spatial database nor are they" + echo " necessary the optimal values. The optimal values can vary depending on" + echo " the database, application and hardware requirements, however the" + echo " values above are adequate for this demo." + echo + echo " To view your current database configuration parameters use the DB2" + echo " command: db2 get database configuration. Details about this command" + echo " can be found in the DB2 Command Line Processor manual." + echo + echo " For more information about the required minimum configuration parameter" + echo " values for your spatial database refer to Chapter \"Setting up a " + echo " database\" in the User's Guide." + echo + echo " This next section of the demo will disconnect your id from the database" + echo " and update the database configuration variables to the values above." + echo + echo "------------------------------------------------------------------------" + fi + + while : + do + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo + echo "Do you want this script to update the database configuration parameters?" + echo "<> Answer y or n, then press RETURN:" + read ans + else + ans=y + fi + case "$ans" in + y)# The update commands for online configurable parameters below + # return 0 when successful, however setting the non-online + # configurable parameters returns 2 when successful because the + # user must disconnect all applications before the updated + # values take effect. To get all 0's, you have to first + # disconnect all applications before issuing update commands. + # + # The update command returns a 4 when a syntax error occurs. + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo 'Updating database configuration parameters. Please wait ...' + fi + + log db2 connect reset + rc_reset=$? + log db2 terminate + rc_terminate=$? + + log db2 "update db cfg for $db_name using APPLHEAPSZ 2048" + rc2=$? + log db2 "update db cfg for $db_name using STMTHEAP 4096" + rc5=$? + + showlog_pause + break ;; + + n) echo + echo "|| The database configuration parameters were not updated." + echo + break ;; + + *) echo "${ans}? Please answer y or n." + esac + done + + if [[ $rc2 = 0 ]] && \ + [[ $rc5 = 0 ]] ; then + return 0 + else + return 1 + fi +} #//end of update_cfg function + + +#===================================================================== +# Name: setup_db +# Purpose: Create tablespaces and bufferpools for demo +#===================================================================== +function setup_db { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + + #return codes of executing statements + typeset rc_connect=0 + typeset rc_create_32k_bp=0; typeset rc_create_8k_bp=0 + typeset rc_create_temp_ts=0 ; typeset rc_create_user_temp_ts=0 + typeset rc_create_8k_ts=0 ; + typeset rc_grant1=0 ; typeset rc_grant2=0 + typeset rc_stop=0 ; typeset rc_start=0 + typeset rc_reset1=0 ; typeset rc_reset2=0 + + typeset ans='' + + # Init log file + outfile=~/tmp/setup_db.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Create bufferpools and tablespaces and grant public authority to" + echo "|> tablespaces." + echo "========================================================================" + echo " This part of the demo is going to create two buffer pools and three" + echo " tablespaces. The default tablespace has a 4k page size and the demo" + echo " requires one 8k page size and two 32k page size tablespaces. The 8k " + echo " page tablespace is for importing a shapefile with more columns than fit" + echo " on a 4k page size. The user temporary tablespace is used by the index" + echo " advisor. The temporary table space is used for complex ad hoc queries." + echo " The user temporary and temporary tablespace both use a 32k page size." + echo + echo " Each tablespace must have an associated bufferpool. Since the default" + echo " bufferpool is of a small 4k page, therefore I need to create two other" + echo " bufferpools for the 8k and 32k tablespaces." + echo + echo " When a new bufferpool is created is requires the database to be stopped" + echo " before it goes into affect. Therefore, this next section will stop and" + echo " start the database manager." + echo + echo " This section also grants access to these new tablespaces to public, so" + echo " that anyone can create tables in these tablespaces." + echo + echo " For more information about bufferpools and tablespaces, please refer to" + echo " the DB2 SQL Reference. For more information about the tablespace " + echo " requirements of the grid index advisor (gseidx) refer to chapter " + echo " \"Using indexes and views to access spatial data\" in the User's Guide." + echo "------------------------------------------------------------------------" + fi + + while : + do + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo + echo 'Do you want this script to create the bufferpools and tablespaces,' + echo ' which requires a stop and start of the database manager?' + echo '<> Answer y or n, then press RETURN: ' + read ans + else + ans=y + fi + case "$ans" in + y) if [[ $mode = i ]] || [[ $mode = b ]]; then + echo 'Creating the bufferpools and tablespaces. Please wait ...' + fi + + log db2 CONNECT RESET + rc_reset1=$? + log db2 CONNECT TO $db_name + rc_connect=$? + log db2 CREATE BUFFERPOOL se_bank_32k_bp SIZE 1024 PAGESIZE 32 K + rc_create_32k_bp=$? + log db2 CREATE BUFFERPOOL se_bank_8k_bp SIZE 1024 PAGESIZE 8 K + rc_create_8k_bp=$? + + log db2 "CREATE TEMPORARY TABLESPACE se_bank_temp_ts \ + PAGESIZE 32 K MANAGED BY SYSTEM USING ('se_bank_container_32k_tt') \ + EXTENTSIZE 64 PREFETCHSIZE 32 BUFFERPOOL se_bank_32k_bp" + rc_create_ts=$? + + log db2 "CREATE USER TEMPORARY TABLESPACE \ + se_bank_u_temp_ts \ + PAGESIZE 32 K MANAGED BY SYSTEM USING ('se_bank_container_32k_utt') \ + EXTENTSIZE 64 PREFETCHSIZE 32 BUFFERPOOL se_bank_32k_bp" + rc_create_user_ts=$? + + log db2 "CREATE TABLESPACE se_bank_8k_ts\ + PAGESIZE 8 K MANAGED BY SYSTEM USING ('se_bank_container_8k') \ + EXTENTSIZE 16 PREFETCHSIZE 8 BUFFERPOOL se_bank_8k_bp" + rc_create_8k_ts=$? + + log db2 GRANT USE OF TABLESPACE se_bank_u_temp_ts TO PUBLIC + rc_grant1=$? + + log db2 GRANT USE OF TABLESPACE se_bank_8k_ts TO PUBLIC + rc_grant2=$? + + log db2 CONNECT RESET + rc_reset2=$? + + log db2stop force + rc_stop=$? + + log db2start + rc_start=$? + + showlog_pause + break ;; + n) echo ; echo "|| The bufferpools and tablespaces were not created." + break ;; + *) echo ; echo "${ans}? Please answer y or n." + esac + done + + if [[ $rc_create_8k_bp = 0 ]] && \ + [[ $rc_create_temp_ts = 0 ]] && [[ $rc_create_user_temp_ts = 0 ]] && \ + [[ $rc_create_8k_ts = 0 ]] && [[ $rc_grant1 = 0 ]] && [[ $rc_grant2 = 0 ]] + then + return 0 + else + return 1 + fi +} #//end of setup_db function + + +#===================================================================== +# Name: enable_db +# Purpose: Spatially enable bank sample database +#===================================================================== +function enable_db { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + typeset rc='' + + # Init log file + outfile=~/tmp/enable_db.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Spatially enable database" + echo "========================================================================" + echo " Most of DB2's Spatial Extender administration is handled by a set of " + echo " stored procedures. Two user friendly mechanisms for calling these" + echo " stored procedures are provided via the command line tool db2se and the" + echo " Spatial Extender Menu Option in the DB2 Control Center. You will have" + echo " access to these tools once the Spatial Extender is installed." + echo " " + echo " The first step that must be performed on every database that you want to" + echo " store spatial data in is to spatially enable the database. Spatially " + echo " enabling your database creates the infrastructure to " + echo " perform all spatial tasks. The spatially enabling step creates all of" + echo " the spatial types, spatial User Defined Functions, spatial administrative" + echo " stored procedures, the grid spatial index and the spatial catalog." + echo " " + echo " For syntax help on using db2se, typing db2se -h will give you usage" + echo " options." + echo " " + echo " For more information about db2se command and the Control Center " + echo " Spatial Extender options, please refer to the User's Guide chapters " + echo " \"DB2 Spatial Extender commands\" and" + echo " \"Setting up spatial resources for a database\"." + echo "------------------------------------------------------------------------" + echo " " + echo " Spatially enabling database" $db_name ". Please wait - this operation " + echo " might take several minutes to complete." + fi + + log db2se enable_db $db_name + rc=$? + if [[ $rc = 0 ]] ; then + showlog_pause + else + echo "* Spatially enabling the database " $db_name " was not successful:" + showlog + + # not successful + return 1 + fi + + return 0 +} #//end of enable_db function + + +#===================================================================== +# Name: create_tables +# Purpose: Create tables +#===================================================================== +function create_tables { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + typeset rc_connect='' + typeset rc='' + + # Init log file + outfile=~/tmp/create_tables.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Create tables for Banking Demo" + echo "========================================================================" + echo " The definition for the tables is located in seBankDemoDDL.db2." + echo " All the tables are created in the se_demo schema." + echo " Name Description" + echo " ----------- -----------------------------------------------------" + echo " Customers Information about each customer" + echo " Branches Information about each bank branch office" + echo " Accounts Information about the customers checking & saving accounts" + echo " Transactions Information about each banking transaction a customer makes" + echo + echo "------------------------------------------------------------------------" + echo "db2 connect to" $db_name " Please wait ..." + fi + + log db2 CONNECT TO $db_name + rc_connect=$? + + if [[ $rc_connect = 0 ]] ; then + # Successful connection - run the script + log db2 -tvf $DB2PATH/samples/extenders/spatial/bank/seBankDemoDDL.db2 + rc=$? + + if [[ $rc = 0 ]] ; then + showlog_pause + else + echo "* Create tables for Banking Demo not successful:" + showlog + + # not successful + return 1 + fi + else + echo "* Could not connect to " $db_name ":" + showlog + + # not successful + return 1 + fi + + return 0 +} #//end of create_tables function + + + +#===================================================================== +# Name: insert_data +# Purpose: Insert non-spatial data. +#===================================================================== +function insert_data { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + typeset rc='' + typeset rc_connect='' + + # Init log file + outfile=~/tmp/insert_data.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Populate tables with records" + echo "========================================================================" + echo " This step is going to insert data into the previously created tables." + echo "------------------------------------------------------------------------" + echo "db2 connect to" $db_name " Please wait ..." + fi + + log db2 connect to $db_name + rc_connect=$? + + if [[ $rc_connect = 0 ]] ; then + # Successful connection - run the script + log db2 -tvf $DB2PATH/samples/extenders/spatial/bank/seBankDemoTableData.db2 + rc=$? + + if [[ $rc = 0 ]] ; then + showlog_pause + else + echo "* Populate tables not successful:" + showlog + + # not successful + return 1 + fi + else + echo "* Could not connect to " $db_name ":" + showlog + + # not successful + return 1 + fi + + return 0 +} #//end of insert_data function + + + +#===================================================================== +# Name: add_spatial_column +# Purpose: Alter tables and add spatial column +#===================================================================== +function add_spatial_column { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + + typeset rc_connect='' + typeset rc_customers=''; typeset rc_branches='' + + # Init log file + outfile=~/tmp/add_spatial_column.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Add spatial column to business tables" + echo "========================================================================" + echo " There are 13 spatial types that comply to the OGC and SQL/MM object" + echo " hierarchy. The spatial types are all part of the db2gse schema. The" + echo " spatial types are User Defined Structured Types that are created during" + echo " the spatial enable database step. These spatial types can be used just" + echo " like any other SQL data types." + echo + echo " In the following step, we are going to alter the customers and branches" + echo " tables and add a spatial column to store the location of customers and" + echo " branches." + echo + echo " For more information about the User Defined Structure types refer to" + echo " DB2 SQL Reference, in particular the Object-Relational section. For" + echo " more information about the spatial types refer to the User's Guide" + echo " chapter \"Setting up spatial columns\"." + echo "------------------------------------------------------------------------" + echo + echo "Adding spatial columns to business tables. Please wait ..." + fi + + log db2 connect to $db_name + rc_connect=$? + + if [[ $rc_connect = 0 ]] ; then + # Successful connection + log db2 "ALTER TABLE se_demo.customers ADD COLUMN location db2gse.ST_Point" + rc_customers=$? + + log db2 "ALTER TABLE se_demo.branches ADD COLUMN location db2gse.ST_Point" + rc_branches=$? + + showlog_pause + else + echo "* Could not connect to " $db_name ":" + showlog + return 1 + fi + + if [[ $rc_customers = 0 ]] && [[ $rc_branches = 0 ]] ; then + return 0 + else + return 1 + fi +} #//end of add_spatial_column function + + + +#===================================================================== +# Name: check_srs +# Purpose: Checks if an appropriate spatial reference system exists +#===================================================================== +function check_srs { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + typeset rc_info=''; typeset rc_connect='' + + # Init log file + outfile=~/tmp/check_srs.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Check spatial reference system" + echo "========================================================================" + echo " A spatial reference system defines the spatial domain and precision" + echo " of the spatial data being stored in a column. The spatial domain " + echo " consists of the maximum possible spatial extent of your coordinate" + echo " values and the coordinate system associated with the spatial data." + echo + echo " The spatial extent is defined by X, Y, Z, and M offset values. The " + echo " coordinate system geo-references your data in space. It defines the" + echo ' origin, units and possibly a projection used (only for projected' + echo ' coordinate systems). For performance reasons, DB2 SE internally ' + echo " stores all spatial data as positive integer values. When you " + echo " define your spatial extent, you must consider your minimum and maximum " + echo ' X, Y (and Z, M) values, and provide offsets so that all your values' + echo " can be converted to positive numbers in the coordinate space. The " + echo " conversions are only for internal purposes and handled automatically " + echo " once they are set." + echo + echo " db2se shape_info command can help you determine the spatial extent" + echo " of a shapefile and possibly the coordinate system if a *.prj file" + echo " exists." + echo + echo " The spatial precision for your data is defined by the X, Y, Z, and M " + echo " scale factors. The spatial precision also factors into the spatial" + echo " extent. The spatial precision is reversely proportional to the" + echo ' spatial extent. As the spatial precision goes up (you can ' + echo 'store more precise values) the size of your extent goes down (you' + echo 'have a smaller extent). Conversely, as spatial precision does down' + echo "your extent goes up. Therefore, the spatial precision defines the" + echo 'upper limit of your spatial extent, the max X, Y and Z (and M).' + echo + echo "For more information, please refer to the User's Guide chapter " + echo "\"Setting up spatial resources for a database\"." + echo + echo "The following are the commands associated with spatial systems:" + echo " db2se create_cs [-h]" + echo " db2se alter_cs [-h]" + echo " db2se drop_cs [-h]" + echo " db2se create_srs [-h]" + echo " db2se alter_srs [-h]" + echo " db2se drop_srs [-h]" + echo + echo "In this step we are going to use db2se shape_info to get information" + echo "about a shapefile and in particular determine if there is an " + echo "existing spatial reference system that can contain the spatial data." + echo "------------------------------------------------------------------------" + echo + echo "db2 connect to" $db_name ". Please wait ..." + fi + + log db2 connect to $db_name + rc_connect=$? + + if [[ $rc_connect = 0 ]] ; then + # Successful connection + + log db2se shape_info -fileName $DB2PATH/samples/extenders/spatial/data/cityLimits -database $db_name + rc_info=$? + + showlog_pause + else + echo "* Could not connect to " $db_name ":" + showlog + return 1 + fi + + if [[ $rc_info = 0 ]] ; then + return 0 + else + return 1 + fi +} #//end of check_srs function + + +#===================================================================== +# Name: populate_location +# Purpose: Setup geocoding and auto_gc for customers and branches table +#===================================================================== +function populate_location { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + + typeset rc_register_gc1=0 ; typeset rc_auto_gc1=0 + typeset rc_register_gc2=0 ; typeset rc_auto_gc2=0 + typeset rc_cp_ref=0 ; typeset rc_cp_loc=0 + + # Init log file + outfile=~/tmp/populate_location.out + rm -f $outfile 2>/dev/null + + echo "========================================================================" + echo "|> Set location column from latitude and longitude values" + echo "========================================================================" + + log db2 "update se_demo.customers set location = db2gse.st_point(longitude, latitude, 1)" + rc_auto_gc1=$? + + log db2 "update se_demo.branches set location = db2gse.st_point(longitude, latitude, 1)" + rc_auto_gc2=$? + + showlog_pause + + if [[ $rc_auto_gc1 = 0 ]] && [[ $rc_auto_gc2 = 0 ]] ; then + return 0 + else + return 1 + fi +} #//end of populate_location function + + +#===================================================================== +# Name: geo_queries +# Purpose: Basic spatial queries with customer and branch +# data +#===================================================================== +function geo_queries { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + + typeset rc_connect=''; typeset rc_function_path='' + typeset rc_query1=''; typeset rc_query2=''; typeset rc_query3=''; + + # Init log file + outfile=~/tmp/geo_queries.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Basic spatial queries with customer and branch data" + echo "========================================================================" + echo " In this step you will have a chance to perform a few basic spatial " + echo " queries." + echo + echo " All the spatial User Defined Functions (UDFs) are in the db2gse " + echo " library. If you do not want to specify the library every time you use " + echo " a function you can add it to the current function path. For example:" + echo " db2 SET CURRENT FUNCTION PATH = CURRENT FUNCTION PATH, db2gse" + echo " This is active for the length of your database connection. For more" + echo " information, please refer to the User's Guide chapter " + echo " \"Spatial functions: categories and uses\". " + echo "------------------------------------------------------------------------" + echo + echo "db2 connect to" $db_name " Please wait ..." + fi + + log db2 connect to $db_name + rc_connect=$? + + log db2 SET CURRENT FUNCTION PATH = CURRENT FUNCTION PATH, db2gse + rc_function_path=$? + + showlog + + if [[ $mode = i ]] || [[ $mode = b ]]; then + typeset q3="db2 SELECT c.name AS cust_name, b.name AS branch_name, DECIMAL(db2gse.st_distance(b.location, c.location, 'KILOMETER'), 6, 2) AS distance FROM se_demo.branches b, se_demo.customers c WHERE db2gse.st_distance(b.location, c.location, 'KILOMETER') < 1 ORDER BY distance" + + PS3='Basic Query? ' + select choice in \ + 'describe branches table', \ + 'view branches location coordinates', \ + 'find branch customers within 1 kilometer of my branches' \ + 'continue demo' + do + case $REPLY in + 1 ) db2 DESCRIBE TABLE se_demo.branches ;; + 2 ) db2 'SELECT name, VARCHAR(ST_AsText(location), 50) FROM se_demo.branches' ;; + 3 ) $q3 ;; + 4 ) break ;; + * ) echo "Please select a number 1-4 or ENTER to see the menu" ;; + esac + done + + press_any_key_to_continue + fi + + return 0 +} #//end of geo_queries function + + +#===================================================================== +# Name: import_shapefiles +# Purpose: Template to use for the rest of the functions +#===================================================================== +function import_shapefiles { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + + typeset rc_city=''; typeset rc_main=''; typeset rc_zip='' + typeset rc_census=''; typeset rc_sales='' + + # Init temporary log file + outfile=~/tmp/import_shapefiles.tmp + + # Init log file + outfile1=~/tmp/import_shapefiles.out + rm -f $outfile1 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Import Reference and Demographic Census Shapefiles" + echo "========================================================================" + echo " Many data providers and GIS products can produce shapefiles. DB2" + echo " Spatial Extender provides a set of spatial data CD's with sample " + echo " spatial data in shapefile format. " + echo + echo " In this step we will import a set of shapefiles. The shapefiles " + echo " contain census demographic data and spatial background data. The " + echo " spatial background data helps reference your data when viewing it on" + echo " a map." + echo + echo " When you import shapefile data you need to provide a spatial reference" + echo " system that the spatial data is going to belong to. For this example" + echo " we are going to use spatial reference system NAD83_SRS_1. " + echo + echo " When you spatial data via db2se you can also specify whether you want" + echo " Spatial Extender to look for the file on the client or server " + echo " filesystem via the createTableFlag option." + echo + echo " When you import shapefiles you can optionally create two other files" + echo " an exception and message file. The message file contains a status " + echo " of the import process and provides information about how many shapes" + echo " were imported. It also says whether a block of shapes failed. If it" + echo " fails it writes the block of shapes out the exception file. Note, " + echo " the block is defined by the commit scope and if within that block there" + echo " is one invalid shape the entire block is rejected. If this happens" + echo " import the exception file with a small commit scope to identify the " + echo " shape that is failing." + echo "------------------------------------------------------------------------" + echo " Please wait - this operation might take several minutes to complete." + echo + fi + + file1=~/tmp/parcels + do_import cityLimits city_limits $file1 1 200 $db_name + rc_city=$? + + file2=~/tmp/main_streets + do_import sjMainStreets sj_main_streets $file2 1 200 $db_name + rc_main=$? + + file3=~/tmp/zip_codes + do_import sjZipCodes sj_zipcodes $file3 1 200 $db_name + rc_zip=$? + + file4=~/tmp/census + do_import sjCensusBlocks sj_census_blocks $file4 1 200 $db_name + rc_census=$? + + file5=~/tmp/sales + do_import salezones sales_regions $file5 0 200 $db_name + rc_sales=$? + + if [[ $mode = i ]] || [[ $mode = b ]]; then + press_any_key_to_continue + fi + + outfile=$outfile1 + + if [[ $rc_city = 0 ]] && [[ $rc_main = 0 ]] && [[ $rc_zip = 0 ]] && \ + [[ $rc_census = 0 ]] && [[ $rc_sales = 0 ]] ; then + return 0 + else + return 1 + fi +} #//end of import_shapefiles function + + +#===================================================================== +# Name: do_import (called by imp_shape) +# Purpose: Imports a shapefile and prints/logs the results. +# Input: $1 => shapefile name +# $2 => table name +# $3 => exception (.shp) and message (.msg) files name +# $4 => if 1 then an id_column with name SE_ROW_ID is created +# otherwise, no id_column +# $5 => commitScope +# $6 => db_name +# Global vars: +# $outfile => temporary log file +# $outfile1 => permanent log file +# $db_name => database name +# Returns: return code of import command +#===================================================================== +function do_import { + typeset id_col=''; typeset rc=''; typeset line='' + typeset db_name=$6 + + if [[ $4 = 1 ]]; then + id_col="-idColumn se_row_id -idColumnIsIdentity 1" + fi + + # Prepare the command line + line="db2se import_shape $db_name" + line="$line -fileName $DB2PATH/samples/extenders/spatial/data/$1" + line="$line -srsName NAD83_SRS_1 -tableSchema se_demo" + line="$line -tableName $2" + line="$line -spatialcolumn geometry -createTableFlag 1 -commitScope $5" + line="$line $id_col" + line="$line -exceptionFile $3.shp" + line="$line -messagesFile $3.msg" + + # Run import, then show and log results + rm -f $outfile $3.shp $3.msg 2>/dev/null + log2 $line + rc=$? + + showlog + + echo $line >>$outfile1 + echo " " >>$outfile1 + cat $outfile >>$outfile1 2>/dev/null + echo " " >>$outfile1 + + return $rc +} #//end of do_import function + + +#===================================================================== +# Name: grid_index_advisor +# Purpose: Demonstrate how to use Grid Index Advisor(gseidx) +#===================================================================== +function grid_index_advisor { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + typeset rc='' + + # Init log file + outfile=~/tmp/grid_index_advisor.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Grid Index Advisor" + echo "========================================================================" + echo " DB2 SE uses an extended index to index spatial data. The spatial index " + echo " method used is a Grid Index Method. The grid index divides the " + echo " planimetric area into equal size rectangles. You can have the grid " + echo " levels each with it own grid rectangle size." + echo + echo " DB2 SE provides a client tool gseidx to provide statistics and " + echo " recommendations on the grid sizes." + echo + echo " In the following step we are going to ask the grid index advisor to " + echo " advise us on the recommended grid sizes for the geometry column in the" + echo " sj_main_streets table. When gathering statistics on a grid index you" + echo " have the option to gather statistics on all the data or a sampling. " + echo " The following will advise you on the grid index, however it is only" + echo " going to sample 30 percent of the data." + echo + echo " For more information about grid index and the grid index advisor refer" + echo " to chapter \"Using indexes and views to access spatial data\" in the" + echo " User's Guide." + echo "------------------------------------------------------------------------" + echo + echo " Running the Index Advisor." + echo " Please wait - this operation might take several minutes to complete." + fi + + log gseidx "connect to $db_name get geometry statistics for column \ + se_demo.sj_main_streets(geometry) analyze 30 % advise" + rc=$? + showlog_pause + + if [[ $rc = 0 ]] ; then + return 0 + else + return 1 + fi +} #//end of grid_index_advisor function + + +#===================================================================== +# Name: create_grid_index +# Purpose: Create a grid index with suggested Grid Index Advisor values +#===================================================================== +function create_grid_index { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + typeset rc_connect=''; typeset rc='' + + # Init log file + outfile=~/tmp/create_grid_index.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Create Grid Index" + echo "========================================================================" + echo " In this step we are going to create a grid index. To create a grid " + echo " index you use the extended index syntax and specify that you are " + echo " going to use an extended index using a grid index extension. A grid " + echo " index can have three levels. The grid levels are in increasing order." + echo + echo " For more information on extended indexes refer to the SQL reference." + echo " For more information about the grid index refer to chapter \"Using " + echo " indexes and views to access spatial data\" in the User's Guide." + echo "------------------------------------------------------------------------" + echo + echo " Creating grid index..." + echo " Please wait - this operation might take several minutes to complete." + fi + + log db2 connect to $db_name + rc_connect=$? + + if [[ $rc_connect = 0 ]] ; then + log db2 "CREATE INDEX se_demo.gidx_main_str ON \ + se_demo.sj_main_streets(geometry) \ + EXTEND USING db2gse.spatial_index(0.04, 0.0, 0.0)" + rc=$? + showlog_pause + else + echo "* Could not connect to " $db_name ":" + showlog + return 1 + fi + + if [[ $rc = 0 ]] ; then + return 0 + else + return 1 + fi +} #//end of create_grid_index function + + +#===================================================================== +# Name: create_views +# Purpose: Template to use for the rest of the functions +#===================================================================== +function create_views { + # Input Parameters + # $1 => mode + # $2 => db_name + # typeset declares local function variables + typeset mode=$1 + typeset db_name=$2 + + typeset rc_connect=1; typeset rc=1 + + # Init log file + outfile=~/tmp/create_views.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Create Views" + echo "========================================================================" + echo " This step is going to create a series of views that could be used " + echo " by a geobrowser to visualize the spatial analysis performed by the " + echo " query." + echo + echo " The views are defined in the file seBankDemoViewDDL.db2" + echo + echo " For more information about creating views refer to the DB2 SQL " + echo " reference book." + echo "------------------------------------------------------------------------" + echo + echo " Creating the views. Please wait ..." + fi + + log db2 connect to $db_name + rc_connect=$? + + if [[ $rc_connect = 0 ]] ; then + # Successful connection + log db2 -tvf $DB2PATH/samples/extenders/spatial/bank/seBankDemoViewDDL.db2 + rc=$? + + if [[ $rc = 0 ]] ; then + showlog_pause + else + echo "* DB2 Spatial View Creation not successful:" + showlog + + # not successful + return 1 + fi + else + echo "* Could not connect to " $db_name ":" + showlog + + # not successful + return 1 + fi + + if [[ $rc = 0 ]] ; then + return 0 + else + return 1 + fi +} #//end of create_views function + + +#===================================================================== +# Name: register_spatial_columns +# Purpose: Register the spatial columns created in tables and view +# by this demo. +#===================================================================== +function register_spatial_columns { +# Input Parameters +# $1 => mode +# $2 => db_name + + typeset mode=$1 + typeset db_name=$2 + + typeset rc_register1=''; typeset rc_register2=''; typeset rc_register3=''; + typeset rc_register4=''; typeset rc_register5=''; typeset rc_register6=''; + typeset rc_register7=''; + + # Init log file + outfile=~/tmp/register_spatial_columns.out + rm -f $outfile 2>/dev/null + + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "========================================================================" + echo "|> Register Spatial Columns" + echo "========================================================================" + echo " The spatial extender allows you to create a constraint on a spatial" + echo " column that enforces the constraint that all spatial data in the " + echo " column must belong to the same spatial reference system." + echo + echo " Many spatial visualization tools require that all the spatial data" + echo " in one column being visualized belong to the same spatial reference " + echo " system." + echo + echo " For more information about registering spatial columns refer to " + echo " chapter \"Setting up spatial columns\" in the User's Guide." + echo "------------------------------------------------------------------------" + echo + echo " Registering spatial columns. Please wait ..." + fi + + log db2se register_spatial_column $db_name -tableSchema se_demo \ + -tableName branches -columnName location -srsName NAD83_SRS_1 + rc_register1=$? + + log db2se register_spatial_column $db_name -tableSchema se_demo \ + -tableName customers -columnName location -srsName NAD83_SRS_1 + rc_register2=$? + + log db2se register_spatial_column $db_name -tableSchema se_demo \ + -tableName city_limits -columnName geometry -srsName NAD83_SRS_1 + rc_register3=$? + + log db2se register_spatial_column $db_name -tableSchema se_demo \ + -tableName sales_regions -columnName geometry -srsName NAD83_SRS_1 + rc_register4=$? + + log db2se register_spatial_column $db_name -tableSchema se_demo \ + -tableName sj_census_blocks -columnName geometry -srsName NAD83_SRS_1 + rc_register5=$? + + log db2se register_spatial_column $db_name -tableSchema se_demo \ + -tableName sj_main_streets -columnName geometry -srsName NAD83_SRS_1 + rc_register6=$? + + log db2se register_spatial_column $db_name -tableSchema se_demo \ + -tableName sj_zipcodes -columnName geometry -srsName NAD83_SRS_1 + rc_register7=$? + + showlog_pause + + if [[ $rc_register1 = 0 ]] && [[ $rc_register2 = 0 ]] && \ + [[ $rc_register3 = 0 ]] && [[ $rc_register4 = 0 ]] && \ + [[ $rc_register5 = 0 ]] && [[ $rc_register6 = 0 ]] && \ + [[ $rc_register7 = 0 ]] ; then + return 0 + else + return 1 + fi +} #//end of register_spatial_columns function + + +#===================================================================== +# Name: press_any_key_to_continue +# Purpose: Pause before starting next part of demo +#===================================================================== +function press_any_key_to_continue { + # typeset declares local function variables + typeset ans='' + echo ; echo "<> Press RETURN to continue..." + read ans +} #//end of press_any_key_to_continue function + + +#===================================================================== +# Name: log +# Purpose: Execute a command and append its output to the file +# indicated by $outfile +# Input: +# $* => the command +#===================================================================== +function log { + echo "$*" >>$outfile + $* >>$outfile 2>&1 + return $? +} + + +#===================================================================== +# Name: log2 +# Purpose: Echo a command to stdout immediately, then execute it and +# append its output to the file indicated by %log% +# Input: +# $* => the command +#===================================================================== +function log2 { + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo "$*" + fi + $* >>$outfile 2>&1 + return $? +} + + +#===================================================================== +# Name: showlog +# Purpose: If $mode is b or i, then sends the file specified by +# $outfile to the standard output -- no pause afterwards. +# Input: +# $mode (must be b or i for the log to go to stdout) +#===================================================================== +function showlog { + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo ; cat $outfile 2>/dev/null ; echo + fi +} + + +#===================================================================== +# Name: showlog_pause +# Purpose: If $mode is b or i, then sends the file specified by +# $outfile to the standard output, then pauses. +# Input: +# $mode (must be b or i for the log to go to stdout) +#===================================================================== +function showlog_pause { + if [[ $mode = i ]] || [[ $mode = b ]]; then + echo ; cat $outfile 2>/dev/null ; echo + press_any_key_to_continue + fi +} + + +#===================================================================== +# Name: loglog +# Purpose: Appends a timestamp and current file $1 to main log file $2 +# Input: +# $1 => current file +# $2 => main log file +#===================================================================== +function loglog { + if [[ -n $2 ]] ; then + echo "##############################################################" >>$2 + echo "`date` - $1" >>$2 + echo "##############################################################" >>$2 + cat $1 >>$2 2>/dev/null + echo " " >>$2 + fi +} + + +#===================================================================== +# Name: usage +# Purpose: Echoes on stdout a command help message. +#===================================================================== +function usage { + echo "Usage: seBankDemoRunBankDemo -i | -n | -c | -b | -h []" + echo " -i = interactive mode (the default mode)" + echo " -n = non-interactive mode: runs all the sample steps without" + echo " prompting the user" + echo " -c = installation confirmation test" + echo " -b = basic mode: creates database, tables, and inserts non-spatial data" + echo " -h = help: prints this usage message" + echo " The default database name is se_bank." + echo +} + + +#===================================================================== +# Name: scripterr +# Purpose: Called whenever an error occurs +#===================================================================== +function scripterr { + # may do some cleanup here ... + if [[ $mode = c ]] ; then + echo "DB2 SE failed the confirmation test" + fi + exit 1 +} + +#===================================================================== +# Name: returncodes +# Purpose: Called when we are done with everything +#===================================================================== +function returncodes { + echo "Function return codes:" + echo "create_db : $rc_create_db" + echo "update_cfg : $rc_update_cfg" + echo "setup_db : $rc_setup_db" + echo "enable_db : $rc_enable_db" + echo "create_tables : $rc_create_tables" + echo "insert_data : $rc_insert_data" + echo "add_spatial_column : $rc_add_spatial_column" + echo "chk_srs : $rc_check_srs" + echo "populate_location : $rc_populate_location" + echo "geo_queries : $rc_geo_queries" + echo "import_shapefiles : $rc_import_shapefiles" + echo "grid_index_advisor : $rc_grid_index_advisor" + echo "create_grid_index : $rc_create_grid_index" + echo "create_views : $rc_create_views" + echo "register_spatial_columns: $rc_register_spatial_columns" + echo "Please check logfiles in ~/tmp/ for details." +} + +#--------------------------------------------------------------------- +# Main script +#--------------------------------------------------------------------- +# Check environment +if [[ -z $DB2PATH ]] ; then + # Must have DB2PATH set + echo "Please set the DB2PATH environment variable to point to the" + echo "sqllib directory of your DB2 installation." + echo "Example: export DB2PATH=~/sqllib" + exit 1 +fi + +# Handle options and arguments +mode=0 +let number_of_options=0 + +while getopts ":incbh" opt; do + # counter keeps track how many options are specified + ((number_of_options= number_of_options + 1)) + + # if more than one option is specified print message and exit + if ((number_of_options > 1)); then + usage + echo "You can only specify one option and you specified" $number_of_options "options." + exit 1 + fi + + # set the correction more for the various options + case $opt in + i) mode=i ;; + n) mode=n ;; + c) mode=c ;; + b) mode=b ;; + \?) usage + exit 1 ;; + *) usage + exit 1 ;; + esac +done +shift $(($OPTIND - 1)) + +if ((number_of_options == 0)); then + #Default mode is (i)nteractive + mode=i +fi + +# Make sure that 1 or less arguments are specified +if (($# > 1)); then + usage + echo "You can only specify one argument after the options, and you specified" + echo " " $# "arguments: " $@ + exit 1 +fi + +# Set the first argument as the database name +database_name=$1 + +# If database_name is null then set it to default of se_bank +database_name=${database_name:=se_bank} + + +#--------------------------------------------------------------------- +# Start demo +#--------------------------------------------------------------------- +rc_create_db=0; rc_update_cfg=0; rc_setup_db=0; rc_enable_db=0; +rc_create_tables=0; rc_insert_data=0; rc_add_spatial_column=0; +rc_check_srs=0; rc_setup_geocoder=0; rc_run_geocoder=0; +rc_geo_queries=0; rc_import_shapefiles=0; +rc_grid_index_advisor=0; rc_create_grid_index=0; rc_create_views=0; +rc_register_spatial_columns=0 + + +# create the directory to write the output to +mkdir -m 755 ~/tmp 2>/dev/null + +# Init and timestamp the log file +logg=~/tmp/${database_name}.log +rm -f $logg >/dev/null 2>&1 +echo "`date` - seBankDemoRunBankDemo starting..." >>$logg +outfile=~/tmp/create_db.out + +# start the database instance +db2start + +# Create and configure the database, create tables and insert +# non-spatial data +create_db $mode $database_name ; rc_create_db=$? +loglog $outfile $logg +[[ $mode != c ]] && ([[ $rc_create_db -eq 0 ]] || scripterr) + +# we no longer need to update the configuration +#update_cfg $mode $database_name ; rc_update_cfg=$? +loglog $outfile $logg +[[ $mode != c ]] && ([[ $rc_update_cfg -eq 0 ]] || scripterr) + +setup_db $mode $database_name ; rc_setup_db=$? +loglog $outfile $logg +[[ $mode != c ]] && ([[ $rc_setup_db -eq 0 ]] || scripterr) + +enable_db $mode $database_name ; rc_enable_db=$? +loglog $outfile $logg +[[ $mode != c ]] && ([[ $rc_enable_db -eq 0 ]] || scripterr) + +create_tables $mode $database_name ; rc_create_tables=$? +loglog $outfile $logg +[[ $mode != c ]] && ([[ $rc_create_tables -eq 0 ]] || scripterr) + +insert_data $mode $database_name ; rc_insert_data=$? +loglog $outfile $logg +[[ $mode != c ]] && ([[ $rc_insert_data -eq 0 ]] || scripterr) + +if [[ $mode = i ]] || [[ $mode = n ]] || [[ $mode = c ]]; then + add_spatial_column $mode $database_name ; rc_add_spatial_column=$? + loglog $outfile $logg + [[ $mode != c ]] && ([[ $rc_add_spatial_column -eq 0 ]] || scripterr) + + check_srs $mode $database_name ; rc_check_srs=$? + loglog $outfile $logg + [[ $mode != c ]] && ([[ $rc_check_srs -eq 0 ]] || scripterr) + + populate_location $mode $database_name ; rc_populate_location=$? + loglog $outfile $logg + [[ $mode != c ]] && ([[ $rc_populate_location -eq 0 ]] || scripterr) + + if [[ $mode = i ]] ; then + # Run queries only in interactive mode + geo_queries $mode $database_name ; rc_geo_queries=$? + loglog $outfile $logg + [[ $mode != c ]] && ([[ $rc_geo_queries -eq 0 ]] || scripterr) + fi + + typeset file1=''; typeset file2=''; typeset file3='' + typeset file4=''; typeset file5='' + import_shapefiles $mode $database_name ; rc_import_shapefiles=$? + loglog $outfile $logg + # copy msg and exp files to the main log + [[ -f ${file1}.msg ]] && loglog ${file1}.msg $logg + [[ -f ${file2}.msg ]] && loglog ${file2}.msg $logg + [[ -f ${file3}.msg ]] && loglog ${file3}.msg $logg + [[ -f ${file4}.msg ]] && loglog ${file4}.msg $logg + [[ -f ${file5}.msg ]] && loglog ${file5}.msg $logg + [[ $mode != c ]] && ([[ $rc_import_shapefiles -eq 0 ]] || scripterr) + + if [[ $mode = i ]] || [[ $mode = c ]]; then + # Demo grid index advisor + grid_index_advisor $mode $database_name ; rc_grid_index_advisor=$? + loglog $outfile $logg + [[ $mode != c ]] && ([[ $rc_grid_index_advisor -eq 0 ]] || scripterr) + fi + + create_grid_index $mode $database_name ; rc_create_grid_index=$? + loglog $outfile $logg + [[ $mode != c ]] && ([[ $rc_create_grid_index -eq 0 ]] || scripterr) + + create_views $mode $database_name ; rc_create_views=$? + loglog $outfile $logg + [[ $mode != c ]] && ([[ $rc_create_views -eq 0 ]] || scripterr) + + register_spatial_columns $mode $database_name ; rc_register_spatial_columns=$? + loglog $outfile $logg + [[ $mode != c ]] && ([[ $rc_register_spatial_columns -eq 0 ]] || scripterr) +fi + +if [[ $rc_create_db -eq 0 ]] && [[ $rc_update_cfg -eq 0 ]] && \ + [[ $rc_setup_db -eq 0 ]] && [[ $rc_enable_db -eq 0 ]] && \ + [[ $rc_create_tables -eq 0 ]] && [[ $rc_insert_data -eq 0 ]] && \ + [[ $rc_add_spatial_column -eq 0 ]] && [[ $rc_check_srs -eq 0 ]] && \ + [[ $rc_populate_location -eq 0 ]] && \ + [[ $rc_geo_queries -eq 0 ]] && [[ $rc_import_shapefiles -eq 0 ]] && \ + [[ $rc_grid_index_advisor -eq 0 ]] && \ + [[ $rc_create_grid_index -eq 0 ]] && [[ $rc_create_views -eq 0 ]] && \ + [[ $rc_register_spatial_columns -eq 0 ]] ; then + + if [[ $mode = c ]] ; then + echo "DB2 Spatial Extender ran the confirmation test successfully." + returncodes + else + echo "DB2 Spatial Extender test has finished successfully." + returncodes + fi + +else + + if [[ $mode = c ]] ; then + echo "DB2 Spatial Extender failed the confirmation test." + returncodes + else + echo "DB2 Spatial Extender terminated with errors." + returncodes + fi + exit 1 +fi +exit 0 + +#********************************************************************** +# End of DB2 Spatial Extender sample 'seBankDemoRunBankDemo' +#********************************************************************** diff --git a/extenders/spatial/bank/seBankDemoSpatialSQL.db2 b/extenders/spatial/bank/seBankDemoSpatialSQL.db2 new file mode 100644 index 0000000..46e83f6 --- /dev/null +++ b/extenders/spatial/bank/seBankDemoSpatialSQL.db2 @@ -0,0 +1,1437 @@ +---------------------------------------------------------------------------- +-- Licensed Materials - Property of IBM +-- Governed under the terms of the IBM Public License +-- +-- (C) COPYRIGHT International Business Machines Corp. 2000 - 2014 +-- All Rights Reserved. +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +---------------------------------------------------------------------------- +-- +-- Product Name: DB2 Spatial Extender 10.5 +-- +-- Source File Name: seBankDemoSpatialSQL.db2 +-- +-- Version: 10.5.1 +-- +-- Description: examples spatial UDF's from the Spatial Extender User's Guide +-- +-- +-- For more information about the DB2 Spatial Extender Bank Demo scripts, +-- see the seBankDemoREADME.txt file. +-- +-- For more information about DB2 SE, see the "DB2 Spatial Extender User Guide". +-- +-- For the latest information on DB2 Spatial Extender and the Bank Demo +-- refer to the DB2 Spatial Extender website at +-- http://www.software.ibm.com/software/data/spatial/db2spatial +---------------------------------------------------------------------------- +--connect to se_bank; +--=============================================================== +-- List Current Function Path +--=============================================================== +-- VALUES(CURRENT FUNCTION PATH); + +--=============================================================== +-- Update Current Function Path +--=============================================================== +--SET CURRENT FUNCTION PATH = CURRENT FUNCTION PATH, db2gse; + +--=============================================================== +-- ST_Area(geometry) +--=============================================================== +--!db2se drop_srs se_bank -srsName new_york1983; + +--!db2se create_srs se_bank -srsId 4000 -srsName new_york1983 -xOffset 0 -yOffset 0 -xScale 1 -yScale 1 -coordsysName NAD_1983_StatePlane_New_York_East_FIPS_3101_Feet; + +--DROP TABLE sample_polygons; +--CREATE TABLE sample_polygons (id SMALLINT, geometry ST_POLYGON) organize by row; + +--INSERT INTO sample_polygons (id, geometry) +--VALUES +-- (1, ST_Polygon('polygon((0 0, 0 10, 10 10, 10 0, 0 0))', 4000) ), +-- (2, ST_Polygon('polygon((20 0, 30 20, 40 0, 20 0 ))', 4000) ), +-- (3, ST_Polygon('polygon((20 30, 25 35, 30 30, 20 30))', 4000)); + +--SELECT id, ST_Area(geometry) AS area +--FROM sample_polygons; + +----The following does the same as the above only with method notation +--SELECT id, geometry..ST_AREA AS area +--FROM sample_polygons; + +--SELECT id, +-- ST_Area(geometry) square_feet, +-- ST_Area(geometry, 'METER') square_meters, +-- ST_Area(geometry, 'STATUTE MILE') square_miles +--FROM sample_polygons; + +--=============================================================== +-- ST_AsBinary(geometry) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT, wkb BLOB(32k)) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (1100, ST_Point(10, 20, 1)); + +--INSERT INTO sample_points(id, wkb) +--VALUES (2222, +-- (SELECT ST_AsBinary(geometry) +-- FROM sample_points +-- WHERE id = 1100)); + +--SELECT id, cast(ST_AsText(ST_Point(wkb)) AS varchar(35)) AS point +--FROM sample_points +--WHERE id = 2222; + +----This one is equal to the one above, but it uses method notation +--SELECT id, cast(ST_Point(wkb)..ST_AsText AS varchar(35)) AS point +--FROM sample_points +--WHERE id = 2222; + +--SELECT id, substr(ST_AsBinary(geometry), 1, 21) AS point_wkb +--FROM sample_points +--WHERE id = 1100; + +--=============================================================== +-- ST_AsGML(geometry) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT, gml CLOB(32K)) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (1100, ST_Point(10, 20, 1)); + +--INSERT INTO sample_points(id, gml) +--VALUES (2222, +-- (SELECT ST_AsGML(geometry) +-- FROM sample_points +-- WHERE id = 1100)); + +--SELECT id, cast(ST_AsGML(geometry) AS varchar(110)) AS gml_fragment +--FROM sample_points +--WHERE id = 1100; + +--=============================================================== +-- ST_AsShape(geometry) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT, shape BLOB(32K)) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (1100, ST_Point(10, 20, 1)); + +--INSERT INTO sample_points(id, shape) +--VALUES (2222, +-- (SELECT ST_AsShape(geometry) +-- FROM sample_points +-- WHERE id = 1100)); + +--SELECT id, substr(ST_AsShape(geometry), 1, 20) AS shape +--FROM sample_points +--WHERE id = 1100; + +--=============================================================== +-- ST_AsText(geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id SMALLINT, spatial_type varchar(18), geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, spatial_type, geometry) +--VALUES +-- (1, 'st_point', ST_Point(50, 50, 0) ), +-- (2, 'st_linestring', ST_LineString('linestring(200 100, 210 130, 220 140)', 0) ), +-- (3, 'st_polygon', ST_Polygon('polygon((110 120, 110 140, 130 140, 130 120, 110 120))', 0) ); + +--SELECT id, spatial_type, cast(geometry..ST_AsText AS varchar(150)) AS wkt +--FROM sample_geometries; + +--=============================================================== +-- ST_Buffer(geometry, radius) +-- ST_Buffer(geometry, radius, unit) +--=============================================================== +--!db2se drop_srs se_bank -srsName new_york1983; + +--!db2se create_srs se_bank -srsId 4000 -srsName new_york1983 -xOffset 0 -yOffset 0 -xScale 1 -yScale 1 -coordsysName NAD_1983_StatePlane_New_York_East_FIPS_3101_Feet; + +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id INTEGER, spatial_type varchar(18), geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, spatial_type, geometry) +--VALUES +-- (1, 'st_point', ST_Point(50, 50, 4000) ), +-- (2, 'st_linestring', ST_LineString('linestring(200 100, 210 130, 220 140)', 4000) ), +-- (3, 'st_polygon', ST_Polygon('polygon((110 120, 110 140, 130 140, 130 120, 110 120))', 4000) ), +-- (4, 'st_multipolygon', ST_MultiPolygon('multipolygon(( +-- (30 30, 30 40, 35 40, 35 30, 30 30), +-- (35 30, 35 40, 45 40, 45 30, 35 30)))', 4000)); + +--SELECT id, spatial_type, +-- cast(geometry..ST_Buffer(10)..ST_AsText AS varchar(470)) AS buffer_10 +--FROM sample_geometries; + +-- Defect -- SQL0440N No authorized routine named "ST_NUMPOLYGONS" of type "FUNCTION" having compatible arguments was found. SQLSTATE=42884 +--SELECT id, spatial_type, +-- cast(geometry..ST_Buffer(10)..ST_AsText AS varchar(470)) AS buffer, +-- ST_NumPolygons(ST_Buffer(geometry, 10)) +--FROM sample_geometries +--WHERE id = 4; + +--SELECT id, spatial_type, +-- cast(ST_AsText(ST_Buffer(geometry, -5)) AS varchar(150)) AS buffer_negative_5 +--FROM sample_geometries +--WHERE id = 3; + +--SELECT id, spatial_type, +-- cast(ST_AsText(ST_Buffer(geometry, 10, 'METER')) AS varchar(680)) AS buffer_10_meter +--FROM sample_geometries +--WHERE id = 3; + + +--=============================================================== +-- ST_Contains(geometry, geometry) +--=============================================================== +--DROP TABLE sample_points; +--DROP TABLE sample_lines; +--DROP TABLE sample_polygons; + +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT) organize by row; +--CREATE TABLE sample_lines(id SMALLINT, geometry ST_LINESTRING) organize by row; +--CREATE TABLE sample_polygons(id SMALLINT, geometry ST_POLYGON) organize by row; + +--INSERT INTO sample_points (id, geometry) +--VALUES +-- (1, ST_Point(10, 20, 1)), +-- (2, ST_Point('point(41 41)', 1)); + +--INSERT INTO sample_lines (id, geometry) +--VALUES +-- (10, ST_LineString('linestring (1 10, 3 12, 10 10)', 1) ), +-- (20, ST_LineString('linestring (50 10, 50 12, 45 10)', 1) ); + +--INSERT INTO sample_polygons(id, geometry) +--VALUES +-- (100, ST_Polygon('polygon((0 0, 0 40, 40 40, 40 0, 0 0))', 1) ); + +--SELECT poly.id AS polygon_id, +-- CASE ST_Contains(poly.geometry, pts.geometry) +-- WHEN 0 THEN 'does not contain' +-- WHEN 1 THEN 'does contain' +-- END AS contains, +-- pts.id AS point_id +--FROM sample_points pts, sample_polygons poly; + +--SELECT poly.id AS polygon_id, +-- CASE ST_Contains(poly.geometry, line.geometry) +-- WHEN 0 THEN 'does not contain' +-- WHEN 1 THEN 'does contain' +-- END AS contains, +-- line.id AS line_id +--FROM sample_lines line, sample_polygons poly; + +--=============================================================== +-- ST_ConvexHull(geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries (id SMALLINT, spatial_type varchar(18), geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, spatial_type, geometry) +--VALUES +-- (1, 'ST_LineString', ST_LineString('linestring(20 20, 30 30, 20 40, 30 50)', 0) ), +-- (2, 'ST_Polygon', ST_Polygon('polygon((110 120, 110 140, 120 130, 110 120))', 0) ), +-- (3, 'ST_Polygon', ST_Polygon('polygon((30 30, 25 35, 15 50, 35 80, 40 85, 80 90, 70 75, 65 70, 55 50, 75 40, 60 30, 30 30))', 0) ), +-- (4, 'ST_MultiPoint', ST_MultiPoint('multipoint(20 20, 30 30, 20 40, 30 50)', 1) ); + +--SELECT id, spatial_type, cast(geometry..ST_ConvexHull..ST_AsText AS varchar(300)) AS convexhull +--FROM sample_geometries; + +--=============================================================== +-- ST_Distance(geometry, geometry) +--=============================================================== +--DROP TABLE sample_geometries1; +--DROP TABLE sample_geometries2; +--CREATE TABLE sample_geometries1 (id SMALLINT, spatial_type varchar(13), geometry ST_GEOMETRY) organize by row; +--CREATE TABLE sample_geometries2 (id SMALLINT, spatial_type varchar(13), geometry ST_GEOMETRY) organize by row; +rganize by row + +--INSERT INTO sample_geometries1(id, spatial_type, geometry) +--VALUES +-- ( 1, 'ST_Point', ST_Point('point(100 100)', 1) ), +-- (10, 'ST_LineString', ST_LineString('linestring(125 125, 125 175)', 1) ), +-- (20, 'ST_Polygon', ST_Polygon('polygon((50 50, 50 150, 150 150, 150 50, 50 50))', 1) ); + +--INSERT INTO sample_geometries2(id, spatial_type, geometry) +--VALUES +-- (101, 'ST_Point', ST_Point('point(200 200)', 1) ), +-- (102, 'ST_Point', ST_Point('point(200 300)', 1) ), +-- (103, 'ST_Point', ST_Point('point(200 0)', 1) ), +-- (110, 'ST_LineString', ST_LineString('linestring(200 100, 200 200)', 1) ), +-- (120, 'ST_Polygon', ST_Polygon('polygon((200 0, 200 200, 300 200, 300 0, 200 0))', 1) ); + +--SELECT sg1.id AS sg1_id, sg1.spatial_type AS sg1_type, +-- sg2.id AS sg1_id, sg2.spatial_type AS sg2_type, +-- cast(ST_Distance(sg1.geometry, sg2.geometry) AS Decimal(8, 4)) AS distance +--FROM sample_geometries1 sg1, sample_geometries2 sg2 +--ORDER BY sg1.id; + +--SELECT sg1.id AS sg1_id, sg1.spatial_type AS sg1_type, +-- sg2.id AS sg1_id, sg2.spatial_type AS sg2_type, +-- cast(ST_Distance(sg1.geometry, sg2.geometry) AS Decimal(8, 4)) AS distance +--FROM sample_geometries1 sg1, sample_geometries2 sg2 +--WHERE ST_Distance(sg1.geometry, sg2.geometry) <= 100; + +--SELECT sg1.id AS sg1_id, sg1.spatial_type AS sg1_type, +-- sg2.id AS sg1_id, sg2.spatial_type AS sg2_type, +-- cast(ST_Distance(sg1.geometry, sg2.geometry, 'KILOMETER') AS DECIMAL(10, 4)) AS distance +--FROM sample_geometries1 sg1, sample_geometries2 sg2 +--ORDER BY sg1.id; + +--=============================================================== +-- St_FindMeasure(geometry, measure) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries (id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (1, ST_LineString('linestring m (2 2 3, 3 5 3, 3 3 6, 4 4 8)', 1)), +-- (2, ST_MultiPoint('multipoint m (2 2 3, 3 5 3, 3 3 6, 4 4 6, 5 5 6, 6 6 8)', 1)); + +--SELECT id, cast(ST_AsText(ST_FindMeasure(geometry, 7)) AS varchar(45)) AS measure_7 +--FROM sample_geometries; + +-- Same as above, but with method notation +--SELECT id, cast(geometry..ST_FindMeasure(7)..ST_AsText AS varchar(45)) AS measure_7 +--FROM sample_geometries; + +--SELECT id, cast(ST_AsText(ST_FindMeasure(geometry, 6)) AS varchar(120)) AS measure_6 +--FROM sample_geometries; + +--SELECT id, cast(geometry..ST_FindMeasure(6)..ST_AsText AS varchar(120)) AS measure_6 +--FROM sample_geometries; + +--=============================================================== +-- ST_GeomCollection(LOB) +--=============================================================== +--DROP TABLE sample_geomcollections; +--CREATE TABLE sample_geomcollections (id SMALLINT, geometry ST_GEOMCOLLECTION) organize by row; + +--INSERT INTO sample_geomcollections(id, geometry) +--VALUES +-- (4001, ST_GeomCollection('multipoint(1 2, 4 3, 5 6)', 1) ), +-- (4002, ST_GeomCollection('multilinestring( +-- (33 2, 34 3, 35 6), +-- (28 4, 29 5, 31 8, 43 12), +-- (39 3, 37 4, 36 7))', 1) ), +-- (4003, ST_GeomCollection('multipolygon(((3 3, 4 6, 5 3, 3 3), +-- (8 24, 9 25, 1 28, 8 24), +-- (13 33, 7 36, 1 40, 10 43, 13 33)))', 1)), +-- (4004, ST_GeomCollection('10203040', 1)); + +--SELECT id, cast(geometry..ST_AsText AS varchar(350)) AS geomcollection +--FROM sample_geomcollections; + +--=============================================================== +-- ST_GeomCollFromTxt(WKT) +--=============================================================== +--DROP TABLE sample_geomcollections; +--CREATE TABLE sample_geomcollections (id SMALLINT, geometry ST_GEOMCOLLECTION) organize by row; + +--INSERT INTO sample_geomcollections(id, geometry) +--VALUES +-- (4011, ST_GeomCollFromTxt('multipoint(1 2, 4 3, 5 6)', 1) ), +-- (4012, ST_GeomCollFromTxt('multilinestring( +-- (33 2, 34 3, 35 6), +-- (28 4, 29 5, 31 8, 43 12), +-- (39 3, 37 4, 36 7))', 1) ), +-- (4013, ST_GeomCollFromTxt('multipolygon(((3 3, 4 6, 5 3, 3 3), +-- (8 24, 9 25, 1 28, 8 24), +-- (13 33, 7 36, 1 40, 10 43, 13 33)))', 1)); + +--SELECT id, cast(geometry..ST_AsText AS varchar(340)) AS GeomCollection +--FROM sample_geomcollections; + +--=============================================================== +-- ST_GeomCollFromWKB(WKB) +--=============================================================== +--DROP TABLE sample_geomcollections; +--CREATE TABLE sample_geomcollections (id SMALLINT, geometry ST_GEOMCOLLECTION, wkb BLOB(32k)) organize by row; + +--INSERT INTO sample_geomcollections(id, geometry) +--VALUES +-- (4021, ST_GeomCollFromTxt('multipoint(1 2, 4 3, 5 6)', 1) ), +-- (4022, ST_GeomCollFromTxt('multilinestring( +-- (33 2, 34 3, 35 6), +-- (28 4, 29 5, 31 8, 43 12))', 1)); + +--UPDATE sample_geomcollections AS temp_correlated +--SET wkb = geometry..ST_AsBinary +--WHERE id = temp_correlated.id; + +--SELECT id, cast(ST_GeomCollFromWKB(wkb)..ST_AsText AS varchar(190)) AS GeomCollection +--FROM sample_geomcollections; + +--=============================================================== +-- ST_Geometry(LOB) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries (id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (7001, ST_Geometry('point(1 2)', 1) ), +-- (7002, ST_Geometry('linestring(33 2, 34 3, 35 6)', 1) ), +-- (7003, ST_Geometry('polygon((3 3, 4 6, 5 3, 3 3))', 1)), +-- (7004, ST_Geometry('5060', 1)); + +--SELECT id, cast(geometry..ST_AsText AS varchar(120)) AS Geometry +--FROM sample_geometries; + +--=============================================================== +-- ST_GeometryN(ST_GeomCollection) +--=============================================================== +--DROP TABLE sample_geomcollections; +--CREATE TABLE sample_geomcollections (id SMALLINT, geometry ST_GEOMCOLLECTION) organize by row; + +--INSERT INTO sample_geomcollections(id, geometry) +--VALUES +-- (4001, ST_GeomCollection('multipoint(1 2, 4 3)', 1) ), +-- (4002, ST_GeomCollection('multilinestring( +-- (33 2, 34 3, 35 6), +-- (28 4, 29 5, 31 8, 43 12), +-- (39 3, 37 4, 36 7))', 1) ), +-- (4003, ST_GeomCollection('multipolygon(((3 3, 4 6, 5 3, 3 3), +-- (8 24, 9 25, 1 28, 8 24), +-- (13 33, 7 36, 1 40, 10 43, 13 33)))', 1)); + +--SELECT id, cast(ST_GeometryN(geometry, 2)..ST_AsText AS varchar(110)) AS second_geometry +--FROM sample_geomcollections; + +--=============================================================== +-- ST_GeometryType(ST_Geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries (id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (7101, ST_Geometry('point(1 2)', 1) ), +-- (7102, ST_Geometry('linestring(33 2, 34 3, 35 6)', 1) ), +-- (7103, ST_Geometry('polygon((3 3, 4 6, 5 3, 3 3))', 1)), +-- (7104, ST_Geometry('multipoint(1 2, 4 3)', 1) ); + +--SELECT id, geometry..ST_GeometryType AS geometry_type +--FROM sample_geometries; + +--=============================================================== +-- ST_GeomFromTxt(WKT) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries (id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (1251, ST_GeomFromText('point(1 2)', 1) ), +-- (1252, ST_GeomFromText('linestring(33 2, 34 3, 35 6)', 1) ), +-- (1253, ST_GeomFromText('polygon((3 3, 4 6, 5 3, 3 3))', 1)); + +--SELECT id, cast(geometry..ST_AsText AS varchar(105)) AS Geometry +--FROM sample_geometries; + +--=============================================================== +-- ST_GeomFromWKB(WKB) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries (id SMALLINT, geometry ST_GEOMETRY, wkb BLOB(32K)) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (1901, ST_GeomFromText('point(1 2)', 1) ), +-- (1902, ST_GeomFromText('linestring(33 2, 34 3, 35 6)', 1) ), +-- (1903, ST_GeomFromText('polygon((3 3, 4 6, 5 3, 3 3))', 1)); + +--UPDATE sample_geometries AS temp_correlated +--SET wkb = geometry..ST_AsBinary +--WHERE id = temp_correlated.id; + +--SELECT id, cast(ST_GeomFromWKB(wkb)..ST_AsText AS varchar(190)) AS Geometry +--FROM sample_geometries; + +--=============================================================== +-- ST_Intersects(geometry, geometry) +--=============================================================== +--DROP TABLE sample_geometries1; +--DROP TABLE sample_geometries2; +--CREATE TABLE sample_geometries1 (id SMALLINT, spatial_type varchar(13), geometry ST_GEOMETRY) organize by row; +--CREATE TABLE sample_geometries2 (id SMALLINT, spatial_type varchar(13), geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries1(id, spatial_type, geometry) +--VALUES +-- ( 1, 'ST_Point', ST_Point('point(550 150)', 1) ), +-- (10, 'ST_LineString', ST_LineString('linestring(800 800, 900 800)', 1) ), +-- (20, 'ST_Polygon', ST_Polygon('polygon((500 100, 500 200, 700 200, 700 100, 500 100))', 1) ); + +--INSERT INTO sample_geometries2(id, spatial_type, geometry) +--VALUES +-- (101, 'ST_Point', ST_Point('point(550 150)', 1) ), +-- (102, 'ST_Point', ST_Point('point(650 200)', 1) ), +-- (103, 'ST_Point', ST_Point('point(800 800)', 1) ), +-- (110, 'ST_LineString', ST_LineString('linestring(850 250, 850 850)', 1) ), +-- (120, 'ST_Polygon', ST_Polygon('polygon((650 50, 650 150, 800 150, 800 50, 650 50))', 1) ), +-- (121, 'ST_Polygon', ST_Polygon('polygon((20 20, 20 40, 40 40, 40 20, 20 20))', 1) ); + +--SELECT sg1.id AS sg1_id, sg1.spatial_type AS sg1_type, +-- sg2.id AS sg1_id, sg2.spatial_type AS sg2_type, +-- CASE ST_Intersects(sg1.geometry, sg2.geometry) +-- WHEN 0 THEN 'Geometries do not intersect' +-- WHEN 1 THEN 'Geometries intersect' +-- END AS intersects +--FROM sample_geometries1 sg1, sample_geometries2 sg2 +--ORDER BY sg1.id; + + +--=============================================================== +-- ST_Length(geometry) +--=============================================================== +DROP TABLE sample_geometries; +CREATE TABLE sample_geometries(id SMALLINT, spatial_type varchar(20), geometry ST_GEOMETRY) organize by row; + +INSERT INTO sample_geometries(id, spatial_type, geometry) +VALUES + (1110, 'ST_LineString', ST_LineString('linestring(50 10, 50 20)', 1) ), + (1111, 'ST_MultiLineString', ST_MultiLineString('multilinestring( + (33 2, 34 3, 35 6), + (28 4, 29 5, 31 8, 43 12), + (39 3, 37 4, 36 7))', 1) ); + +SELECT id, spatial_type, cast(ST_Length(ST_ToLineString(geometry)) AS DECIMAL(7, 2)) AS line_length +FROM sample_geometries +WHERE id = 1110; + +----Does the same as above, but in method notation +--SELECT id, spatial_type, cast(ST_Length(geometry..ST_ToLineString) AS DECIMAL(7, 2)) AS line_length +--FROM sample_geometries +--WHERE id = 1110; + +----Currently this is failing with a GSE3016 defect +SELECT id, spatial_type, ST_Length(ST_ToMultiLine(geometry)) AS multiline_length +FROM sample_geometries +WHERE id = 1111; + +----Does the same as above, but in method notation +--SELECT id, spatial_type, ST_Length(geometry..ST_ToMultiLine) AS multiline_length +--FROM sample_geometries +--WHERE id = 1111; + +--=============================================================== +-- ST_LineFromText(WKT) +--=============================================================== +--DROP TABLE sample_lines; +--CREATE TABLE sample_lines(id SMALLINT, geometry ST_LineString) organize by row; + +--INSERT INTO sample_lines(id, geometry) +--VALUES +-- (1110, ST_LineFromText('linestring(850 250, 850 850)', 1) ), +-- (1111, ST_LineFromText('linestring empty', 1) ); + +--SELECT id, cast(geometry..ST_AsText AS varchar(75)) AS LineString +--FROM sample_lines; + +--=============================================================== +-- ST_LineFromWKB(WKB) +--=============================================================== +--DROP TABLE sample_lines; +--CREATE TABLE sample_lines(id SMALLINT, geometry ST_LineString, wkb BLOB(32k)) organize by row; + +--INSERT INTO sample_lines(id, geometry) +--VALUES +-- (1901, ST_LineString('linestring(850 250, 850 850)', 1) ), +-- (1902, ST_LineString('linestring(33 2, 34 3, 35 6)', 1) ); + +--UPDATE sample_lines AS temp_correlated +--SET wkb = geometry..ST_AsBinary +--WHERE id = temp_correlated.id; + +--SELECT id, cast(ST_LineFromWKB(wkb)..ST_AsText AS varchar(90)) AS Line +--FROM sample_lines; + +--=============================================================== +-- ST_LineString(LOB) +--=============================================================== +--DROP TABLE sample_lines; +--CREATE TABLE sample_lines(id SMALLINT, geometry ST_LineString) organize by row; + +--INSERT INTO sample_lines(id, geometry) +--VALUES +-- (1110, ST_LineString('linestring(850 250, 850 850)', 1) ), +-- (1111, ST_LineString('9090100100', 1) ); + +--SELECT id, cast(geometry..ST_AsText AS varchar(75)) AS linestring +--FROM sample_lines; + +--=============================================================== +-- ST_LineStringN(ST_MultiLineString) +--=============================================================== +--DROP TABLE sample_mlines; +--CREATE TABLE sample_mlines (id SMALLINT, geometry ST_MULTILINESTRING) organize by row; + +--INSERT INTO sample_mlines(id, geometry) +--VALUES +-- (1110, ST_MultiLineString('multilinestring( +-- (33 2, 34 3, 35 6), +-- (28 4, 29 5, 31 8, 43 12), +-- (39 3, 37 4, 36 7))', 1) ), +-- (1111, ST_MLineFromText('multilinestring( +-- (61 2, 64 3, 65 6), +-- (58 4, 59 5, 61 8), +-- (69 3, 67 4, 66 7, 68 9))', 1) ); + +--SELECT id, cast(ST_LineStringN(geometry, 2)..ST_AsText AS varchar(110)) AS second_linestring +--FROM sample_mlines; + +--=============================================================== +-- ST_M(st_point) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (1, ST_Point(2, 3, 32, 5, 1)), +-- (2, ST_Point(4, 5, 20, 4, 1)), +-- (3, ST_Point(3, 8, 23, 7, 1)); + +--SELECT id, ST_M(geometry) AS measure +--FROM sample_points; + +----This does the same as above only in Method Notation +--SELECT id, geometry..ST_M AS measure +--FROM sample_points; + +--SELECT id, cast(ST_AsText(ST_M(geometry, 40)) AS varchar(60)) AS measure_40 +--FROM sample_points +--WHERE id = 3; + +--=============================================================== +-- ST_MaxM(st_geometry) +-- ST_MaxX(st_geometry) +-- ST_MaxY(st_geometry) +-- ST_MaxZ(st_geometry) +-- ST_MinM(st_geometry) +-- ST_MinX(st_geometry) +-- ST_MinY(st_geometry) +-- ST_MinZ(st_geometry) +--=============================================================== +--DROP TABLE sample_polygons; +--CREATE TABLE sample_polygons(id SMALLINT, geometry ST_POLYGON) organize by row; + +--INSERT INTO sample_polygons(id, geometry) +--VALUES +-- (1, ST_Polygon('polygon zm((110 120 20 3, 110 140 22 3, 120 130 26 4, 110 120 20 3))', 0) ), +-- (2, ST_Polygon('polygon zm((0 0 40 7, 0 4 35 9, 5 4 32 12, 5 0 31 5, 0 0 40 7))', 0) ), +-- (3, ST_Polygon('polygon zm((12 13 10 16 , 8 4 10 12, 9 4 12 11, 12 13 10 16))', 0) ); + +----------------------------------------------------------------- +-- ST_MaxM(st_geometry) +----------------------------------------------------------------- +--SELECT id, cast(geometry..ST_MaxM() AS SMALLINT) AS max_measure_per_polygon +--FROM sample_polygons; + +--< TO DO >-- +--How do you include the id without the SQL failing +--SELECT cast(MAX(geometry..ST_MaxM()) AS SMALLINT) AS max_measure +--FROM sample_polygons; + +----------------------------------------------------------------- +-- ST_MaxX(st_geometry) +----------------------------------------------------------------- +--SELECT id, cast(geometry..ST_MaxX() AS SMALLINT) AS max_x_coordinate_per_polygon +--FROM sample_polygons; + +--SELECT cast(MAX(geometry..ST_MaxX()) AS SMALLINT) AS max_x_coordinate +--FROM sample_polygons; + +--Super Min/Max Example +--SELECT cast(MIN(ST_MinX(geometry)) AS SMALLINT) AS MinX, +-- cast(MIN(ST_MinY(geometry)) AS SMALLINT) AS MinY, +-- cast(MIN(ST_MinZ(geometry)) AS SMALLINT) AS MinZ, +-- cast(MIN(ST_MinM(geometry)) AS SMALLINT) AS MinM, +-- cast(MAX(ST_MaxX(geometry)) AS SMALLINT) AS MaxX, +-- cast(MAX(ST_MaxY(geometry)) AS SMALLINT) AS MaxY, +-- cast(MAX(ST_MaxZ(geometry)) AS SMALLINT) AS MaxZ, +-- cast(MAX(ST_MaxM(geometry)) AS SMALLINT) AS MaxM +--FROM sample_polygons; + +----------------------------------------------------------------- +-- ST_MaxY(st_geometry) +----------------------------------------------------------------- +--SELECT id, cast(geometry..ST_MaxY() AS SMALLINT) AS max_y_coordinate_per_polygon +--FROM sample_polygons; + +--SELECT cast(MAX(geometry..ST_MaxY()) AS SMALLINT) AS max_y_coordinate +--FROM sample_polygons; + +----------------------------------------------------------------- +-- ST_MaxZ(st_geometry) +----------------------------------------------------------------- +--SELECT id, cast(geometry..ST_MaxZ() AS SMALLINT) AS max_z_coordinate_per_polygon +--FROM sample_polygons; + +--SELECT cast(MAX(geometry..ST_MaxZ()) AS SMALLINT) AS max_z_coordinate +--FROM sample_polygons; + +----------------------------------------------------------------- +-- ST_MinM(st_geometry) +----------------------------------------------------------------- +--SELECT id, cast(geometry..ST_MinM() AS SMALLINT) AS min_m_coordinate_per_polygon +--FROM sample_polygons; + +--SELECT cast(MIN(geometry..ST_MinM()) AS SMALLINT) AS min_m_coordinate +--FROM sample_polygons; + +----------------------------------------------------------------- +-- ST_MinX(st_geometry) +----------------------------------------------------------------- +--SELECT id, cast(geometry..ST_MinX() AS SMALLINT) AS min_x_coordinate_per_polygon +--FROM sample_polygons; + +--SELECT cast(MIN(geometry..ST_MinX()) AS SMALLINT) AS min_x_coordinate +--FROM sample_polygons; + +----------------------------------------------------------------- +-- ST_MinY(st_geometry) +----------------------------------------------------------------- +--SELECT id, cast(geometry..ST_MinY() AS SMALLINT) AS min_y_coordinate_per_polygon +--FROM sample_polygons; + +--SELECT cast(MIN(geometry..ST_MinY()) AS SMALLINT) AS min_y_coordinate +--FROM sample_polygons; + + +----------------------------------------------------------------- +-- ST_MinZ(st_geometry) +----------------------------------------------------------------- +--SELECT id, cast(geometry..ST_MinZ() AS SMALLINT) AS min_z_coordinate_per_polygon +--FROM sample_polygons; + +--SELECT cast(MIN(geometry..ST_MinZ()) AS SMALLINT) AS min_z_coordinate +--FROM sample_polygons; + + +--=============================================================== +-- St_MBR(geometry) +--=============================================================== +--DROP TABLE sample_polygons; +--CREATE TABLE sample_polygons (id SMALLINT, geometry ST_POLYGON) organize by row; + +--INSERT INTO sample_polygons (id, geometry) +--VALUES +-- (1, ST_Polygon('polygon((5 5, 7 7, 5 9, 7 9, 9 11, 13 9, 15 9, 13 7, 15 5, 9 6, 5 5))', 0) ), +-- (2, ST_Polygon('polygon((20 30, 25 35, 30 30, 20 30))', 0)); + +--SELECT id, cast(geometry..ST_MBR..ST_AsText AS varchar(150)) AS MBR +--FROM sample_polygons; + +--=============================================================== +-- St_MBRIntersect(geometry) +--=============================================================== +--DROP TABLE sample_polygons; +--CREATE TABLE sample_polygons (id SMALLINT, geometry ST_POLYGON) organize by row; + +--INSERT INTO sample_polygons (id, geometry) +--VALUES +-- (1, ST_Polygon('polygon((0 0, 30 0, 40 30, 40 35, 5 35, 5 10, 20 10, 20 5, 0 0))', 0) ), +-- (2, ST_Polygon('polygon((15 15, 15 20, 60 20, 60 15, 15 15))', 0) ), +-- (3, ST_Polygon('polygon((115 15, 115 20, 160 20, 160 15, 115 15))', 0) ); + +--SELECT sp1.id, sp2.id, +-- CASE ST_MBRIntersects(sp1.geometry, sp2.geometry) +-- WHEN 0 THEN 'MBRs do not intersect' +-- WHEN 1 THEN 'MBRs intersect' +-- END AS mbr_intersects +--FROM sample_polygons sp1, sample_polygons sp2 +--WHERE sp1.id <= sp2.id; + +--=============================================================== +-- St_MeasureBetween(geometry, startMeasure, endMeasure) +--=============================================================== +--DROP TABLE sample_lines; +--CREATE TABLE sample_lines (id SMALLINT, geometry ST_LINESTRING) organize by row; + +--INSERT INTO sample_lines(id, geometry) +--VALUES +-- (1, ST_LineString('linestring m (2 2 3, 3 5 3, 3 3 6, 4 4 6, 5 5 6, 6 6 8)', 1)); + +--SELECT id, cast(geometry..ST_MeasureBetween(4, 6)..ST_AsText AS varchar(150)) AS measure_between_4_and_6 +--FROM sample_lines; + +--=============================================================== +-- St_MidPoint(st_linestring) +--=============================================================== +--DROP TABLE sample_lines; +--CREATE TABLE sample_lines (id SMALLINT, geometry ST_LINESTRING) organize by row; + +--INSERT INTO sample_lines(id, geometry) +--VALUES +-- (1, ST_LineString('linestring (0 0, 0 10, 0 20, 0 30, 0 40)', 1)), +-- (2, ST_LineString('linestring (2 2, 3 5, 3 3, 4 4, 5 5, 6 6)', 1)), +-- (3, ST_LineString('linestring (0 10, 0 0, 10 0, 10 10)', 1)), +-- (4, ST_LineString('linestring (0 20, 5 20, 10 20, 15 20)', 1)); + +--SELECT id, cast(ST_AsText(ST_MidPoint(geometry)) AS varchar(60)) AS mid_point +--FROM sample_lines; + +---- Does the same as above but in method notation +--SELECT id, cast(geometry..ST_MidPoint..ST_AsText AS varchar(60)) AS mid_point +--FROM sample_lines; + +--=============================================================== +-- St_MLineFromText(WKT) +--=============================================================== +--DROP TABLE sample_mlines; +--CREATE TABLE sample_mlines (id SMALLINT, geometry ST_MULTILINESTRING) organize by row; + +--INSERT INTO sample_mlines(id, geometry) +--VALUES +-- (1110, ST_MLineFromText('multilinestring( +-- (33 2, 34 3, 35 6), +-- (28 4, 29 5, 31 8, 43 12), +-- (39 3, 37 4, 36 7))', 1) ); + +--SELECT id, cast(geometry..ST_AsText AS varchar(280)) AS multilinestring +--FROM sample_mlines +--WHERE id = 1110; + +--=============================================================== +-- ST_MLineFromWKB(WKB) +--=============================================================== +--DROP TABLE sample_mlines; +--CREATE TABLE sample_mlines (id SMALLINT, geometry ST_MULTILINESTRING, wkb BLOB(32K)) organize by row; + +--INSERT INTO sample_mlines(id, geometry) +--VALUES +-- (10, ST_MLineFromText('multilinestring( +-- (61 2, 64 3, 65 6), +-- (58 4, 59 5, 61 8), +-- (69 3, 67 4, 66 7, 68 9))', 1) ); + +--UPDATE sample_mlines AS temp_correlated +--SET wkb = geometry..ST_AsBinary +--WHERE id = temp_correlated.id; + +--SELECT id, cast(ST_MLineFromWKB(wkb)..ST_AsText AS varchar(280)) AS MultiLineString +--FROM sample_mlines +--WHERE id = 10; + +--=============================================================== +-- ST_MPointFromText(WKT) +--=============================================================== +--DROP TABLE sample_mpoints; +--CREATE TABLE sample_mpoints (id SMALLINT, geometry ST_MULTIPOINT) organize by row; + +--INSERT INTO sample_mpoints(id, geometry) +--VALUES +-- (1110, ST_MPointFromText('multipoint(1 2, 4 3, 5 6)', 1) ); + +--SELECT id, cast(geometry..ST_AsText AS varchar(280)) AS MultiPoint +--FROM sample_mpoints +--WHERE id = 1110; + + +--=============================================================== +-- ST_MPointFromWKB(WKB) +--=============================================================== +--DROP TABLE sample_mpoints; +--CREATE TABLE sample_mpoints (id SMALLINT, geometry ST_MULTIPOINT, wkb BLOB(32K)) organize by row; + +--INSERT INTO sample_mpoints(id, geometry) +--VALUES +-- (10, ST_MPointFromText('multipoint(44 14, 35 16, 24 13)', 1)); + +--UPDATE sample_mpoints AS temp_correlated +--SET wkb = geometry..ST_AsBinary +--WHERE id = temp_correlated.id; + +--SELECT id, cast(ST_MPointFromWKB(wkb)..ST_AsText AS varchar(100)) AS MultiPoint +--FROM sample_mpoints +--WHERE id = 10; + +--=============================================================== +-- ST_MPolyFromText(WKT) +--=============================================================== +--DROP TABLE sample_mpolygons; +--CREATE TABLE sample_mpolygons (id SMALLINT, geometry ST_MULTIPOLYGON) organize by row; + +--INSERT INTO sample_mpolygons(id, geometry) +--VALUES +-- (1110, ST_MPolyFromText('multipolygon(((3 3, 4 6, 5 3, 3 3), +-- (8 24, 9 25, 1 28, 8 24), +-- (13 33, 7 36, 1 40, 10 43, 13 33)))', 1)); + +--SELECT id, cast(geometry..ST_AsText AS varchar(350)) AS MultiPolygon +--FROM sample_mpolygons +--WHERE id = 1110; + +--=============================================================== +-- ST_MPolyFromWKB(WKB) +--=============================================================== +--DROP TABLE sample_mpolygons; +--CREATE TABLE sample_mpolygons (id SMALLINT, geometry ST_MULTIPOLYGON, wkb BLOB(32K)) organize by row; + +--INSERT INTO sample_mpolygons(id, geometry) +--VALUES +-- (10, ST_MPolyFromText('multipolygon(((1 72, 4 79, 5 76, 1 72), +-- (10 20, 10 40, 30 41, 10 20), +-- (9 43, 7 44, 6 47, 9 43)))', 1)); + +--UPDATE sample_mpolygons AS temp_correlated +--SET wkb = geometry..ST_AsBinary +--WHERE id = temp_correlated.id; + +--SELECT id, cast(ST_MPolyFromWKB(wkb)..ST_AsText AS varchar(320)) AS MultiPolygon +--FROM sample_mpolygons +--WHERE id = 10; + +--=============================================================== +-- St_MultiLineString(LOB) +--=============================================================== +--DROP TABLE sample_mlines; +--CREATE TABLE sample_mlines (id SMALLINT, geometry ST_MULTILINESTRING) organize by row; + +--INSERT INTO sample_mlines(id, geometry) +--VALUES +-- (1110, ST_MultiLineString('multilinestring( +-- (33 2, 34 3, 35 6), +-- (28 4, 29 5, 31 8, 43 12), +-- (39 3, 37 4, 36 7))', 1) ); + +--SELECT id, cast(geometry..ST_AsText AS varchar(280)) AS MultiLineString +--FROM sample_mlines +--WHERE id = 1110; + +--=============================================================== +-- ST_MultiPoint(LOB) +--=============================================================== +--DROP TABLE sample_mpoints; +--CREATE TABLE sample_mpoints (id SMALLINT, geometry ST_MULTIPOINT) organize by row; + +--INSERT INTO sample_mpoints(id, geometry) +--VALUES +-- (1110, ST_MultiPoint('multipoint(1 2, 4 3, 5 6)', 1) ); + +--SELECT id, cast(geometry..ST_AsText AS varchar(90)) AS MultiPoint +--FROM sample_mpoints +--WHERE id = 1110; + +--=============================================================== +-- ST_MultiPolygon(LOB) +--=============================================================== +--DROP TABLE sample_mpolygons; +--CREATE TABLE sample_mpolygons (id SMALLINT, geometry ST_MULTIPOLYGON) organize by row; + +--INSERT INTO sample_mpolygons(id, geometry) +--VALUES +-- (1110, ST_MultiPolygon('multipolygon(((3 3, 4 6, 5 3, 3 3), +-- (8 24, 9 25, 1 28, 8 24), +-- (13 33, 7 36, 1 40, 10 43, 13 33)))', 1)); + +--SELECT id, cast(geometry..ST_AsText AS varchar(350)) AS MultiPolygon +--FROM sample_mpolygons +--WHERE id = 1110; + +--=============================================================== +-- ST_NumGeometries(collection) +--=============================================================== +--DROP TABLE sample_geometrycol; +--CREATE TABLE sample_geometrycol(id SMALLINT, geometry ST_GEOMCOLLECTION) organize by row; + +--INSERT INTO sample_geometrycol(id, geometry) +--VALUES +-- (1, ST_MultiPolygon('multipolygon(((3 3, 4 6, 5 3, 3 3), +-- (8 24, 9 25, 1 28, 8 24), +-- (13 33, 7 36, 1 40, 10 43, 13 33)))', 1)), +-- (2, ST_MultiPoint('multipoint(1 2, 4 3, 5 6, 7 6, 8 8)', 1) ); + +--SELECT id, ST_NumGeometries(geometry) AS number_of_geometries +--FROM sample_geometrycol; + +--=============================================================== +-- ST_NumLineStrings(ST_MultiLineStrings) +--=============================================================== +--DROP TABLE sample_mlines; +--CREATE TABLE sample_mlines (id SMALLINT, geometry ST_MULTILINESTRING) organize by row; + +--INSERT INTO sample_mlines(id, geometry) +--VALUES +-- (1110, ST_MultiLineString('multilinestring( +-- (33 2, 34 3, 35 6), +-- (28 4, 29 5, 31 8, 43 12), +-- (39 3, 37 4, 36 7))', 1) ), +-- (1111, ST_MultiLineString('multilinestring( +-- (3 2, 4 3, 5 6), +-- (8 4, 9 5, 3 8, 4 12))', 1)); + +--SELECT id, ST_NumLineStrings(geometry) AS number_of_linestrings +--FROM sample_mlines; + +--=============================================================== +-- ST_NumPoints(geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(spatial_type varchar(18), geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(spatial_type, geometry) +--VALUES +-- ('st_point', ST_Point(2, 3, 0) ), +-- ('st_linestring', ST_LineString('linestring(2 5, 21 3, 23 10)', 0) ), +-- ('st_polygon', ST_Polygon('polygon((110 120, 110 140, 120 130, 110 120))', 0) ); + +--SELECT spatial_type, geometry..ST_NumPoints AS number_of_points +--FROM sample_geometries; + +--=============================================================== +-- ST_NumPolygons(multipolygon) +--=============================================================== +--DROP TABLE sample_mpolygons; +--CREATE TABLE sample_mpolygons (id SMALLINT, geometry ST_MULTIPOLYGON); + +--INSERT INTO sample_mpolygons(id, geometry) +--VALUES +-- (1, ST_MultiPolygon('multipolygon(((3 3, 4 6, 5 3, 3 3), +-- (8 24, 9 25, 1 28, 8 24), +-- (13 33, 7 36, 1 40, 10 43, 13 33)))', 1)), +-- (2, ST_MultiPolygon('multipolygon empty', 1)), +-- (3, ST_MultiPolygon('multipolygon(((3 3, 4 6, 5 3, 3 3), +-- (13 33, 7 36, 1 40, 10 43, 13 33)))', 1)); + +--SELECT id, ST_NumPolygons(geometry) AS number_of_polygons +--FROM sample_mpolygons; + +--=============================================================== +-- ST_Overlaps(geometry, geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (1, ST_Point(10, 20, 1)), +-- (2, ST_Point('point(41 41)', 1)), +-- (10, ST_LineString('linestring (1 10, 3 12, 10 10)', 1) ), +-- (20, ST_LineString('linestring (50 10, 50 12, 45 10)', 1) ), +-- (30, ST_LineString('linestring (50 12, 50 10, 60 8)', 1) ), +-- (100, ST_Polygon('polygon((0 0, 0 40, 40 40, 40 0, 0 0))', 1) ), +-- (110, ST_Polygon('polygon((30 10, 30 30, 50 30, 50 10, 30 10))', 1) ), +-- (120, ST_Polygon('polygon((0 50, 0 60, 40 60, 40 60, 0 50))', 1) ); + + +----Tests weather Points Overlaps----Tests weather Points Overlaps +--SELECT sg1.id, sg2.id, +-- CASE ST_Overlaps(sg1.geometry, sg2.geometry) +-- WHEN 0 THEN 'Points_do_not_Overlap' +-- WHEN 1 THEN 'Points_Overlap' +-- END AS Overlap +--FROM sample_geometries sg1, sample_geometries sg2 +--WHERE sg1.id < 10 AND sg2.id < 10 AND sg1.id >= sg2.id; + +----Tests weather Lines Overlaps +--SELECT sg1.id, sg2.id, +-- CASE ST_Overlaps(sg1.geometry, sg2.geometry) +-- WHEN 0 THEN 'Lines_do_not_Overlap' +-- WHEN 1 THEN 'Lines_Overlap' +-- END AS Overlap +--FROM sample_geometries sg1, sample_geometries sg2 +--WHERE sg1.id >= 10 AND sg1.id < 100 AND sg2.id >= 10 AND sg2.id < 100 +-- AND sg1.id >= sg2.id; + +----Tests weather Polygons Overlaps +--SELECT sg1.id, sg2.id, +-- CASE ST_Overlaps(sg1.geometry, sg2.geometry) +-- WHEN 0 THEN 'Polygons_do_not_Overlap' +-- WHEN 1 THEN 'Polygons_Overlap' +-- END AS Overlap +--FROM sample_geometries sg1, sample_geometries sg2 +--WHERE sg1.id >= 100 AND sg2.id >=100 +-- AND sg1.id >= sg2.id; + +--=============================================================== +-- ST_Perimeter(surface) +--=============================================================== +--!db2se drop_srs se_bank -srsName new_york1983; + +--!db2se create_srs se_bank -srsId 4000 -srsName new_york1983 -xOffset 0 -yOffset 0 -xScale 1 -yScale 1 -coordsysName NAD_1983_StatePlane_New_York_East_FIPS_3101_Feet; + +--DROP TABLE sample_polygons; +--CREATE TABLE sample_polygons(id SMALLINT, geometry ST_POLYGON) organize by row; + +--INSERT INTO sample_polygons(id, geometry) +--VALUES +-- (1, ST_Polygon('polygon((0 0, 0 4, 5 4, 5 0, 0 0))', 4000)); + +--SELECT id, ST_Perimeter(geometry) AS perimeter +--FROM sample_polygons; + +---- Does the samething as above but uses method notation +--SELECT id, geometry..ST_Perimeter AS perimeter +--FROM sample_polygons; + +--SELECT id, ST_Perimeter(geometry, 'METER') AS perimeter_meter +--FROM sample_polygons; + +--=============================================================== +-- ST_PerpPoint(curve, point) +--=============================================================== +--This is not updated with Bill's fixes +--DROP TABLE sample_lines; +--CREATE TABLE sample_lines(id SMALLINT, line ST_LINESTRING) organize by row; + +--INSERT INTO sample_lines(id, line) +--VALUES +-- (1, ST_LineString('linestring z (0 10 1, 0 0 3, 10 0 5, 10 10 7)', 0) ); + +-- Perpendicular point is coincident with the input point, on the base of the U: +--SELECT ST_PerpPoint(line, ST_Point(5, 0, 0)) AS Perp_Point +--FROM sample_lines; + + +--=============================================================== +-- ST_Point(LOB) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (1100, ST_Point(10, 20, 1)), +-- (1101, ST_Point('point(30 40)', 1)); + +--SELECT id, cast(geometry..ST_AsText AS varchar(35)) AS Points +--FROM SAMPLE_POINTS; + +--=============================================================== +-- ST_PointFromText(WKT) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (1100, ST_PointFromText('point(30 40)', 1)); + +--SELECT id, cast(geometry..ST_AsText AS varchar(35)) AS points +--FROM sample_points; + +--=============================================================== +-- ST_PointFromWKB(WKB) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT, wkb BLOB(32k)) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (10, ST_PointFromText('point(44 14)', 1)), +-- (11, ST_PointFromText('point(24 13)', 1)); + +--UPDATE sample_points AS temp_correlated +--SET wkb = geometry..ST_AsBinary +--WHERE id = temp_correlated.id; + +--SELECT id, cast(geometry..ST_AsText AS varchar(35)) AS points +--FROM SAMPLE_POINTS; + +--=============================================================== +-- ST_PolyFromText(WKT) +--=============================================================== +--DROP TABLE sample_polygons; +--CREATE TABLE sample_polygons(id SMALLINT, geometry ST_POLYGON) organize by row; + +--INSERT INTO sample_polygons(id, geometry) +--VALUES +-- (1110, ST_Polygon('polygon((50 20, 50 40, 70 30, 50 20))', 0) ); + +--SELECT id, cast(geometry..ST_AsText AS varchar(120)) AS polygons +--FROM sample_polygons; + +--=============================================================== +-- ST_PolyFromWKB(WKB) +--=============================================================== +--DROP TABLE sample_polygons; +--CREATE TABLE sample_polygons (id SMALLINT, geometry ST_POLYGON, wkb BLOB(32K)) organize by row; + +--INSERT INTO sample_polygons(id, geometry) +--VALUES +-- (1115, ST_Polygon('polygon((50 20, 50 40, 70 30, 50 20))', 0) ); + +--UPDATE sample_polygons AS temp_correlated +--SET wkb = geometry..ST_AsBinary +--WHERE id = temp_correlated.id; + +--SELECT id, cast(ST_PolyFromWKB(wkb)..ST_AsText AS varchar(120)) AS Polygon +--FROM sample_polygons +--WHERE id = 1115; + +--=============================================================== +-- ST_Polgyon(LOB) +--=============================================================== +--DROP TABLE sample_polygons; +--CREATE TABLE sample_polygons (id SMALLINT, geometry ST_POLYGON) organize by row; + +--INSERT INTO sample_polygons(id, geometry) +--VALUES +-- (1100, ST_Polygon(db2gse.ST_LineFromText('linestring(10 20, 10 40, 20 30, 10 20)', 1), 1)), +-- (1101, ST_Polygon('polygon((110 120, 110 140, 120 130, 110 120))', 1) ), +-- (1102, ST_Polygon('polygon((110 120, 110 140, 130 140, 130 120, 110 120),(115 125, 115 135, 125 135, 125 135, 115 125))', 1) ); + +--SELECT id, cast(geometry..ST_AsText AS varchar(280)) AS Polygon +--FROM sample_polygons; + +--=============================================================== +-- ST_PolgyonN(geometry) +--=============================================================== +--DROP TABLE sample_mpolygons; +--CREATE TABLE sample_mpolygons (id SMALLINT, geometry ST_MULTIPOLYGON) organize by row; + +--INSERT INTO sample_mpolygons(id, geometry) +--VALUES +-- (1, ST_MPolyFromText('multipolygon(((3 3, 4 6, 5 3, 3 3), +-- (8 24, 9 25, 1 28, 8 24), +-- (13 33, 7 36, 1 40, 10 43, 13 33)))', 1)); + +--SELECT id, cast(geometry..ST_PolygonN(2)..ST_AsText AS varchar(120)) AS polygon_n +--FROM sample_mpolygons +--WHERE id = 1; + +--=============================================================== +-- ST_ToGeomColl(geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (1, ST_Polygon('polygon((3 3, 4 6, 5 3, 3 3))', 1)), +-- (2, ST_Point('point(1 2)', 1) ); + +--SELECT id, cast(geometry..ST_ToGeomColl..ST_AsText AS varchar(120)) AS geometry_collections +--FROM sample_geometries; + +--=============================================================== +-- ST_ToPoint(geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (1, ST_Geometry('point(30 40)', 1)), +-- (2, ST_Geometry('linestring empty', 1)), +-- (3, ST_Geometry('multipolygon empty', 1)); + +--SELECT cast(geometry..st_astext AS varchar(35)) AS points +--FROM sample_geometries; + +--SELECT cast(geometry..ST_ToPoint()..st_AsText() as varchar(35)) AS points +--FROM sample_geometries; + +--SELECT cast(TREAT(geometry AS ST_Point)..ST_AsText() as varchar(35)) AS points +--FROM sample_geometries; + +--=============================================================== +-- ST_ToLineString(geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (1, ST_Geometry('linestring z (0 10 1, 0 0 3, 10 0 5)', 0)), +-- (2, ST_Geometry('point empty', 1)), +-- (3, ST_Geometry('multipolygon empty', 1)); + + +--SELECT cast(geometry..ST_ToLineString()..st_AsText() as varchar(130)) AS lines +--FROM sample_geometries; + +--=============================================================== +-- ST_ToPolygon(geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (1, ST_Geometry('polygon((0 0, 0 4, 5 4, 5 0, 0 0))', 1)), +-- (2, ST_Geometry('point empty', 1)), +-- (3, ST_Geometry('multipolygon empty', 1)); + +--SELECT cast(geometry..ST_ToPolygon()..st_AsText() as varchar(130)) AS polygons +--FROM sample_geometries; + +--=============================================================== +-- ST_ToMultiPoint(geometry) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (1, ST_Geometry('multipoint(0 0, 0 4)', 1)); +-- (2, ST_Geometry('point(30 40)', 1)), +-- (3, ST_Geometry('multipolygon empty', 1)); + +--SELECT cast(geometry..ST_ToMultiPoint()..st_AsText() as varchar(100)) AS MultiPoint +--FROM sample_geometries; + +--=============================================================== +-- ST_Within(geometry) +--=============================================================== +--DROP TABLE sample_points; +--DROP TABLE sample_lines; +--DROP TABLE sample_polygons; + +--CREATE TABLE sample_points (id SMALLINT, geometry ST_POINT) organize by row; +--CREATE TABLE sample_lines(id SMALLINT, line ST_LINESTRING) organize by row; +--CREATE TABLE sample_polygons (id SMALLINT, geometry ST_POLYGON) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (1, ST_Point(10, 20, 1)), +-- (2, ST_Point('point(41 41)', 1)); +---- (2, ST_Point('point(50 50)', 1)); --Points to test defect + +--INSERT INTO sample_lines(id, line) +--VALUES +-- (10, ST_LineString('linestring (1 10, 3 12, 10 10)', 1) ), +-- (20, ST_LineString('linestring (50 10, 50 12, 45 10)', 1) ); + +--INSERT INTO sample_polygons(id, geometry) +--VALUES +-- (100, ST_Polygon('polygon((0 0, 0 40, 40 40, 40 0, 0 0))', 1) ); + +--SELECT pts.id AS point_ids_within_polygon +--FROM sample_points pts, sample_polygons poly +--WHERE ST_Within(poly.geometry, pts.geometry) = 0; + +--SELECT lin.id AS line_ids_within_polygon +--FROM sample_lines lin, sample_polygons poly +--WHERE ST_Within(poly.geometry, lin.geometry) = 0; + +--=============================================================== +-- ST_WKBToSQL(wkb) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id SMALLINT, geometry ST_GEOMETRY, wkb BLOB(32k)) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (10, ST_Point('point(44 14)', 0)), +-- (11, ST_Point('point(24 13)', 0)), +-- (12, ST_Polygon('polygon((50 20, 50 40, 70 30, 50 20))', 0) ); + +--UPDATE sample_geometries AS temp_correlated +--SET wkb = geometry..ST_AsBinary +--WHERE id = temp_correlated.id; + +--SELECT id, cast(ST_WKBToSQL(wkb)..ST_AsText AS varchar(120)) AS Geometries +--FROM sample_geometries; + +--=============================================================== +-- ST_WKTToSQL(wkt) +--=============================================================== +--DROP TABLE sample_geometries; +--CREATE TABLE sample_geometries(id SMALLINT, geometry ST_GEOMETRY) organize by row; + +--INSERT INTO sample_geometries(id, geometry) +--VALUES +-- (10, ST_WKTToSQL('point(44 14)')), +-- (11, ST_WKTToSQL('point(24 13)')), +-- (12, ST_WKTToSQL('polygon((50 20, 50 40, 70 30, 50 20))')); + +--SELECT id, cast(geometry..ST_AsText AS varchar(120)) AS Geometries +--FROM sample_geometries; + +--=============================================================== +-- ST_X(st_point) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (1, ST_Point(2, 3, 32, 5, 1)), +-- (2, ST_Point(4, 5, 20, 4, 1)), +-- (3, ST_Point(3, 8, 23, 7, 1)); + +--SELECT id, geometry..ST_X AS x_coordinate +--FROM sample_points; + +--SELECT id, cast(ST_AsText(ST_X(geometry, 40)) AS varchar(60)) AS x_40 +--FROM sample_points +--WHERE id = 3; + +--=============================================================== +-- ST_Y(st_point) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT) organize by row; + +--INSERT INTO sample_points (id, geometry) +--VALUES +-- (1, ST_Point(2, 3, 32, 5, 1)), +-- (2, ST_Point(4, 5, 20, 4, 1)), +-- (3, ST_Point(3, 8, 23, 7, 1)); + +--SELECT id, geometry..ST_Y AS y_coordinate +--FROM sample_points; + +--SELECT id, cast(ST_AsText(ST_Y(geometry, 40)) AS varchar(60)) AS y_40 +--FROM sample_points +--WHERE id = 3; + +--=============================================================== +-- ST_Z(st_point) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT) organize by row; + +--INSERT INTO SAMPLE_POINTS (id, geometry) +--VALUES +-- (1, ST_Point(2, 3, 32, 5, 1)), +-- (2, ST_Point(4, 5, 20, 4, 1)), +-- (3, ST_Point(3, 8, 23, 7, 1)); + +--SELECT id, geometry..ST_Z AS z_coordinate +--FROM sample_points; + +--SELECT id, cast(ST_AsText(ST_Z(geometry, 40)) AS varchar(60)) AS z_40 +--FROM sample_points +--WHERE id = 3; + +--=============================================================== +-- ST_GetAggrResult(MAX(ST_BuildUnionAggr(geometry) +--=============================================================== +--DROP TABLE sample_points; +--CREATE TABLE sample_points(id SMALLINT, geometry ST_POINT) organize by row; + +--INSERT INTO sample_points(id, geometry) +--VALUES +-- (1, ST_Point(2, 3, 1)), +-- (2, ST_Point(4, 5, 1)), +-- (3, ST_Point(13, 15, 1)), +-- (4, ST_Point(12, 5, 1)), +-- (5, ST_Point(23, 2, 1)), +-- (6, ST_Point(11, 4, 1)); + +--SELECT cast(ST_GetAggrResult(MAX(ST_BuildUnionAggr(geometry)))..ST_AsText AS varchar(160)) AS aggregate_of_points +--FROM sample_points; + +--SELECT cast(ST_GetAggrResult(MAX(ST_BuildUnionAggr(geometry)))..ST_ConvexHull..ST_AsText AS varchar(110)) AS aggregate_of_points +--FROM sample_points; + + + diff --git a/extenders/spatial/bank/seBankDemoTableData.db2 b/extenders/spatial/bank/seBankDemoTableData.db2 new file mode 100644 index 0000000..293b0a4 --- /dev/null +++ b/extenders/spatial/bank/seBankDemoTableData.db2 @@ -0,0 +1,1096 @@ +---------------------------------------------------------------------------- +-- Licensed Materials - Property of IBM +-- Governed under the terms of the IBM Public License +-- +-- (C) COPYRIGHT International Business Machines Corp. 2999 - 2010 +-- All Rights Reserved. +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +---------------------------------------------------------------------------- +-- +-- Product Name: DB2 Spatial Extender v10.0 +-- +-- Source File Name: seBankDemoTableData.db2 +-- +-- Version: 10.0.0 +-- +-- Description: +-- +-- +-- +-- For more information about the DB2 Spatial Extender Bank Demo scripts, +-- see the seBankDemoREADME.txt file. +-- +-- For more information about DB2 SE, see the "DB2 Spatial Extender User Guide". +-- +-- For the latest information on DB2 Spatial Extender and the Bank Demo +-- refer to the DB2 Spatial Extender website at +-- http://www.software.ibm.com/software/data/spatial/db2spatial +---------------------------------------------------------------------------- + +--========================================================================== +-- BRANCH DATA +--========================================================================== +INSERT INTO se_demo.branches( + BRANCH_ID, SE_ROW_ID, NAME, MANAGER, STREET, CITY, STATE, ZIP,LATITUDE,LONGITUDE) VALUES + (1, 1, 'Meridian', 'Francisco Villa', '1670 Meridian Ave', 'San Jose', 'CA','95125',37.31164,-121.91451), + (2, 2, 'San Carlos ','Stacey Nguyen', '580 San Carlos St', 'San Jose', 'CA','95112',37.33729,-121.87508); +-- end of BRANCH DATA + +--========================================================================== +-- CUSTOMER DATA +--========================================================================== +INSERT INTO se_demo.customers( + CUSTOMER_ID, SE_ROW_ID, NAME, STREET, CITY, STATE, ZIP,CUSTOMER_TYPE,LATITUDE,LONGITUDE) VALUES +( 124, 1,'James T.Kirk ',' 855 Garden Dr ',' San Jose ','CA','95126','NORMAL',37.33253, -121.93148), +( 125, 2,'Leonard McCoy ',' 815 Garden Dr ',' San Jose ','CA','95126','NORMAL',37.33187, -121.93069), +( 126, 3,'Hikaru Sulu ','1849 University Ave',' San Jose ','CA','95126','NORMAL',37.33126, -121.93243), +( 127, 4,'Michelle Nichols ','1649 University Way',' San Jose ','CA','95126','NORMAL',37.33333, -121.93044), +( 135, 5,'Montgomery Scott ','2024 University Ave',' San Jose ','CA','95128','NORMAL',37.33006, -121.93432), +( 136, 6,'Pavel Chekov ',' 725 Bascom Ave',' San Jose ','CA','95128','NORMAL',37.33013, -121.93367), +( 138, 8,'Deforest Kelly ',' 725 Garden Dr ',' San Jose ','CA','95126','NORMAL',37.33060, -121.92919), +( 139, 9,'Walter Koenig ','1779 Naglee Ave',' San Jose ','CA','95126','NORMAL',37.32925, -121.93012), +( 156, 10,'James Lenard ','2236 Central Park Dr ',' San Jose ','CA','95008','NORMAL',37.27586, -121.93877), +( 157, 11,'Leonard Nimoy ',' 805 Sweetbriar Dr ',' San Jose ','CA','95008','NORMAL',37.27553, -121.93867), +( 158, 12,'George Takei ',' 575 Cambrian Dr ',' San Jose ','CA','95008','NORMAL',37.27524, -121.93921), +( 159, 13,'Jean Luc Picard ',' 905 Sweetbriar Dr ',' San Jose ','CA','95008','NORMAL',37.27445, -121.93867), +( 160, 14,'Willian Riker ',' 515 Dallas Dr ',' San Jose ','CA','95008','NORMAL',37.27371, -121.94057), +( 176, 15,'Patrick Stewart ','1899 Cabana Dr ',' San Jose ','CA','95125','NORMAL',37.28738, -121.92073), +( 177, 16,'Jonathan Frakes ','2031 Hurst Ave',' San Jose ','CA','95125','NORMAL',37.28691, -121.91827), +( 178, 17,'Bervely Crusher ','2078 Hurst Ave',' San Jose ','CA','95125','NORMAL',37.28613, -121.91827), +( 179, 18,'Diana Troi ','1699 Cabana Dr ',' San Jose ','CA','95125','NORMAL',37.28770, -121.91677), +( 180, 19,'Whesley Crusher ','1974 Kocher Dr ',' San Jose ','CA','95125','NORMAL',37.28754, -121.91480), +( 262, 21,'James Cisko ','2435 Aragon Way',' San Jose ','CA','95125','NORMAL',37.27970, -121.90986), +( 263, 22,'Julian Bashir ','1690 Curtner Ave',' San Jose ','CA','95125','NORMAL',37.28147, -121.90946), +( 264, 23,'Jadzia Dax ','2349 La Mirada Dr ',' San Jose ','CA','95125','NORMAL',37.28128, -121.90878), +( 265, 24,'Katryn Janeway ','1749 Sweetbriar Dr ',' San Jose ','CA','95125','NORMAL',37.28202, -121.91039), +( 266, 25,'Bellana Torres ','2326 Briarwood Dr ',' San Jose ','CA','95125','NORMAL',37.28239, -121.90843), +( 267, 26,'Tom Parris ','1682 Curtner Ave',' San Jose ','CA','95125','NORMAL',37.28184, -121.90859), +( 368, 27,'Naomi Wilderman ','1933 Georgetta Dr ',' San Jose ','CA','95125','NORMAL',37.28537, -121.90861), +( 369, 28,'Zeffren Cockrane ','1874 Cherry Ave',' San Jose ','CA','95125','NORMAL',37.29144, -121.90176), +( 370, 29,'Jonh Sheridan ','1800 Nomark Ct ',' San Jose ','CA','95125','NORMAL',37.29228, -121.90326), +( 371, 30,'Michael Garibaldi','1974 Booksin Ave',' San Jose ','CA','95125','NORMAL',37.28708, -121.90645), +( 372, 31,'Ben Franklin ','1999 James Pl ',' San Jose ','CA','95125','NORMAL',37.28618, -121.90716), +( 373, 32,'Talia de Winters ','1832 Georgetta Dr ',' San Jose ','CA','95125','NORMAL',37.28630, -121.90652), +( 1007, 33,'Kosh Neranek ',' 399 Mayellen Ave',' San Jose ','CA','95126','NORMAL',37.32155, -121.92056), +( 1008, 34,'Zack Allan ',' 304 Buena Vista Ave',' San Jose ','CA','95126','NORMAL',37.32315, -121.91896), +( 1009, 35,'Lita Alexander ','1587 Scott St ',' San Jose ','CA','95126','NORMAL',37.31969, -121.92012), +( 1010, 36,'Susan Ivanova ',' 549 Mayellen Ave',' San Jose ','CA','95126','NORMAL',37.31893, -121.92056), +( 1011, 37,'Michael Bester ','1567 Scott St ',' San Jose ','CA','95126','NORMAL',37.31971, -121.91941), +( 1012, 38,'Fox Mulder ','1554 Scott St ',' San Jose ','CA','95126','NORMAL',37.31973, -121.91872), +( 1041, 39,'David Duchovny ',' 524 Julian St ',' San Jose ','CA','95110','NORMAL',37.33571, -121.90304), +( 1042, 40,'Danna Scully ',' 250 Autumn St ',' San Jose ','CA','95110','NORMAL',37.33560, -121.90212), +( 1043, 41,'David Skinner ',' 575 Santa Clara St ',' San Jose ','CA','95113','NORMAL',37.33196, -121.90182), +( 1044, 42,'Willian Boonne ',' 150 Autumn St ',' San Jose ','CA','95110','NORMAL',37.32836, -121.90033), +( 2127, 43,'Lilly Marquete ',' 849 Vine St ',' San Jose ','CA','95110','NORMAL',37.32102, -121.88525), +( 2128, 44,'James Sandoval ',' 224 West Virginia St ',' San Jose ','CA','95110','NORMAL',37.32189, -121.88520), +( 2129, 45,'Lian Kinkaid ',' 829 Almaden Ave',' San Jose ','CA','95110','NORMAL',37.32173, -121.88438), +( 2130, 46,'Samantha Carter ',' 149 West Virginia St ',' San Jose ','CA','95110','NORMAL',37.32258, -121.88397), +( 2131, 47,'Angela Cartwright',' 149 Sutter St ',' San Jose ','CA','95110','NORMAL',37.32194, -121.88341), +( 2132, 48,'June Lockhart ',' 274 Oak St ',' San Jose ','CA','95110','NORMAL',37.32008, -121.88525), +( 2154, 56,'Marcia Wallace ',' 500 Phelan Ave',' San Jose ','CA','95112','NORMAL',37.31710, -121.86046), +( 2155, 57,'Meggie Smith ','1718 Senter Rd ',' San Jose ','CA','95112','NORMAL',37.31816, -121.85821), +( 2156, 58,'Hank Azaria ',' 623 Nordale Ave',' San Jose ','CA','95112','NORMAL',37.31810, -121.85750), +( 2157, 59,'Paul Buchman ','1799 Welch Ave',' San Jose ','CA','95112','NORMAL',37.31771, -121.85643), +( 2158, 60,'Derek Whitestar ','1665 10th St ',' San Jose ','CA','95112','NORMAL',37.31624, -121.86285), +( 2159, 61,'Dorothy Lane ',' 375 Phelan Ave',' San Jose ','CA','95112','NORMAL',37.31526, -121.86319), +( 2160, 62,'Hemmet Brown ','1799 10th St ',' San Jose ','CA','95112','NORMAL',37.31422, -121.86088), +( 2161, 63,'Andrea Neal ','1803 Senter Rd ',' San Jose ','CA','95112','NORMAL',37.31710, -121.85720), +( 2162, 64,'James Oconor ',' 500 Needles Dr ',' San Jose ','CA','95112','NORMAL',37.31444, -121.85976), +( 2223, 49,'Billy Mummy ','1999 Senter Rd ',' San Jose ','CA','95112','NORMAL',37.31268, -121.85282), +( 2224, 50,'James Darren ',' 649 Palm St ',' San Jose ','CA','95110','NORMAL',37.32254, -121.88907), +( 2225, 51,'David Colbert ','1949 10th St ',' San Jose ','CA','95112','NORMAL',37.31275, -121.85934), +( 2226, 52,'Agnes Moghead ','1791 Monterey Hwy',' San Jose ','CA','95111','NORMAL',37.30961, -121.86740), +( 2227, 53,'Liz Montgomery ','1100 Algiers Ave',' San Jose ','CA','95122','NORMAL',37.32715, -121.84979), +( 2228, 54,'Dan Castanella ','1286 Clemence Ave',' San Jose ','CA','95122','NORMAL',37.32892, -121.85323), +( 2229, 55,'Nancy Cartwright ','1050 Walnut Woods Dr ',' San Jose ','CA','95122','NORMAL',37.32914, -121.85249), +( 3034, 65,'Idek Go ',' 350 7th St ',' San Jose ','CA','95112','NORMAL',37.33347, -121.88007), +( 3035, 66,'Kuai Chang Kaine ',' 225 Washington St ',' San Jose ','CA','95112','NORMAL',37.34497, -121.89078), +( 3036, 67,'Max Power ',' 350 6th St ',' San Jose ','CA','95112','NORMAL',37.34418, -121.88946), +( 3037, 68,'Homer Simpson ',' 375 Empire St ',' San Jose ','CA','95112','NORMAL',37.34856, -121.88916), +( 3038, 69,'Margie Simpson ',' 450 9th St ',' San Jose ','CA','95112','NORMAL',37.33337, -121.87709), +( 3039, 70,'Lisa Simpson ',' 425 Empire St ',' San Jose ','CA','95112','NORMAL',37.34904, -121.88811), +( 3084, 71,'Bart Simpson ',' 50 28th St ',' San Jose ','CA','95116','NORMAL',37.34791, -121.86358), +( 3085, 72,'Rafael Coss ','1337 Santa Clara St ',' San Jose ','CA','95116','NORMAL',37.34868, -121.86437), +( 3086, 73,'Bryan Patterson ',' 25 28th St ',' San Jose ','CA','95116','NORMAL',37.34835, -121.86390), +( 3087, 74,'Jean Ho ','1312 Santa Clara St ',' San Jose ','CA','95116','NORMAL',37.34856, -121.86464), +( 3088, 75,'Knut Stolze ','1329 Shortridge Ave',' San Jose ','CA','95116','NORMAL',37.34785, -121.86376), +( 4030, 76,'Claire Suttle ',' 949 Asbury St ',' San Jose ','CA','95126','NORMAL',37.33933, -121.91755), +( 4031, 77,'Andre Braga ',' 725 Elm St ',' San Jose ','CA','95126','NORMAL',37.33928, -121.91641), +( 4032, 78,'Tony Leung ','1074 Taylor St ',' San Jose ','CA','95126','NORMAL',37.33730, -121.91804), +( 4033, 79,'Cheung-Yuk ','1024 Taylor St ',' San Jose ','CA','95126','NORMAL',37.33779, -121.91734), +( 4034, 80,'Y. Morimoto ',' 650 Myrtle St ',' San Jose ','CA','95126','NORMAL',37.33755, -121.91671), +( 4035, 81,'Gery Mueckenbauer',' 849 Asbury St ',' San Jose ','CA','95126','NORMAL',37.34023, -121.91630), +( 4036, 82,'David Adler ',' 725 Laurel St ',' San Jose ','CA','95126','NORMAL',37.34017, -121.91515), +( 4037, 83,'Bob Shoberg ',' 849 Taylor St ',' San Jose ','CA','95126','NORMAL',37.33924, -121.91523), +( 4038, 84,'Laura Stewart ',' 949 Taylor St ',' San Jose ','CA','95126','NORMAL',37.33837, -121.91650), +( 4039, 85,'Soraia Alves ',' 650 Elm St ',' San Jose ','CA','95126','NORMAL',37.33842, -121.91548), +( 4097, 86,'Graziela Kunde ','1169 Vanessa Dr ',' San Jose ','CA','95126','NORMAL',37.30292, -121.91820), +( 4099, 88,'Nelson Mattos ','1824 Willow St ',' San Jose ','CA','95125','NORMAL',37.30075, -121.91869), +( 4100, 89,'Marilene Noronha ','1788 Isabel Dr ',' San Jose ','CA','95125','NORMAL',37.30080, -121.91825), +( 4101, 90,'Carla Nunes ','1416 Saint Francis Dr ',' San Jose ','CA','95125','NORMAL',37.30036, -121.91787), +( 4102, 91,'G.Sauaressig ','1699 Santa Barbara Dr ',' San Jose ','CA','95125','NORMAL',37.29984, -121.91567), +( 4430, 93,'Steven Elliott ','1258 Willowhaven Dr ',' San Jose ','CA','95126','NORMAL',37.30593, -121.91860), +( 4431, 94,'James Taylor ',' 942 St Elizabeth Dr ',' San Jose ','CA','95126','NORMAL',37.30721, -121.91648), +( 4432, 95,'Al Jarreau ','2323 Gunar Dr ',' San Jose ','CA','95124','NORMAL',37.27923, -121.92646), +( 4433, 96,'Diana Krall ',' 766 Malone Rd ',' San Jose ','CA','95125','NORMAL',37.29723, -121.88158), +( 4434, 97,'Gari Robinson ','2049 Delbarr Ct ',' San Jose ','CA','95125','NORMAL',37.29725, -121.88131), +( 4436, 99,'Angela Dima ',' 359 Shadow Run Dr ',' San Jose ','CA','95110','NORMAL',37.31034, -121.88066), +( 4437, 100,'Shannon Fargusson','1225 Willowhaven Dr ',' San Jose ','CA','95126','NORMAL',37.30593, -121.91802) +; +-- end of CUSTOMER DATA + +--========================================================================== +-- ACCOUNT DATA +--========================================================================== +INSERT INTO se_demo.accounts( + ACCOUNT_ID, CUSTOMER_ID, BRANCH_ID, TYPE, BALANCE, ROUTING_NUMBER) VALUES +( 100, 124,1,'Checking', 2363.255132,1100), +( 101, 125,2,'Checking', 2885.789723,1101), +( 102, 126,1,'Checking', 863.7858514,1102), +( 103, 127,1,'Checking', 376.3056556,1103), +( 104, 135,1,'Checking', 1335.755385,1104), +( 105, 136,1,'Checking', 1522.425684,1105), +( 107, 138,1,'Checking', 1285.902569,1107), +( 108, 139,1,'Checking', 3260.161556,1108), +( 109, 156,1,'Checking', 2919.795841,1109), +( 110, 157,1,'Checking', 1073.549577,1110), +( 111, 158,1,'Checking', 1225.286351,1111), +( 112, 159,1,'Checking', 389.7738339,1112), +( 113, 160,1,'Checking', 182.9277962,1113), +( 114, 176,2,'Checking', 812.2161706,1114), +( 115, 177,1,'Checking', 2329.205387,1115), +( 116, 178,2,'Checking', 332.32188,1116), +( 117, 179,2,'Checking', 2718.337876,1117), +( 118, 180,1,'Checking', 1188.955105,1118), +( 120, 262,1,'Checking', 2427.166818,1120), +( 121, 263,1,'Checking', 1933.819423,1121), +( 122, 264,1,'Checking', 549.3841173,1122), +( 123, 265,1,'Checking', 2429.47217,1123), +( 124, 266,1,'Checking', 1940.300551,1124), +( 125, 267,1,'Checking', 1683.467949,1125), +( 126, 368,1,'Checking', 1206.174575,1126), +( 127, 369,1,'Checking', 768.6893814,1127), +( 128, 370,2,'Checking', 1129.363835,1128), +( 129, 371,1,'Checking', 1418.82726,1129), +( 130, 372,1,'Checking', 1674.021154,1130), +( 131, 373,1,'Checking', 2477.973427,1131), +( 132,1007,1,'Checking', 370.7056947,1132), +( 133,1008,1,'Checking', 116.1817531,1133), +( 134,1009,1,'Checking', 520.6105051,1134), +( 135,1010,1,'Checking', 195.6016937,1135), +( 136,1011,1,'Checking', 106.0564091,1136), +( 138,1041,1,'Checking', 539.2325158,1138), +( 139,1042,1,'Checking', 101.1402553,1139), +( 140,1043,1,'Checking', 950.7055043,1140), +( 141,1044,1,'Checking', 575.4253339,1141), +( 142,2127,1,'Checking', 345.6576006,1142), +( 143,2128,2,'Checking', 235.6670355,1143), +( 144,2129,2,'Checking', 345.3365138,1144), +( 145,2130,2,'Checking', 137.687037,1145), +( 146,2131,1,'Checking', 100.7461097,1146), +( 147,2132,1,'Checking', 686.8912253,1147), +( 148,2223,2,'Checking', 57.94033953,1148), +( 149,2224,2,'Checking', 209.6814143,1149), +( 150,2225,2,'Checking', 272.993464,1150), +( 151,2226,1,'Checking', 273.1754423,1151), +( 152,2227,2,'Checking', 155.3547925,1152), +( 153,2228,1,'Checking', 269.5428597,1153), +( 154,2229,1,'Checking', 151.1208164,1154), +( 155,2154,2,'Checking', 8.275955916,1155), +( 156,2155,2,'Checking', 227.8439034,1156), +( 157,2156,2,'Checking', 351.6053223,1157), +( 158,2157,2,'Checking', 175.8251799,1158), +( 159,2158,2,'Checking', 636.3168721,1159), +( 160,2159,2,'Checking', 808.5135018,1160), +( 161,2160,2,'Checking', 322.3511567,1161), +( 162,2161,1,'Checking', 113.6516125,1162), +( 163,2162,2,'Checking', 634.4714832,1163), +( 164,3034,2,'Checking', 803.0728587,1164), +( 165,3035,2,'Checking', 1374.49218,1165), +( 166,3036,2,'Checking', 737.7980341,1166), +( 167,3037,1,'Checking', 880.1150966,1167), +( 168,3038,2,'Checking', 1714.550973,1168), +( 169,3039,1,'Checking', 1296.540013,1169), +( 170,3084,2,'Checking', 935.6609093,1170), +( 171,3085,2,'Checking', 534.2058106,1171), +( 172,3086,2,'Checking', 416.365382,1172), +( 173,3087,2,'Checking', 1222.481322,1173), +( 174,3088,2,'Checking', 1234.423716,1174), +( 175,4030,1,'Checking', 342.3687716,1175), +( 176,4031,1,'Checking', 219.8221082,1176), +( 177,4032,1,'Checking', 821.8153705,1177), +( 178,4033,1,'Checking', 333.0223163,1178), +( 179,4034,1,'Checking', 78.67911241,1179), +( 180,4035,1,'Checking', 692.0828828,1180), +( 181,4036,1,'Checking', 1465.075807,1181), +( 182,4037,1,'Checking', 1823.983833,1182), +( 183,4038,1,'Checking', 733.0881632,1183), +( 184,4039,1,'Checking', 1100.820315,1184), +( 185,4097,1,'Checking', 38.94935605,1185), +( 186,4099,1,'Checking', 150.0550955,1186), +( 187,4100,1,'Checking', 159.8017401,1187), +( 188,4101,1,'Checking', 363.2827794,1188), +( 189,4102,1,'Checking', 1242.323194,1189), +( 191,4430,1,'Checking', 240.9412472,1191), +( 192,4431,1,'Checking', 393.6994475,1192), +( 193,4432,1,'Checking', 873.6447408,1193), +( 194,4433,1,'Checking', 849.881861,1194), +( 195,4434,1,'Checking', 920.8499389,1195), +( 197,4436,1,'Checking', 769.2452027,1197), +( 198,4437,1,'Checking', 203.4685531,1198), +( 199, 124,1,'Saving', 25947.23173,1199), +( 200, 125,2,'Saving', 204755.0108,1200), +( 201, 126,1,'Saving', 114390.855,1201), +( 202, 127,1,'Saving', 202659.7704,1202), +( 203, 135,1,'Saving', 105370.5459,1203), +( 204, 136,1,'Saving', 16331.64918,1204), +( 206, 138,1,'Saving', 77485.47104,1206), +( 207, 139,1,'Saving', 101003.4193,1207), +( 208, 156,1,'Saving', 30627.54354,1208), +( 209, 157,1,'Saving', 84310.68934,1209), +( 210, 158,1,'Saving', 95724.16915,1210), +( 211, 159,1,'Saving', 58738.6481,1211), +( 212, 160,1,'Saving', 33947.76889,1212), +( 213, 176,2,'Saving', 50009.22738,1213), +( 214, 177,1,'Saving', 53839.09653,1214), +( 215, 178,2,'Saving', 37252.65724,1215), +( 216, 179,2,'Saving', 38832.03591,1216), +( 217, 180,1,'Saving', 157923.6088,1217), +( 219, 262,1,'Saving', 161690.7533,1219), +( 220, 263,1,'Saving', 60963.05602,1220), +( 221, 264,1,'Saving', 129716.7982,1221), +( 222, 265,1,'Saving', 146258.3654,1222), +( 223, 266,1,'Saving', 189802.0553,1223), +( 224, 267,1,'Saving', 224976.7577,1224), +( 225, 368,1,'Saving', 39103.89544,1225), +( 226, 369,1,'Saving', 46182.78934,1226), +( 227, 370,2,'Saving', 45155.12824,1227), +( 228, 371,1,'Saving', 118843.0557,1228), +( 229, 372,1,'Saving', 146979.6841,1229), +( 230, 373,1,'Saving', 79742.70174,1230), +( 231,1007,1,'Saving', 18766.24436,1231), +( 232,1008,1,'Saving', 56978.37152,1232), +( 233,1009,1,'Saving', 39892.98345,1233), +( 234,1010,1,'Saving', 14340.12927,1234), +( 235,1011,1,'Saving', 24524.27683,1235), +( 236,1012,2,'Saving', 30944.41188,1236), +( 237,1041,1,'Saving', 39186.16525,1237), +( 238,1042,1,'Saving', 17185.41623,1238), +( 239,1043,1,'Saving', 59682.25556,1239), +( 240,1044,1,'Saving', 7648.203145,1240), +( 241,2127,1,'Saving', 13560.58125,1241), +( 242,2128,2,'Saving', 14369.43733,1242), +( 243,2129,2,'Saving', 36340.46654,1243), +( 244,2130,2,'Saving', 14979.87798,1244), +( 245,2131,1,'Saving', 14515.74201,1245), +( 246,2132,1,'Saving', 305.3633823,1246), +( 247,2223,2,'Saving', 12417.23338,1247), +( 248,2224,2,'Saving', 39457.64595,1248), +( 249,2225,2,'Saving', 23017.44714,1249), +( 250,2226,1,'Saving', 7742.484165,1250), +( 251,2227,2,'Saving', 17624.66363,1251), +( 252,2228,1,'Saving', 1535.394306,1252), +( 253,2229,1,'Saving', 1226.676885,1253), +( 254,2154,2,'Saving', 22547.57602,1254), +( 255,2155,2,'Saving', 12486.17339,1255), +( 256,2156,2,'Saving', 38364.90976,1256), +( 257,2157,2,'Saving', 1734.126161,1257), +( 258,2158,2,'Saving', 60251.94392,1258), +( 259,2159,2,'Saving', 46657.42166,1259), +( 260,2160,2,'Saving', 9505.175495,1260), +( 261,2161,1,'Saving', 32381.25655,1261), +( 262,2162,2,'Saving', 34863.35359,1262), +( 263,3034,2,'Saving', 48563.18138,1263), +( 264,3035,2,'Saving', 48493.01592,1264), +( 265,3036,2,'Saving', 173101.6616,1265), +( 266,3037,1,'Saving', 88026.78844,1266), +( 267,3038,2,'Saving', 143707.0279,1267), +( 268,3039,1,'Saving', 99494.98056,1268), +( 269,3084,2,'Saving', 88987.75075,1269), +( 270,3085,2,'Saving', 25567.8175,1270), +( 271,3086,2,'Saving', 112184.2155,1271), +( 272,3087,2,'Saving', 168562.1903,1272), +( 273,3088,2,'Saving', 185847.5828,1273), +( 274,4030,1,'Saving', 44559.8743,1274), +( 275,4031,1,'Saving', 26054.6617,1275), +( 276,4032,1,'Saving', 58280.98421,1276), +( 277,4033,1,'Saving', 33446.0035,1277), +( 278,4034,1,'Saving', 88012.34913,1278), +( 279,4035,1,'Saving', 84526.49687,1279), +( 280,4036,1,'Saving', 78822.73393,1280), +( 281,4037,1,'Saving', 10788.06735,1281), +( 282,4038,1,'Saving', 101492.5752,1282), +( 283,4039,1,'Saving', 21233.41511,1283), +( 284,4097,1,'Saving', 77413.15157,1284), +( 285,4099,1,'Saving', 84883.84174,1285), +( 286,4100,1,'Saving', 69186.40003,1286), +( 287,4101,1,'Saving', 28291.18589,1287), +( 288,4102,1,'Saving', 21900.57646,1288), +( 290,4430,1,'Saving', 22028.39868,1290), +( 291,4431,1,'Saving', 69694.60985,1291), +( 292,4432,1,'Saving', 70770.24328,1292), +( 293,4433,1,'Saving', 52412.67197,1293), +( 294,4434,1,'Saving', 61382.88758,1294), +( 296,4436,1,'Saving', 46565.86445,1296), +( 297,4437,1,'Saving', 78073.61351,1297); +-- end of ACCOUNT DATA + +--========================================================================== +-- TRANSACTION DATA +--========================================================================== +INSERT INTO se_demo.transactions( + TRANSACTION_ID, TRANSACTION_DATE, ACCOUNT_ID, AMOUNT) VALUES +( 200,'6/9/1999', 100,410.0649), +( 203,'3/16/1999', 101,134.6683), +( 206,'5/8/2000', 102,128.8427), +( 209,'2/14/1999', 103,55.29605), +( 212,'5/24/2000', 104, 246.328), +( 215,'1/20/2000', 105,217.8844), +( 221,'6/15/2000', 107,249.6642), +( 224,'6/2/1999', 108,120.8983), +( 227,'2/27/1999', 109,116.1058), +( 230,'2/6/1999', 110,187.5347), +( 233,'6/23/2000', 111,48.13646), +( 236,'5/27/1999', 112,26.88456), +( 239,'4/4/1999', 113,7.963927), +( 242,'12/14/1999', 114,6.796708), +( 245,'6/17/2000', 115,59.15062), +( 248,'1/20/2000', 116,16.10502), +( 251,'10/3/1999', 117,513.2409), +( 254,'10/4/1999', 118,136.2889), +( 260,'6/28/2000', 120,421.2396), +( 263,'5/10/1999', 121,186.4202), +( 266,'5/23/2000', 122,102.4402), +( 269,'12/19/1999', 123, 248.581), +( 272,'7/22/1999', 124, 226.448), +( 275,'11/2/2000', 125,48.19283), +( 278,'8/20/1999', 126, 228.173), +( 281,'10/3/1999', 127,68.18768), +( 284,'1/3/1999', 128,31.63948), +( 287,'6/22/1999', 129,256.2542), +( 290,'11/28/1999', 130,19.16289), +( 293,'11/16/2000', 131,162.1792), +( 296,'7/26/1999', 132,3.779025), +( 299,'2/17/1999', 133,18.46187), +( 302,'4/24/2000', 134,25.31652), +( 305,'1/1/2000', 135,4.483854), +( 308,'7/2/2000', 136,18.33536), +( 314,'10/17/1999', 138,21.03512), +( 317,'1/21/1999', 139,15.50602), +( 320,'7/20/1999', 140, 114.246), +( 323,'11/8/2000', 141,16.60923), +( 326,'8/24/1999', 142,40.86036), +( 329,'5/22/1999', 143,44.24424), +( 332,'4/1/1999', 144,14.28121), +( 335,'11/6/2000', 145,25.39269), +( 338,'11/28/2000', 146,6.341318), +( 341,'1/10/2000', 147,7.487512), +( 344,'9/12/1999', 148,5.611813), +( 347,'2/1/1999', 149,11.63708), +( 350,'4/13/1999', 150,26.33636), +( 353,'1/19/1999', 151, 26.9734), +( 356,'9/18/1999', 152, 26.3779), +( 359,'10/26/1999', 153,44.01659), +( 362,'2/20/1999', 154,3.055476), +( 365,'6/4/2000', 155,0.088982), +( 368,'11/27/2000', 156,8.333825), +( 371,'5/6/2000', 157,22.51631), +( 374,'3/21/1999', 158,29.04578), +( 377,'1/23/2000', 159,26.38774), +( 380,'10/18/1999', 160,92.33102), +( 383,'12/24/1999', 161,59.83667), +( 386,'2/8/1999', 162,8.266304), +( 389,'3/17/2000', 163,101.5791), +( 392,'11/5/2000', 164,150.8449), +( 395,'9/25/1999', 165,228.3387), +( 398,'7/24/2000', 166,121.3898), +( 401,'4/16/1999', 167,78.65684), +( 404,'7/19/2000', 168,266.9651), +( 407,'2/7/2000', 169,34.14283), +( 410,'2/4/1999', 170,62.29798), +( 413,'4/11/2000', 171,75.89482), +( 416,'8/5/2000', 172,48.03834), +( 419,'2/11/1999', 173,176.7392), +( 422,'3/15/2000', 174,129.5668), +( 425,'12/6/1999', 175,23.25297), +( 428,'8/20/2000', 176,14.07896), +( 431,'7/12/2000', 177,39.66607), +( 434,'5/9/1999', 178, 22.162), +( 437,'12/9/2000', 179,0.869688), +( 440,'9/12/1999', 180,138.2647), +( 446,'7/24/1999', 182,225.1657), +( 449,'5/7/2000', 183,12.54472), +( 452,'2/18/1999', 184,110.9305), +( 455,'5/12/2000', 185,4.345138), +( 458,'8/27/1999', 186,8.993184), +( 461,'6/16/2000', 187, 6.36054), +( 464,'5/25/2000', 188,52.51078), +( 467,'7/22/2000', 189,25.45362), +( 473,'11/2/2000', 191,40.43505), +( 476,'8/20/1999', 192,5.576618), +( 479,'11/13/1999', 193,133.9944), +( 482,'9/20/2000', 194,109.4392), +( 485,'7/4/2000', 195,84.65599), +( 491,'2/6/1999', 197,16.62518), +( 494,'8/9/2000', 198, 19.734), +( 497,'7/1/1999', 199,4172.654), +( 500,'5/14/1999', 200,38353.48), +( 503,'4/12/1999', 201,6068.544), +( 506,'4/16/1999', 202,11277.34), +( 509,'12/12/1999', 203,15628.58), +( 512,'5/23/2000', 204,1544.129), +( 518,'1/24/2000', 206, 134.573), +( 521,'12/25/1999', 207,9989.299), +( 524,'3/10/2000', 208,4443.906), +( 527,'4/2/1999', 209,1784.336), +( 530,'2/20/1999', 210, 8814.86), +( 533,'4/3/2000', 211,1133.963), +( 536,'12/4/2000', 212,1321.064), +( 539,'12/2/1999', 213,1134.468), +( 542,'9/11/2000', 214,1791.388), +( 545,'5/22/2000', 215,611.6733), +( 548,'3/1/2000', 216,3846.393), +( 551,'1/14/1999', 217,5136.206), +( 557,'4/14/1999', 219,1806.315), +( 560,'11/27/2000', 220,9556.921), +( 563,'9/7/2000', 221,5052.018), +( 566,'8/24/2000', 222,19897.25), +( 569,'8/10/1999', 223,20643.46), +( 572,'5/19/1999', 224,1010.197), +( 575,'7/26/1999', 225,5505.485), +( 578,'2/4/2000', 226,7053.833), +( 581,'9/14/1999', 227,3386.158), +( 584,'7/24/1999', 228,13494.65), +( 587,'12/21/1999', 229,2740.613), +( 590,'4/25/1999', 230, 13284.4), +( 593,'3/24/1999', 231,2445.456), +( 596,'9/23/1999', 232,1760.232), +( 599,'12/5/2000', 233,1687.219), +( 602,'7/11/2000', 234,115.0738), +( 605,'2/8/2000', 235,1271.798), +( 608,'11/20/1999', 236,4541.155), +( 611,'4/15/1999', 237, 3677.7), +( 614,'1/17/1999', 238,2795.182), +( 617,'5/17/2000', 239,774.5752), +( 620,'4/20/2000', 240,782.5478), +( 623,'2/18/1999', 241,1436.765), +( 626,'1/1/2000', 242,2771.544), +( 629,'11/19/1999', 243,3420.935), +( 632,'1/7/2000', 244,2231.038), +( 635,'9/9/1999', 245,2025.772), +( 638,'10/25/2000', 246,9.387454), +( 641,'12/18/2000', 247,1969.252), +( 644,'3/15/1999', 248,6195.007), +( 647,'10/1/2000', 249,4103.657), +( 650,'11/9/1999', 250,1359.439), +( 653,'4/17/1999', 251,530.9645), +( 656,'5/28/2000', 252,171.7705), +( 659,'3/25/2000', 253,190.8625), +( 662,'1/22/2000', 254,2765.804), +( 665,'10/7/2000', 255, 1720.33), +( 668,'2/11/1999', 256,6441.007), +( 671,'6/23/1999', 257,121.6101), +( 674,'7/24/1999', 258,9957.765), +( 677,'10/5/1999', 259,6853.639), +( 680,'4/28/1999', 260,726.6378), +( 683,'11/9/2000', 261, 769.309), +( 686,'2/7/1999', 262,5860.827), +( 689,'5/5/2000', 263,1754.494), +( 692,'3/17/2000', 264,2713.556), +( 695,'12/19/1999', 265,417.2778), +( 698,'7/20/1999', 266, 10273.4), +( 701,'8/11/1999', 267,4018.836), +( 704,'8/24/2000', 268,9078.658), +( 707,'3/21/2000', 269,16283.33), +( 710,'12/8/1999', 270, 3269.45), +( 713,'6/14/1999', 271,10040.68), +( 716,'11/24/2000', 272,6451.387), +( 719,'11/17/1999', 273,22634.37), +( 722,'12/22/2000', 274,6310.148), +( 725,'5/17/1999', 275,5195.875), +( 728,'12/22/1999', 276, 9716.49), +( 731,'11/21/2000', 277,6015.548), +( 734,'9/8/2000', 278,2858.153), +( 737,'12/21/1999', 279,14701.36), +( 740,'4/17/1999', 280,13436.15), +( 743,'12/4/2000', 281,1437.694), +( 746,'9/2/2000', 282,5929.765), +( 749,'9/28/2000', 283,851.2012), +( 752,'10/18/1999', 284,11199.08), +( 755,'7/6/2000', 285,867.0179), +( 758,'12/3/2000', 286,10766.49), +( 761,'9/4/2000', 287,4060.866), +( 764,'11/10/1999', 288,2868.957), +( 770,'6/13/1999', 290,3921.282), +( 773,'6/6/1999', 291,5691.669), +( 776,'10/22/2000', 292,5842.467), +( 779,'8/8/2000', 293,995.6348), +( 782,'10/19/1999', 294,164.2341), +( 788,'10/6/1999', 296,3120.884), +( 791,'5/24/2000', 297,4215.467), +( 794,'10/16/1999', 100,265.6453), +( 797,'8/19/1999', 101,539.0321), +( 800,'11/13/1999', 102,78.76525), +( 803,'11/9/2000', 103,68.03113), +( 806,'11/21/1999', 104,200.9549), +( 809,'3/24/1999', 105,215.4605), +( 815,'5/2/1999', 107,66.71727), +( 818,'6/9/2000', 108,623.4824), +( 821,'5/6/1999', 109,109.9385), +( 824,'6/24/2000', 110,32.86801), +( 827,'8/26/2000', 111,151.9085), +( 830,'1/26/2000', 112,11.68539), +( 833,'4/19/1999', 113,13.75836), +( 836,'10/6/2000', 114,80.53244), +( 839,'6/26/1999', 115, 20.9271), +( 842,'4/1/2000', 116,26.76104), +( 845,'1/16/2000', 117,278.6843), +( 848,'12/19/1999', 118,109.5831), +( 854,'9/8/2000', 120,161.5764), +( 857,'4/20/1999', 121,49.81852), +( 860,'11/7/1999', 122, 26.4448), +( 863,'10/27/2000', 123, 436.118), +( 866,'4/11/2000', 124,46.06044), +( 869,'4/23/2000', 125,305.0076), +( 872,'10/9/1999', 126,232.3231), +( 875,'8/2/1999', 127, 61.2963), +( 878,'3/14/2000', 128,205.2637), +( 881,'9/19/2000', 129,34.73888), +( 884,'1/14/2000', 130,170.3945), +( 887,'1/19/1999', 131,241.7908), +( 890,'1/9/2000', 132,50.60082), +( 893,'11/14/1999', 133,22.68992), +( 896,'2/6/2000', 134, 26.9585), +( 899,'8/7/1999', 135,38.72871), +( 902,'6/26/1999', 136,18.99279), +( 908,'5/1/1999', 138,95.14236), +( 911,'10/4/2000', 139,6.336616), +( 914,'11/9/2000', 140,138.0959), +( 917,'2/26/2000', 141,2.088899), +( 920,'6/12/2000', 142,32.59317), +( 923,'2/5/1999', 143, 22.6203), +( 926,'4/11/1999', 144, 35.478), +( 929,'6/21/2000', 145,27.32847), +( 932,'7/19/1999', 146,14.01379), +( 935,'1/11/1999', 147,98.60913), +( 938,'10/1/2000', 148,7.594179), +( 941,'4/17/1999', 149,14.74927), +( 944,'9/14/1999', 150,17.64516), +( 947,'10/21/2000', 151,8.414119), +( 950,'2/3/2000', 152,21.81273), +( 953,'5/24/2000', 153,45.43275), +( 956,'3/28/2000', 154,2.890876), +( 959,'5/27/1999', 155,0.941372), +( 962,'1/8/1999', 156,36.43327), +( 965,'4/19/2000', 157,22.75757), +( 968,'4/23/1999', 158, 18.3028), +( 971,'6/8/1999', 159,111.2169), +( 974,'8/25/2000', 160,144.8827), +( 977,'12/3/2000', 161,41.74191), +( 980,'12/3/2000', 162,20.86361), +( 983,'8/10/2000', 163,84.66857), +( 986,'2/9/2000', 164, 23.4569), +( 989,'10/21/1999', 165,141.7547), +( 992,'7/23/1999', 166,77.80529), +( 995,'12/24/2000', 167,111.2804), +( 998,'10/26/1999', 168,333.6068), +(1001,'2/6/2000', 169,197.2564), +(1004,'6/15/1999', 170,14.14601), +(1007,'9/16/1999', 171,65.91726), +(1010,'1/10/1999', 172,35.38287), +(1013,'3/19/1999', 173,41.68522), +(1016,'2/5/1999', 174,157.0025), +(1019,'7/28/2000', 175,49.59643), +(1022,'1/13/2000', 176,30.31786), +(1025,'1/17/2000', 177,126.8564), +(1028,'6/22/2000', 178,7.913088), +(1031,'4/16/2000', 179,0.261574), +(1034,'10/23/1999', 180,64.25004), +(1040,'10/7/2000', 182,29.98905), +(1043,'8/1/2000', 183,83.81477), +(1046,'4/9/1999', 184,96.80246), +(1049,'9/23/1999', 185,2.654964), +(1052,'2/8/2000', 186,12.90884), +(1055,'3/22/2000', 187,18.68655), +(1058,'2/19/1999', 188,25.10699), +(1061,'4/12/1999', 189,230.6099), +(1067,'2/17/1999', 191,25.50788), +(1070,'10/15/2000', 192,66.20551), +(1073,'8/16/1999', 193,145.7211), +(1076,'9/6/1999', 194,129.9411), +(1079,'6/20/2000', 195,5.229966), +(1085,'7/22/1999', 197,110.2286), +(1088,'12/8/2000', 198,27.85117), +(1091,'1/22/1999', 199,4147.848), +(1094,'2/2/1999', 200,40630.21), +(1097,'3/26/2000', 201,6341.582), +(1100,'5/27/2000', 202,19718.14), +(1103,'1/7/2000', 203,20412.81), +(1106,'11/27/2000', 204,98.19314), +(1112,'1/11/1999', 206,9746.122), +(1115,'2/28/2000', 207,12884.93), +(1118,'6/21/1999', 208,3053.719), +(1121,'8/1/2000', 209,3781.076), +(1124,'11/22/2000', 210,8038.879), +(1127,'9/16/2000', 211, 354.355), +(1130,'12/19/2000', 212,3048.593), +(1133,'6/4/2000', 213,9616.066), +(1136,'8/1/2000', 214, 4383.46), +(1139,'9/18/2000', 215,1728.502), +(1142,'9/18/1999', 216,5088.025), +(1145,'8/23/1999', 217,8403.177), +(1151,'11/14/1999', 219, 7516.24), +(1154,'2/14/2000', 220,10618.38), +(1157,'3/7/1999', 221,4955.935), +(1160,'4/18/1999', 222,8996.822), +(1163,'1/4/1999', 223,31032.86), +(1166,'2/5/2000', 224,42096.04), +(1169,'5/12/1999', 225,3026.361), +(1172,'10/20/2000', 226,5415.512), +(1175,'2/6/2000', 227,3518.782), +(1178,'7/11/1999', 228,18853.91), +(1181,'8/26/2000', 229,14540.79), +(1184,'2/12/2000', 230,3190.184), +(1187,'12/25/1999', 231,2644.192), +(1190,'4/22/1999', 232,2037.797), +(1193,'9/11/2000', 233,3369.338), +(1196,'7/2/1999', 234,1695.653), +(1199,'10/3/2000', 235,3178.529), +(1202,'2/5/1999', 236,3617.337), +(1205,'11/12/1999', 237,3787.433), +(1208,'7/20/1999', 238,1108.258), +(1211,'2/13/2000', 239,10837.12), +(1214,'8/19/1999', 240,1089.209), +(1217,'10/16/1999', 241,1176.584), +(1220,'7/21/1999', 242,2316.119), +(1223,'11/17/1999', 243,991.6162), +(1226,'11/3/2000', 244, 393.124), +(1229,'5/8/2000', 245,2604.353), +(1232,'8/16/1999', 246,25.90977), +(1235,'12/2/1999', 247,1787.568), +(1238,'9/1/2000', 248, 2377.79), +(1241,'4/2/1999', 249,1698.527), +(1244,'8/23/2000', 250,1267.302), +(1247,'6/20/2000', 251,2808.839), +(1250,'1/3/1999', 252,20.07844), +(1253,'10/5/2000', 253,88.35182), +(1256,'9/8/1999', 254,69.99725), +(1259,'11/25/2000', 255,1633.452), +(1262,'12/5/2000', 256,1299.553), +(1265,'9/20/2000', 257,197.3139), +(1268,'9/22/2000', 258,6281.389), +(1271,'4/23/2000', 259,4748.887), +(1274,'11/15/1999', 260,414.1412), +(1277,'10/4/2000', 261,4661.834), +(1280,'10/4/1999', 262,4974.991), +(1283,'6/6/2000', 263,4678.143), +(1286,'1/22/2000', 264,5313.296), +(1289,'3/19/1999', 265,19422.03), +(1292,'9/26/1999', 266,14053.36), +(1295,'10/7/2000', 267,21816.82), +(1298,'3/11/2000', 268, 1338.64), +(1301,'12/25/1999', 269,15786.09), +(1304,'8/4/2000', 270,1279.132), +(1307,'3/12/2000', 271,19843.18), +(1310,'3/17/1999', 272,30949.97), +(1313,'11/27/1999', 273,17072.19), +(1316,'8/13/1999', 274,509.6888), +(1319,'8/13/2000', 275, 4630.61), +(1322,'12/5/2000', 276,5630.218), +(1325,'9/25/2000', 277,6595.324), +(1328,'6/7/1999', 278,6732.644), +(1331,'12/8/1999', 279,9735.542), +(1334,'12/26/1999', 280,15728.74), +(1337,'4/4/1999', 281,1957.673), +(1340,'8/7/1999', 282,2560.619), +(1343,'3/17/2000', 283,474.9938), +(1346,'6/19/1999', 284,10766.51), +(1349,'7/12/2000', 285,11223.75), +(1352,'10/3/2000', 286,1553.378), +(1355,'12/25/1999', 287,4076.504), +(1358,'11/26/2000', 288,3494.722), +(1364,'4/24/2000', 290,1376.821), +(1367,'8/14/2000', 291,5235.508), +(1370,'9/23/1999', 292,190.3102), +(1373,'6/26/2000', 293,2735.294), +(1376,'6/2/2000', 294,10877.28), +(1382,'4/7/1999', 296, 9086.92), +(1385,'2/26/2000', 297,9702.064), +(1388,'3/12/1999', 100,188.7422), +(1391,'12/26/2000', 101,576.3459), +(1394,'2/24/1999', 102,67.87226), +(1397,'11/27/1999', 103,49.16274), +(1400,'3/2/2000', 104,152.5284), +(1403,'8/22/1999', 105,138.3044), +(1409,'8/5/1999', 107,24.79981), +(1412,'6/25/2000', 108,160.5938), +(1415,'6/18/1999', 109,56.72258), +(1418,'8/20/1999', 110,36.32044), +(1421,'2/17/2000', 111,131.5891), +(1424,'2/19/2000', 112,64.13718), +(1427,'8/26/2000', 113,15.60056), +(1430,'12/21/1999', 114,2.275107), +(1433,'5/23/2000', 115,353.9784), +(1436,'4/2/2000', 116,59.10805), +(1439,'4/3/1999', 117,117.4123), +(1442,'10/20/2000', 118,44.62285), +(1448,'11/8/1999', 120,482.0618), +(1451,'12/1/2000', 121,0.158674), +(1454,'2/6/2000', 122,26.42557), +(1457,'8/15/2000', 123,86.99796), +(1460,'3/14/1999', 124,245.3788), +(1463,'2/15/1999', 125,81.07891), +(1466,'9/8/2000', 126,47.85189), +(1469,'2/16/2000', 127,50.21799), +(1472,'11/23/2000', 128, 47.351), +(1475,'6/22/2000', 129,12.46757), +(1478,'4/24/1999', 130,237.2425), +(1481,'3/25/2000', 131,186.9159), +(1484,'6/2/1999', 132,18.42853), +(1487,'8/27/1999', 133,7.432432), +(1490,'7/15/2000', 134,60.26388), +(1493,'8/10/2000', 135,16.37941), +(1496,'10/2/2000', 136,4.143121), +(1502,'10/8/1999', 138,7.242031), +(1505,'8/24/2000', 139,14.24114), +(1508,'8/9/2000', 140,91.99023), +(1511,'7/1/1999', 141, 70.151), +(1514,'3/13/2000', 142,46.92224), +(1517,'6/27/2000', 143,4.914297), +(1520,'9/14/2000', 144,12.68786), +(1523,'3/18/1999', 145,9.831023), +(1526,'12/14/2000', 146,7.424878), +(1529,'6/24/1999', 147,26.91243), +(1532,'4/14/2000', 148,1.705627), +(1535,'2/20/1999', 149, 31.3328), +(1538,'7/28/1999', 150, 54.4283), +(1541,'12/3/1999', 151,30.67218), +(1544,'10/11/1999', 152, 22.6467), +(1547,'3/18/2000', 153,24.05183), +(1550,'3/15/1999', 154, 28.5632), +(1553,'8/7/1999', 155,0.826164), +(1556,'11/23/1999', 156,9.920162), +(1559,'8/21/1999', 157,14.64077), +(1562,'3/17/1999', 158,32.81727), +(1565,'3/25/1999', 159,66.04171), +(1568,'6/24/1999', 160, 112.243), +(1571,'7/2/2000', 161,18.21168), +(1574,'4/27/2000', 162,10.61284), +(1577,'10/19/1999', 163,83.85694), +(1580,'12/10/2000', 164, 52.8986), +(1583,'12/28/2000', 165,211.4837), +(1586,'11/4/1999', 166,97.49797), +(1589,'10/20/1999', 167,53.01525), +(1592,'10/14/1999', 168,46.53771), +(1595,'5/22/1999', 169,15.11523), +(1598,'5/25/2000', 170,127.9403), +(1601,'5/25/1999', 171,77.36744), +(1604,'6/9/1999', 172,78.45289), +(1607,'9/8/1999', 173,178.9362), +(1610,'6/3/2000', 174,190.9741), +(1613,'7/22/2000', 175,6.944259), +(1616,'12/27/2000', 176, 9.10269), +(1619,'4/26/2000', 177,101.4788), +(1622,'6/11/2000', 178, 50.6176), +(1625,'11/19/2000', 179,14.27261), +(1628,'4/9/1999', 180,137.7139), +(1634,'11/1/1999', 182,101.6721), +(1637,'9/11/1999', 183, 60.1139), +(1640,'4/17/2000', 184,190.7395), +(1643,'5/11/1999', 185, 5.05994), +(1646,'8/21/1999', 186,14.38241), +(1649,'4/26/1999', 187,25.71961), +(1652,'4/3/1999', 188,37.35634), +(1655,'5/7/1999', 189,167.6363), +(1661,'5/13/1999', 191,12.41107), +(1664,'11/18/1999', 192,50.95264), +(1667,'8/2/2000', 193,67.62999), +(1670,'7/16/1999', 194,83.97284), +(1673,'1/9/2000', 195,8.462688), +(1679,'10/3/1999', 197, 77.3681), +(1682,'3/10/2000', 198,1.117515), +(1685,'9/20/1999', 199,4732.466), +(1688,'12/20/2000', 200,15504.25), +(1691,'9/18/1999', 201,11203.11), +(1694,'9/5/2000', 202,16689.98), +(1697,'10/4/1999', 203,4997.475), +(1700,'6/2/1999', 204,473.3774), +(1706,'4/10/2000', 206,4661.805), +(1709,'8/4/1999', 207,11006.09), +(1712,'5/28/2000', 208, 380.71), +(1715,'1/21/1999', 209,10150.82), +(1718,'4/7/2000', 210,6567.307), +(1721,'3/12/2000', 211,1610.885), +(1724,'7/27/1999', 212,6091.375), +(1727,'10/28/2000', 213,3054.828), +(1730,'4/6/1999', 214, 8658.91), +(1733,'1/11/1999', 215,5509.121), +(1736,'10/9/1999', 216, 926.55), +(1739,'7/21/2000', 217,27760.22), +(1745,'6/2/1999', 219,10328.86), +(1748,'7/1/2000', 220,679.4078), +(1751,'9/4/1999', 221,12090.48), +(1754,'2/12/1999', 222,3772.923), +(1757,'10/5/2000', 223,35608.31), +(1760,'10/9/2000', 224,30748.52), +(1763,'9/3/2000', 225,4682.998), +(1766,'5/7/1999', 226,8499.817), +(1769,'5/20/1999', 227,7709.753), +(1772,'12/2/1999', 228,8610.715), +(1775,'11/11/2000', 229, 2641.61), +(1778,'4/3/2000', 230,12071.88), +(1781,'6/2/2000', 231,3715.188), +(1784,'1/24/1999', 232,7048.929), +(1787,'7/28/1999', 233,853.6858), +(1790,'3/17/1999', 234,82.34863), +(1793,'10/25/2000', 235,972.5005), +(1796,'1/27/1999', 236,2789.688), +(1799,'6/20/2000', 237,829.3602), +(1802,'6/13/2000', 238,1718.027), +(1805,'12/11/2000', 239,2874.005), +(1808,'8/22/2000', 240,1326.661), +(1811,'8/2/1999', 241,2673.106), +(1814,'7/23/2000', 242,2727.875), +(1817,'10/18/2000', 243,1742.129), +(1820,'11/22/2000', 244,779.3618), +(1823,'8/20/2000', 245,26.86364), +(1826,'8/15/1999', 246,5.360506), +(1829,'5/4/1999', 247,560.6894), +(1832,'12/25/2000', 248,3984.985), +(1835,'12/2/1999', 249,2396.236), +(1838,'3/9/1999', 250,459.5467), +(1841,'9/12/2000', 251,2766.734), +(1844,'8/23/1999', 252,231.6356), +(1847,'8/18/1999', 253,94.30295), +(1850,'11/26/1999', 254,1104.924), +(1853,'12/16/1999', 255,1393.034), +(1856,'9/9/1999', 256,5095.222), +(1859,'3/10/1999', 257,283.8402), +(1862,'4/6/2000', 258, 8110.89), +(1865,'12/14/2000', 259,5057.524), +(1868,'4/20/1999', 260,87.03693), +(1871,'3/19/1999', 261, 5541.51), +(1874,'9/16/1999', 262,4953.092), +(1877,'12/12/2000', 263,6178.717), +(1880,'3/8/2000', 264,8376.747), +(1883,'1/23/1999', 265,23313.55), +(1886,'8/10/1999', 266,12911.57), +(1889,'4/4/2000', 267,23678.95), +(1892,'8/20/2000', 268,7156.746), +(1895,'5/5/1999', 269,6572.862), +(1898,'1/2/2000', 270,1186.186), +(1901,'9/25/1999', 271,8418.143), +(1904,'11/23/2000', 272,33049.09), +(1907,'2/7/2000', 273,35906.11), +(1910,'9/28/1999', 274,3484.518), +(1913,'12/19/2000', 275,787.9008), +(1916,'12/2/2000', 276,1880.011), +(1919,'8/26/1999', 277,1512.381), +(1922,'4/26/1999', 278,11789.42), +(1925,'10/17/2000', 279,15526.06), +(1928,'6/24/2000', 280,15046.52), +(1931,'5/23/1999', 281,1928.325), +(1934,'5/25/2000', 282,10937.21), +(1937,'1/23/1999', 283,4017.299), +(1940,'1/18/2000', 284,11313.78), +(1943,'11/27/1999', 285,13807.37), +(1946,'12/2/1999', 286,10054.29), +(1949,'12/18/2000', 287,1341.674), +(1952,'8/20/1999', 288,4182.189), +(1958,'3/13/1999', 290, 489.583), +(1961,'10/22/1999', 291,8001.026), +(1964,'11/4/2000', 292,7429.313), +(1967,'10/6/2000', 293, 1592.42), +(1970,'10/7/2000', 294,1674.686), +(1976,'12/28/1999', 296, 2713.18), +(1979,'5/14/1999', 297,5228.697), +(1982,'2/6/1999', 100,397.2972), +(1985,'5/8/1999', 101,270.0248), +(1988,'1/6/2000', 102,171.1764), +(1991,'8/28/1999', 103,25.89929), +(1994,'2/22/1999', 104,232.3206), +(1997,'5/6/1999', 105,235.2605), +(2003,'4/2/2000', 107,30.99789), +(2006,'11/10/1999', 108,608.7637), +(2009,'1/4/2000', 109,288.1529), +(2012,'2/8/2000', 110,76.10206), +(2015,'11/7/2000', 111,43.93914), +(2018,'12/28/1999', 112,10.25989), +(2021,'1/17/2000', 113,28.78546), +(2024,'1/18/1999', 114,58.15921), +(2027,'3/22/1999', 115, 187.817), +(2030,'12/11/2000', 116,54.81473), +(2033,'1/16/2000', 117,446.1077), +(2036,'1/5/1999', 118,203.5912), +(2042,'11/24/1999', 120,23.42961), +(2045,'5/22/1999', 121,87.14982), +(2048,'11/24/1999', 122, 20.3656), +(2051,'3/9/2000', 123,256.5047), +(2054,'2/17/1999', 124,286.4381), +(2057,'9/6/1999', 125,123.9119), +(2060,'12/9/2000', 126,142.6252), +(2063,'7/17/2000', 127,104.2036), +(2066,'9/8/1999', 128,201.5262), +(2069,'6/25/1999', 129,175.6191), +(2072,'4/6/1999', 130,104.4412), +(2075,'11/9/2000', 131,417.5754), +(2078,'9/22/1999', 132,9.971304), +(2081,'9/5/1999', 133,1.064763), +(2084,'11/15/1999', 134,25.05566), +(2087,'3/17/2000', 135,19.94687), +(2090,'3/14/2000', 136,16.79072), +(2096,'7/1/2000', 138,14.76112), +(2099,'2/26/1999', 139,8.636134), +(2102,'8/4/1999', 140,33.20779), +(2105,'11/12/1999', 141,49.57415), +(2108,'10/13/2000', 142,49.40475), +(2111,'11/9/1999', 143,36.55046), +(2114,'3/21/2000', 144,5.867452), +(2117,'9/5/2000', 145,14.63534), +(2120,'4/23/1999', 146,15.91529), +(2123,'3/26/1999', 147,73.85168), +(2126,'6/1/1999', 148,8.992213), +(2129,'3/26/2000', 149,8.362277), +(2132,'6/13/2000', 150,30.64562), +(2135,'6/16/2000', 151, 34.2395), +(2138,'6/9/1999', 152,30.33333), +(2141,'1/20/2000', 153,3.226211), +(2144,'1/14/1999', 154,28.97461), +(2147,'12/19/1999', 155, 0.30189), +(2150,'6/23/2000', 156, 21.0384), +(2153,'12/25/2000', 157,29.22727), +(2156,'6/22/1999', 158,2.647235), +(2159,'2/13/1999', 159,68.63482), +(2162,'4/19/2000', 160,130.3504), +(2165,'10/6/2000', 161,2.180321), +(2168,'7/16/1999', 162,7.910875), +(2171,'5/17/1999', 163,29.40676), +(2174,'7/3/2000', 164,24.30426), +(2177,'10/6/2000', 165,90.38355), +(2180,'3/2/2000', 166,36.46251), +(2183,'3/13/1999', 167,2.747963), +(2186,'2/6/2000', 168,182.0007), +(2189,'11/1/2000', 169, 191.417), +(2192,'1/19/1999', 170,171.5873), +(2195,'8/16/2000', 171,41.89359), +(2198,'8/6/1999', 172,11.04035), +(2201,'10/8/1999', 173,68.56703), +(2204,'4/10/2000', 174,106.7472), +(2207,'6/23/1999', 175,39.85807), +(2210,'6/18/2000', 176,41.44438), +(2213,'4/20/2000', 177,44.66734), +(2216,'8/13/1999', 178,11.21136), +(2219,'11/13/1999', 179,5.600994), +(2222,'5/11/2000', 180,123.0376), +(2228,'6/1/2000', 182,251.2471), +(2231,'11/27/1999', 183,35.94439), +(2234,'4/17/1999', 184,198.5348), +(2237,'7/3/2000', 185,2.967351), +(2240,'12/2/2000', 186,8.045825), +(2243,'7/21/2000', 187,5.728503), +(2246,'9/23/1999', 188,36.76644), +(2249,'10/26/2000', 189,232.8362), +(2255,'1/12/1999', 191,33.72641), +(2258,'10/3/2000', 192,64.46211), +(2261,'7/25/2000', 193,67.27182), +(2264,'6/24/1999', 194,61.60903), +(2267,'4/13/2000', 195,165.0446), +(2273,'4/11/1999', 197,113.3709), +(2276,'3/3/2000', 198,11.32904), +(2279,'11/14/1999', 199,1851.289), +(2282,'6/6/2000', 200,31405.72), +(2285,'7/13/2000', 201,716.3705), +(2288,'9/3/2000', 202,29606.56), +(2291,'7/25/2000', 203,20195.74), +(2294,'9/4/1999', 204,2842.049), +(2300,'1/7/2000', 206,5454.829), +(2303,'11/25/1999', 207,2206.141), +(2306,'1/28/2000', 208,4744.707), +(2309,'7/7/1999', 209, 6390.97), +(2312,'4/11/1999', 210,9539.196), +(2315,'12/24/2000', 211,7864.815), +(2318,'5/15/1999', 212, 872.542), +(2321,'1/7/2000', 213,3318.323), +(2324,'11/4/1999', 214,5763.722), +(2327,'6/9/1999', 215,944.3873), +(2330,'4/13/1999', 216,511.0076), +(2333,'6/28/1999', 217,12801.39), +(2339,'7/17/1999', 219,27869.35), +(2342,'3/11/2000', 220,623.9558), +(2345,'5/16/1999', 221,20758.23), +(2348,'4/8/1999', 222,10280.78), +(2351,'7/8/2000', 223,33963.38), +(2354,'4/7/1999', 224,4988.438), +(2357,'5/8/2000', 225,177.7306), +(2360,'4/4/1999', 226,3673.922), +(2363,'2/25/1999', 227,5418.243), +(2366,'12/6/2000', 228,9651.242), +(2369,'2/19/2000', 229,801.9194), +(2372,'8/12/2000', 230,2035.503), +(2375,'1/21/2000', 231,2476.122), +(2378,'1/9/1999', 232,4527.432), +(2381,'1/27/1999', 233,275.1983), +(2384,'8/24/1999', 234, 2747.21), +(2387,'8/22/2000', 235,2454.241), +(2390,'2/2/1999', 236,2111.672), +(2393,'8/9/1999', 237,1387.837), +(2396,'12/8/2000', 238, 1163), +(2399,'7/12/1999', 239,3890.431), +(2402,'4/21/2000', 240,239.6195), +(2405,'4/6/2000', 241,1842.653), +(2408,'8/20/1999', 242,2152.329), +(2411,'3/12/2000', 243,3005.124), +(2414,'8/2/1999', 244,2638.944), +(2417,'2/26/2000', 245,2431.208), +(2420,'5/23/2000', 246,42.41151), +(2423,'2/21/2000', 247,841.1042), +(2426,'7/17/2000', 248,3386.254), +(2429,'1/3/2000', 249,1843.864), +(2432,'10/11/2000', 250,1357.021), +(2435,'11/13/2000', 251,2883.029), +(2438,'4/13/2000', 252,236.1756), +(2441,'1/10/1999', 253,142.5996), +(2444,'7/15/1999', 254,2718.375), +(2447,'4/26/1999', 255,989.5613), +(2450,'4/27/2000', 256,6972.301), +(2453,'2/24/1999', 257,130.9576), +(2456,'11/10/1999', 258,6262.766), +(2459,'11/18/2000', 259,3086.867), +(2462,'10/28/2000', 260,20.02136), +(2465,'12/10/1999', 261,4172.872), +(2468,'12/10/2000', 262,1533.623), +(2471,'12/1/2000', 263,3092.681), +(2474,'10/9/2000', 264,3854.422), +(2477,'1/19/2000', 265,9572.416), +(2480,'12/15/1999', 266,12107.02), +(2483,'6/12/1999', 267,249.8177), +(2486,'3/8/1999', 268,11433.34), +(2489,'3/15/2000', 269,905.8667), +(2492,'5/15/2000', 270,431.7046), +(2495,'11/10/2000', 271,7490.943), +(2498,'7/4/2000', 272, 4332.43), +(2501,'3/20/1999', 273,11927.34), +(2504,'7/21/2000', 274,6024.322), +(2507,'9/20/1999', 275, 84.9894), +(2510,'5/15/2000', 276,4547.415), +(2513,'5/23/2000', 277,4440.402), +(2516,'9/28/1999', 278,9733.886), +(2519,'9/13/2000', 279,1155.452), +(2522,'10/20/2000', 280,7285.954), +(2525,'6/19/1999', 281,466.4518), +(2528,'11/1/1999', 282,8143.997), +(2531,'11/28/2000', 283,2163.073), +(2534,'10/22/1999', 284,9218.228), +(2537,'7/10/2000', 285,9369.708), +(2540,'6/28/2000', 286,7669.178), +(2543,'2/25/2000', 287,2292.681), +(2552,'10/21/1999', 290,3701.036), +(2555,'3/19/2000', 291,6146.988), +(2558,'2/16/1999', 292,3093.035), +(2561,'12/8/2000', 293, 3779.69), +(2564,'4/22/2000', 294,4568.839), +(2570,'4/23/2000', 296,8000.067), +(2573,'5/4/2000', 297, 7879.64); +-- end of TRANSACTION DATA diff --git a/extenders/spatial/bank/seBankDemoViewDDL.db2 b/extenders/spatial/bank/seBankDemoViewDDL.db2 new file mode 100644 index 0000000..717b689 --- /dev/null +++ b/extenders/spatial/bank/seBankDemoViewDDL.db2 @@ -0,0 +1,210 @@ +---------------------------------------------------------------------------- +-- Licensed Materials - Property of IBM +-- Governed under the terms of the IBM Public License +-- +-- (C) COPYRIGHT International Business Machines Corp. 2000 - 2014 +-- All Rights Reserved. +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +---------------------------------------------------------------------------- +-- +-- Product Name: DB2 Spatial Extender +-- +-- Source File Name: seBankDemoViewDDL.db2 +-- +-- Version: 10.5.0 +-- +-- Description: +-- +-- +-- +-- For more information about the DB2 Spatial Extender Bank Demo scripts, +-- see the seBankDemoREADME.txt file. +-- +-- For more information about DB2 SE, see the "DB2 Spatial Extender User Guide". +-- +-- For the latest information on DB2 Spatial Extender and the Bank Demo +-- refer to the DB2 Spatial Extender website at +-- http://www.software.ibm.com/software/data/spatial/db2spatial +---------------------------------------------------------------------------- + +--========================================================================== +-- Show all customers of Branch 1 - Meridian +--========================================================================== + +CREATE VIEW se_demo.meridian_customers (name, phone, location, branch_name) AS + SELECT c.name, c.phone, c.location, b.name + FROM (se_demo.customers AS c + JOIN se_demo.accounts AS a + ON (a.customer_id = c.customer_id)) + JOIN se_demo.branches AS b + ON (b.branch_id = a.branch_id) + WHERE b.name='Meridian'; + +--========================================================================== +-- Show all customers of Branch 2 - San Carlos +--========================================================================== + +CREATE VIEW se_demo.sancarlos_customers (name, phone, location, branch_name) AS + SELECT c.name, c.phone, c.location, b.name + FROM (se_demo.customers AS c + JOIN se_demo.accounts AS a + ON (a.customer_id = c.customer_id)) + JOIN se_demo.branches AS b + ON (b.branch_id = a.branch_id) + WHERE b.name='San Carlos'; + +--========================================================================== +-- Show the nearest branch of each customer +--========================================================================== + +CREATE VIEW se_demo.closest_branch AS + WITH distance_to_customers(c_id, b_id, distance) AS + (SELECT c.customer_id, b.branch_id, db2gse.ST_Distance(c.location, b.location) + FROM se_demo.customers c, se_demo.branches b + WHERE c.customer_id > 0) + SELECT c.name, c.location, c.phone, d_c.b_id, d_c.distance + FROM distance_to_customers d_c, se_demo.customers c + WHERE d_c.c_id=c.customer_id AND + d_c.distance <= ALL(SELECT distance + FROM distance_to_customers d_c2 + WHERE d_c2.c_id=d_c.c_id); + +--========================================================================== +-- Show all savings balance +--========================================================================== + +CREATE VIEW se_demo.customers_savings AS + SELECT c.customer_id, c.name, c.phone, c.location, a.balance + FROM se_demo.accounts a, se_demo.customers c + WHERE a.type = 'Saving' AND + a.customer_id = c.customer_id; + +--========================================================================== +-- Show all checking accounts balance +--========================================================================== + +CREATE VIEW se_demo.customers_checkings AS + SELECT c.customer_id, c.name, c.phone, c.location, a.balance + FROM se_demo.accounts a, se_demo.customers c + WHERE a.type = 'Checking' AND + a.customer_id = c.customer_id; + +--========================================================================== +-- Show checking+saving accounts balance +--========================================================================== + +CREATE VIEW se_demo.customers_totals AS + WITH account_sum (customer_id, sum_balance) AS + (SELECT act.customer_id, SUM(act.balance) + FROM se_demo.accounts act + GROUP BY act.customer_id + ) + SELECT c.customer_id, c.name, c.phone, c.location, account_sum.sum_balance + FROM se_demo.customers c, account_sum + WHERE account_sum.customer_id = c.customer_id; + + +--========================================================================== +-- Show the savings balance of all customers 0.05(3.5) miles from my branches +--========================================================================== + +CREATE VIEW se_demo.closest_savings AS + SELECT c.customer_id, c.name, c.phone, c.location, a.balance + FROM se_demo.accounts a, se_demo.branches b, se_demo.customers c + WHERE db2gse.st_distance(b.location, c.location) > .05 AND + a.type = 'Saving' AND + a.customer_id = c.customer_id AND + a.balance > 45000; + +--========================================================================== +-- Show the checking balance of all customers 0.05 miles from my branches +--========================================================================== + +CREATE VIEW se_demo.closest_checking AS + SELECT c.customer_id, c.name, c.phone, c.location, a.balance + FROM se_demo.accounts a, se_demo.branches b, se_demo.customers c + WHERE db2gse.st_distance(b.location, c.location) > .05 AND + a.TYPE = 'Checking' AND + a.customer_id = c.customer_id AND + a.balance > 2000; + +--========================================================================== +-- Branch Zone Overlap Query +-- All the customer with more than 50000 in their saving accounts in overlapping zones +--========================================================================== + +CREATE VIEW se_demo.overlap_zone AS + SELECT c.customer_id, c.name, c.phone, c.location, a.balance + FROM se_demo.customers c, se_demo.branches b1, se_demo.branches b2, + se_demo.accounts a + WHERE db2gse.ST_Within(c.location, + db2gse.ST_Intersection( + db2gse.ST_Buffer(b1.location ,0.04), + db2gse.ST_Buffer(b2.location ,0.04) + ) + )=1 + AND b1.branch_id <> b2.branch_id + AND a.balance > 50000 AND a.type = 'Saving' + AND a.customer_id = c.customer_id + AND (a.branch_id=b1.branch_id OR a.branch_id=b2.branch_id); + +--========================================================================== +-- Branch Buffers +-- Show the areas 0.04 miles away from my branches +--========================================================================== +-- This table is needed because of a limitation in ArcExplorer. +-- ArcExplorer can't visualize views when the geometry changes type. + +CREATE TABLE se_demo.branch_buffers( + se_row_id INTEGER, + geometry db2gse.ST_Polygon ) organize by row; + +INSERT INTO se_demo.branch_buffers(se_row_id, geometry) + (SELECT se_row_id, TREAT(db2gse.ST_Buffer(location, 0.04) AS db2gse.ST_Polygon) + FROM se_demo.branches); + +--========================================================================== +-- Create aggregate view of Savings balance per census block +--========================================================================== + +CREATE VIEW se_demo.avg_savings_block AS + SELECT cb.geometry, cb.se_row_id, avg_blocks.avg_balance + FROM se_demo.sj_census_blocks AS cb, + (SELECT blocks.se_row_id, avg(customer_savings.balance) AS avg_balance + FROM se_demo.sj_census_blocks AS blocks, + (SELECT c.location, a.balance + FROM se_demo.customers AS c, se_demo.accounts AS a + WHERE (a.type='Saving') AND + (a.customer_id=c.customer_id) + ) as customer_savings + WHERE (db2gse.ST_Within(customer_savings.location, blocks.geometry)=1 ) + GROUP BY blocks.se_row_id + ) as avg_blocks + WHERE cb.se_row_id=avg_blocks.se_row_id; + +--========================================================================== +-- Show the areas of Census blocks(SELBLOCKS) that have average +-- income greater than 80% of my maximum savings balance +--========================================================================== +-- all_customer = all customers with a savings account + +CREATE VIEW se_demo.prospects AS + WITH max_blocks(amount) AS + (SELECT MAX(group_blocks.average) + FROM + (SELECT blocks.se_row_id, AVG(all_customers.balance) AS average + FROM se_demo.sj_census_blocks blocks, + (SELECT c.location, a.balance + FROM se_demo.customers AS c, se_demo.accounts AS a + WHERE (a.type='Saving') AND + (a.customer_id=c.customer_id) + ) AS all_customers + WHERE (db2gse.ST_Within(all_customers.location, blocks.geometry)=1) + GROUP BY blocks.se_row_id + ) AS group_blocks + ) + SELECT blocks.geometry, blocks.se_row_id, average__1 + FROM se_demo.sj_census_blocks AS blocks, max_blocks AS mx + WHERE average__1 > (0.8 * mx.amount); diff --git a/extenders/spatial/bldDemo b/extenders/spatial/bldDemo new file mode 100644 index 0000000..a4bbe84 --- /dev/null +++ b/extenders/spatial/bldDemo @@ -0,0 +1,157 @@ +#! /bin/sh + +############################################################################# +# Licensed Materials - Property of IBM +# +# Governed under the terms of the International +# License Agreement for Non-Warranted Sample Code. +# +# (C) COPYRIGHT International Business Machines Corp. 1995, 2002 +# All Rights Reserved. +# +# US Government Users Restricted Rights - Use, duplication or +# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +############################################################################# +# SCRIPT: bldDemo.sh +# Builds Spatial Extender sample program "runGseDemo" for UNIX platforms +# Supported platforms are: AIX, Linux, HP-UX, SunOS +# 32-bit or 64-bit installations +# Usage: bldDemo.sh + +echo "This script will rebuild the runGseDemo program... " +echo "==> Do you wish to continue? (y/n)" +read yesno +if [ "$yesno" != "y" ] ; then + echo "bldDemo.sh: No changes made. Exiting at user request. " + exit +fi + +# DB2PATH must be set to the path to sqllib in this instance. +# If the user has it set in the environment, we use it +if [ "$DB2PATH" = "" ] ; then + # We try our best to set the correct value and then ask the user to confirm + echo "DB2PATH is not set as an environment variable--we try to set it now..." + INSTHOME=`grep "^$DB2INSTANCE:" /etc/passwd | sed 's/.*:.*:.*.:\(.*\):.*/\1/'` + DB2PATH=$INSTHOME/sqllib + echo "DB2PATH: [$DB2PATH]" + echo "==> Is this the correct path to sqllib for this instance? (y/n)" + read yesno + if [ "$yesno" != "y" ] ; then + echo "Please set the environment variable DB2PATH and re-run this script." + echo " ==> DB2PATH must be the full path to sqllib in this instance." + echo "bldDemo.sh: No changes made. Exiting at user request. " + exit + fi +else + echo "Using DB2PATH: [$DB2PATH]" +fi + +# Set compile and link flags for 32-bit and 64-bit programs. +LIB="lib" +EXTRA_CFLAG="" +EXTRA_LFLAG="" +MTFLAG="" +OS_UNAME=`uname` +HARDWAREPLAT=`uname -m` +bitwidth=`LANG=C db2level | awk '/bits/{print $5}'` +if [ $bitwidth = "\"32\"" ]; then + WIDTH="32bit" +else + WIDTH="64bit" +fi + +# The linked-in runtime path is recommended for all applications +# rather than LD_LIBRARY_PATH. If you need to use LD_LIBRARY_PATH for +# some reason, comment out the next line and rebuild the program. +RUNTIME=true + +#------------------------------------------------------------------------ +if [ $OS_UNAME = "AIX" ]; then + COMPILER=xlc + if [ $WIDTH = "32bit" ]; then + LIB=lib32 + EXTRA_CFLAG="-qcpluscmt" + else + EXTRA_CFLAG="-q64 -qcpluscmt" + fi + LINK_FLAGS="-ldb2 -L$DB2PATH/$LIB" +fi # end of AIX section +#------------------------------------------------------------------------ +if [ $OS_UNAME = "Linux" ]; then + COMPILER=gcc + if [ $WIDTH = "32bit" ]; then + LIB="lib32" + if [ "$HARDWAREPLAT" = "x86_64" ]; then + EXTRA_CFLAG="-m32" + fi + fi + + if [ "$RUNTIME" != "" ] ; then + EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + fi + LINK_FLAGS="-L$DB2PATH/$LIB $EXTRA_LFLAG -ldb2" +fi # end of Linux section +#------------------------------------------------------------------------ +if [ $OS_UNAME = "HP-UX" ]; then + COMPILER=cc + if [ $HARDWAREPLAT = "ia64" ] ; then + if [ $WIDTH = "32bit" ]; then + EXTRA_CFLAG="+DD32" + LIB="lib32" + else + EXTRA_CFLAG="+DD64" + fi + else + if [ $WIDTH = "32bit" ]; then + EXTRA_CFLAG= + LIB="lib32" + else + EXTRA_CFLAG="+DA2.0W" + fi + fi + if [ "$RUNTIME" != "" ] ; then + EXTRA_LFLAG="-Wl,+b$DB2PATH/$LIB" + fi + LINK_FLAGS="$EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2" +fi # end of HP-UX section +#------------------------------------------------------------------------ +if [ $OS_UNAME = "SunOS" ] ; then + COMPILER=cc + MTFLAG="-mt" + if [ $WIDTH = "32bit" ]; then + EXTRA_CFLAG="-xarch=v8plusa" + LIB=lib32 + else + EXTRA_CFLAG="-xarch=v9" + fi + if [ "$RUNTIME" != "" ] ; then + EXTRA_LFLAG="-R$DB2PATH/$LIB" + fi + LINK_FLAGS="-L$DB2PATH/$LIB $EXTRA_LFLAG -ldb2" +fi # end of SunOS section +#------------------------------------------------------------------------ + +echo "Rebuilding runGseDemo program for $WIDTH $OS_UNAME ..." +rm -f runGseDemo.o samputil.o runGseDemo + +# Compile the program. +$COMPILER $EXTRA_CFLAG -I$DB2PATH/include -c runGseDemo.c +$COMPILER $EXTRA_CFLAG -I$DB2PATH/include -c samputil.c + +$COMPILER $EXTRA_CFLAG $MTFLAG -o runGseDemo runGseDemo.o samputil.o $LINK_FLAGS + +chmod 777 runGseDemo +echo "==>Done building runGseDemo program" + +echo " " +echo "It is recommended to create a directory for temp files that" +echo " are generated when runGseDemo executes. " +echo "Then set the environment variable DEMO_TMPDIR to the " +echo " full path to that directory." +echo "EXAMPLE: " +echo " rm -rf ./gsedemo_tmp" +echo " mkdir ./gsedemo_tmp" +echo " chmod 777 ./gsedemo_tmp" +echo " export DEMO_TMPDIR=$PWD/gsedemo_tmp" +echo " " + diff --git a/extenders/spatial/customers.data b/extenders/spatial/customers.data new file mode 100644 index 0000000..abf20d7 --- /dev/null +++ b/extenders/spatial/customers.data @@ -0,0 +1,337 @@ +40458,"Michelle Pan","1671 AVON CIRCLE","RADCLIFF","KY","40160",+3.81820000000000E+004,+1.25500000000000E+003,5,+3.78265480000000E+001,-8.59635150000000E+001 +40779,"Gene Mayer","3804 BERRYTOWN RD","RINEYVILLE","KY","40162",+9.90960000000000E+004,+1.98200000000000E+003,7,+3.77835420000000E+001,-8.60460890000000E+001 +40844,"Jean Scott","3400 PORTER PIKE","BOWLING GREEN","KY","42103",+1.44542000000000E+005,+1.37300000000000E+003,8,+3.69890050000000E+001,-8.63426470000000E+001 +41003,"Roy McArthur","300 GARDEN RD","LEXINGTON","KY","40502",+8.36330000000000E+004,+2.68900000000000E+003,5,+3.80203730000000E+001,-8.44847400000000E+001 +41009,"Gene Carey","1132 WELLS LN","LAWRENCEBURG","KY","40342",+1.49099000000000E+005,+1.50300000000000E+003,8,+3.80061200000000E+001,-8.48927230000000E+001 +41012,"Hsin Henderson","8487 WATERSEDGE DR","FLORENCE","KY","41042",+2.27220000000000E+004,+2.26400000000000E+003,1,+3.89706020000000E+001,-8.46395640000000E+001 +41084,"Eileen Wang","3019 ROSEDALE BLVD","LOUISVILLE","KY","40220",+1.44544000000000E+005,+1.57400000000000E+003,8,+3.82193700000000E+001,-8.56505030000000E+001 +41119,"Keith Panwar","1318 N MILES ST","ELIZABETHTOWN","KY","42701",+4.90900000000000E+004,+2.15800000000000E+003,3,+3.77159200000000E+001,-8.58514760000000E+001 +41155,"Peter Smith","516 5TH ST","CARROLLTON","KY","41008",+1.05456000000000E+005,+1.76100000000000E+003,7,+3.86757710000000E+001,-8.51791360000000E+001 +41171,"Michelle Pan","128 S CRESTMOOR AVE","LOUISVILLE","KY","40206",+1.11812000000000E+005,+3.03800000000000E+003,5,+3.82530110000000E+001,-8.56722560000000E+001 +41286,"Michelle Swagerman","2041 DUNKIRK DR","LEXINGTON","KY","40504",+6.63680000000000E+004,+4.09000000000000E+002,9,+3.80566780000000E+001,-8.45440650000000E+001 +41373,"Jean Wilson","8303 ROSEBOROUGH RD","LOUISVILLE","KY","40228",+3.36360000000000E+004,+1.87200000000000E+003,2,+3.81283680000000E+001,-8.56298770000000E+001 +41617,"Cindy Peterson","157 N BAYLY AVE","LOUISVILLE","KY","40206",+7.72730000000000E+004,+1.00900000000000E+003,8,+3.82561700000000E+001,-8.56924380000000E+001 +41626,"Jean Vincent","131 CLEARWATER LN","FRANKFORT","KY","40601",+1.63620000000000E+004,+5.85000000000000E+002,4,+3.81386870000000E+001,-8.49344110000000E+001 +41654,"Michelle McArthur","70 BURNEY LN","FORT THOMAS","KY","41075",+1.44540000000000E+005,+1.17100000000000E+003,8,+3.90688180000000E+001,-8.44550450000000E+001 +41657,"Brian Vincent","1541 WOODSIDE DR","FLORENCE","KY","41042",+2.72730000000000E+004,+1.79000000000000E+003,1,+3.90001600000000E+001,-8.46770800000000E+001 +41668,"Samuel Tran","2015 BARNES RD","BARDSTOWN","KY","40004",+1.38184000000000E+005,+1.79500000000000E+003,8,+3.78326590000000E+001,-8.55573770000000E+001 +41730,"Peter Tran","5020 POND CREEK RD","ALEXANDRIA","KY","41001",+9.07000000000000E+002,+2.09800000000000E+003,1,+3.88997480000000E+001,-8.44347080000000E+001 +41758,"Rajendra Jou","424 SOUTHSIDE DR","HENDERSON","KY","42420",+1.38185000000000E+005,+1.89600000000000E+003,7,+3.78179740000000E+001,-8.75702470000000E+001 +41891,"Peter Cody","12170 WOODWIND LN","WALTON","KY","41094",+1.11810000000000E+005,+2.83600000000000E+003,6,+3.88707430000000E+001,-8.46474550000000E+001 +42040,"Jean Tran","3609 SAINT GERMAINE CT","LOUISVILLE","KY","40207",+1.00900000000000E+005,+1.73200000000000E+003,7,+3.82434770000000E+001,-8.56546450000000E+001 +42384,"Keith Grandbois","38 WOODSTOCK CIR","LA GRANGE","KY","40031",+9.45470000000000E+004,+7.57000000000000E+002,8,+3.84394260000000E+001,-8.53125360000000E+001 +42406,"Roy Kleewein","404 COMANCHE CT","SHELBYVILLE","KY","40065",+1.63600000000000E+004,+3.83000000000000E+002,6,+3.82258990000000E+001,-8.52382280000000E+001 +42408,"Jean Fuh","321 COMANCHE RD","SHELBYVILLE","KY","40065",+3.81820000000000E+004,+1.25500000000000E+003,5,+3.82253670000000E+001,-8.52376270000000E+001 +42410,"Grace Li","2453 BLUEBALL RD","RINEYVILLE","KY","40162",+5.09040000000000E+004,+1.01500000000000E+003,7,+3.77640390000000E+001,-8.60233660000000E+001 +42486,"Daniel Kifer","3113 DALE ANN DR","LOUISVILLE","KY","40220",+6.63600000000000E+004,+1.50300000000000E+003,6,+3.82079470000000E+001,-8.56312190000000E+001 +42576,"Hsin Panwar","101 CRESENT DR","BEREA","KY","40403",+6.63610000000000E+004,+1.60300000000000E+003,6,+3.75724340000000E+001,-8.42832530000000E+001 +42923,"Daniel Wilson","607 EDGEWATER DR","ELIZABETHTOWN","KY","42701",+8.36320000000000E+004,+2.58800000000000E+003,5,+3.77190390000000E+001,-8.58581210000000E+001 +42956,"Samuel McArthur","1405 ROUNDTOP RD","ELIZABETHTOWN","KY","42701",+1.16365000000000E+005,+1.22600000000000E+003,8,+3.76193380000000E+001,-8.58206900000000E+001 +42957,"Albert McKnight","1146 ROUNDTOP RD","ELIZABETHTOWN","KY","42701",+1.27276000000000E+005,+2.43100000000000E+003,7,+3.76229270000000E+001,-8.58217940000000E+001 +42985,"Grace Wilson","761 COLONIAL TRCE","FRANKFORT","KY","40601",+1.05454000000000E+005,+1.56000000000000E+003,7,+3.82141460000000E+001,-8.48482810000000E+001 +42986,"Lawrence Winer","2515 TOP HILL RD","LOUISVILLE","KY","40206",+1.16365000000000E+005,+1.22600000000000E+003,8,+3.82472000000000E+001,-8.56961230000000E+001 +42989,"Ping Huras","506 NATIONAL TPKE","MUNFORDVILLE","KY","42765",+1.49098000000000E+005,+1.40200000000000E+003,8,+3.72742400000000E+001,-8.58930820000000E+001 +43040,"Ted Harris","502 E MAIN ST","GLASGOW","KY","42141",+5.09000000000000E+004,+2.51200000000000E+003,2,+3.69940800000000E+001,-8.59073540000000E+001 +43042,"Yun Mayer","3140 BEECH AVE","COVINGTON","KY","41015",+7.27220000000000E+004,+1.48400000000000E+003,6,+3.90509530000000E+001,-8.45083180000000E+001 +43137,"Normen Kifer","3865 GLADMAN WAY","LEXINGTON","KY","40514",+1.27278000000000E+005,+2.63300000000000E+003,6,+3.79976620000000E+001,-8.45748490000000E+001 +43162,"Mary Cody","1593 TANNER RD","HEBRON","KY","41048",+7.27230000000000E+004,+1.58400000000000E+003,6,+3.90977220000000E+001,-8.47028060000000E+001 +43279,"Albert Pan","3101 CHATHAM DR","LEXINGTON","KY","40503",+4.90910000000000E+004,+2.25900000000000E+003,3,+3.80044500000000E+001,-8.45518930000000E+001 +43360,"Daniel McKnight","19 FOUNDERS CT","COLD SPRING","KY","41076",+1.00903000000000E+005,+2.03400000000000E+003,6,+3.90176830000000E+001,-8.44450730000000E+001 +43399,"Grace Henderson","1204 WASHINGTON ST","SHELBYVILLE","KY","40065",+4.90930000000000E+004,+2.46000000000000E+003,2,+3.82134500000000E+001,-8.52289410000000E+001 +43400,"Lawrence Fuh","4706 ROCKFORD PLZ","LOUISVILLE","KY","40216",+5.09040000000000E+004,+1.01500000000000E+003,7,+3.81780840000000E+001,-8.58280390000000E+001 +43553,"Mary Kleewein","4437 INDIAN TRACE RD","ALEXANDRIA","KY","41001",+8.36380000000000E+004,+1.29300000000000E+003,7,+3.89324630000000E+001,-8.44410000000000E+001 +43566,"Brian Elliot","780 GRACE DR","FLORENCE","KY","41042",+6.63610000000000E+004,+1.60300000000000E+003,6,+3.89693000000000E+001,-8.46505090000000E+001 +43614,"Eileen Vance","4811 FERRER WAY","LOUISVILLE","KY","40291",+9.45400000000000E+004,+1.95200000000000E+003,6,+3.81762630000000E+001,-8.55883080000000E+001 +43793,"Michelle McArthur","185 ROBIN LN","SHEPHERDSVILLE","KY","40165",+8.36310000000000E+004,+2.48700000000000E+003,5,+3.80188430000000E+001,-8.56374390000000E+001 +44247,"Keith Cody","1912 SPRING STATION DR","LEXINGTON","KY","40505",+1.27279000000000E+005,+2.73300000000000E+003,6,+3.80674020000000E+001,-8.44511680000000E+001 +44887,"Mary Henderson","616 E DIXIE AVE","ELIZABETHTOWN","KY","42701",+7.72750000000000E+004,+1.21100000000000E+003,7,+3.76859310000000E+001,-8.58518250000000E+001 +44953,"Steven Pan","1340 CHESTNUT STAND RD","IRVINE","KY","40336",+1.33632000000000E+005,+1.80700000000000E+003,7,+3.77247900000000E+001,-8.39374830000000E+001 +45009,"Grace Vance","9802 STONEHENGE WAY","LOUISVILLE","KY","40241",+9.90990000000000E+004,+2.28400000000000E+003,6,, +45068,"Steven Swagerman","89 THOMPSON AVE","FORT MITCHELL","KY","41017",+8.81880000000000E+004,+1.07900000000000E+003,8,+3.90446040000000E+001,-8.45596030000000E+001 +45098,"Keith Vincent","274 APOLLO DR","MOUNT WASHINGTON","KY","40047",+8.81880000000000E+004,+1.07900000000000E+003,8,+3.80564220000000E+001,-8.55522920000000E+001 +45099,"Jean Swagerman","162 KIMBERLY DR","MOUNT WASHINGTON","KY","40047",+9.90900000000000E+004,+1.37700000000000E+003,7,+3.80456070000000E+001,-8.55518430000000E+001 +45729,"Daniel Tran","404 MCALPIN AVE","ERLANGER","KY","41018",+9.90960000000000E+004,+1.98200000000000E+003,7,+3.90200110000000E+001,-8.46108910000000E+001 +46136,"Grace Ryden","7503 MANSLICK RD","LOUISVILLE","KY","40214",+1.16367000000000E+005,+1.42700000000000E+003,8,+3.81480240000000E+001,-8.57904240000000E+001 +46490,"Ted McArthur","13710 BOAT DOCK RD","UNION","KY","41091",+5.09040000000000E+004,+1.01500000000000E+003,7,+3.88616230000000E+001,-8.47707010000000E+001 +46784,"Ping Lee","6472 TODD DR","BURLINGTON","KY","41005",+1.44541000000000E+005,+1.27200000000000E+003,8,+3.90138290000000E+001,-8.47097550000000E+001 +47101,"Ingrid Harris","320 HIALEAH DR","COXS CREEK","KY","40013",+1.18120000000000E+004,+2.69900000000000E+003,1,+3.79599180000000E+001,-8.54862450000000E+001 +47113,"Yun Vincent","300 BLUE CREEK COURT","LOUISVILLE","KY","40229",+1.33634000000000E+005,+2.00900000000000E+003,7,+3.81038720000000E+001,-8.56976260000000E+001 +47151,"Michelle Fuh","8108 PINECASTLE DR","LOUISVILLE","KY","40219",+6.18120000000000E+004,+1.91800000000000E+003,5,+3.81321060000000E+001,-8.56554490000000E+001 +47228,"Yun Peterson","435 RED RIVER RD","IRVINE","KY","40336",+8.81800000000000E+004,+2.72000000000000E+002,9,, +47253,"Steven Wang","1730 COPELIN RD","WHITE MILLS","KY","42788",+3.36350000000000E+004,+1.77100000000000E+003,2,+3.75386810000000E+001,-8.60392120000000E+001 +47360,"Hsin Huras","607 EL DORADO DR","ELIZABETHTOWN","KY","42701",+5.09030000000000E+004,+9.15000000000000E+002,7,+3.77017810000000E+001,-8.58797510000000E+001 +47361,"Brian Vincent","600 QUAIL RUN RD","BRANDENBURG","KY","40108",+6.18140000000000E+004,+2.12000000000000E+003,4,+3.79712360000000E+001,-8.61755340000000E+001 +47362,"Daniel Swagerman","125 WESTWIND TRL","BARDSTOWN","KY","40004",+7.27250000000000E+004,+1.78600000000000E+003,6,+3.78186140000000E+001,-8.54695780000000E+001 +47389,"Yun McArthur","3751 ROSEMONT BLVD","LOUISVILLE","KY","40218",+4.90920000000000E+004,+2.35900000000000E+003,2,+3.82023840000000E+001,-8.56460170000000E+001 +47403,"Gene Tran","5505 WESTHALL AVE","LOUISVILLE","KY","40214",+3.36370000000000E+004,+1.97300000000000E+003,2,+3.81514090000000E+001,-8.57751060000000E+001 +47445,"Jean Peterson","5650 HARDYVILLE RD","HARDYVILLE","KY","42746",+5.45900000000000E+003,+1.72500000000000E+003,1,+3.72284940000000E+001,-8.56827020000000E+001 +47451,"Ping McArthur","1402 VERSAILLES RD","LEXINGTON","KY","40504",+6.18150000000000E+004,+2.22100000000000E+003,4,+3.80493600000000E+001,-8.45264120000000E+001 +47474,"Ping Panwar","4011 DIXIE LN","BARDSTOWN","KY","40004",+1.44548000000000E+005,+1.97700000000000E+003,7,+3.78560830000000E+001,-8.55052940000000E+001 +47475,"Hsin Mayer","4116 VINE GROVE RD","VINE GROVE","KY","40175",+5.45900000000000E+003,+1.72500000000000E+003,1,+3.78119890000000E+001,-8.59913440000000E+001 +47695,"Albert Scott","2124 WOODBOURNE AVE","LOUISVILLE","KY","40205",+1.05452000000000E+005,+1.35800000000000E+003,8,+3.82252960000000E+001,-8.56888600000000E+001 +47709,"Ted Fuh","100 PATRICK CT","ELIZABETHTOWN","KY","42701",+9.90960000000000E+004,+1.98200000000000E+003,7,+3.77180460000000E+001,-8.58933600000000E+001 +47710,"Peter Jou","8298 LOUISVILLE RD","COXS CREEK","KY","40013",+1.00907000000000E+005,+2.43700000000000E+003,6,+3.79244650000000E+001,-8.54655340000000E+001 +48197,"Normen Huras","1028 HIGHLAND PARK DR","LEXINGTON","KY","40505",+2.72780000000000E+004,+2.29400000000000E+003,1,+3.80530380000000E+001,-8.44711030000000E+001 +48622,"Gene Mayer","407 N WILSON AVE","MOREHEAD","KY","40351",+7.27280000000000E+004,+2.08800000000000E+003,5,+3.81845160000000E+001,-8.34389390000000E+001 +48624,"Ping Kifer","917 MAYWICK DR","LEXINGTON","KY","40504",+9.45400000000000E+004,+1.95200000000000E+003,6,+3.80318210000000E+001,-8.45457170000000E+001 +48678,"Cindy Ryden","9207 MARSE HENRY DR","LOUISVILLE","KY","40299",+3.81840000000000E+004,+1.45600000000000E+003,4,+3.81818980000000E+001,-8.55901950000000E+001 +48744,"Ted Harris","10804 TURFLAND WAY","LOUISVILLE","KY","40241",+9.45410000000000E+004,+2.05300000000000E+003,6,, +48852,"Gene Carey","1035 ST HWY 1947","GRAYSON","KY","41143",+1.22720000000000E+005,+2.40100000000000E+003,7,+3.83437270000000E+001,-8.29767340000000E+001 +48933,"Normen Peterson","129 S 38TH ST","LOUISVILLE","KY","40212",+3.36320000000000E+004,+1.46900000000000E+003,3,+3.82628320000000E+001,-8.58117370000000E+001 +48935,"Mary Scott","2910 PETTY JAY RD","LOUISVILLE","KY","40220",+5.54540000000000E+004,+2.34000000000000E+003,3,+3.82054940000000E+001,-8.56135920000000E+001 +48936,"Samuel Smith","6105 KIRKWOOD CT","LOUISVILLE","KY","40229",+6.63650000000000E+004,+2.00600000000000E+003,5,+3.80891410000000E+001,-8.56513490000000E+001 +48938,"Roy Winer","2818 W MAIN ST","LOUISVILLE","KY","40212",+8.81870000000000E+004,+9.78000000000000E+002,8,+3.82614020000000E+001,-8.57977270000000E+001 +48939,"Keith McArthur","419 KENILWORTH RD","LOUISVILLE","KY","40206",+9.90980000000000E+004,+2.18300000000000E+003,6,+3.82625350000000E+001,-8.57060580000000E+001 +49124,"Jean Winer","3827 KLONDIKE LN","LOUISVILLE","KY","40218",+1.44545000000000E+005,+1.67500000000000E+003,8,+3.82065700000000E+001,-8.56366210000000E+001 +49271,"Daniel Harris","7510 MALLARD DR","LOUISVILLE","KY","40258",+1.11813000000000E+005,+3.13800000000000E+003,5,+3.81459680000000E+001,-8.58908070000000E+001 +49272,"Eileen Panwar","524 NAVAHO RD","SHELBYVILLE","KY","40065",+1.22724000000000E+005,+9.04000000000000E+002,8,+3.82246460000000E+001,-8.52431930000000E+001 +49391,"Cindy Ryden","12110 SAINT CLAIRE DR","LOUISVILLE","KY","40243",+1.11814000000000E+005,+3.23900000000000E+003,5,+3.82502250000000E+001,-8.55315850000000E+001 +49553,"Steven Peterson","1796 WILART DR","LOUISVILLE","KY","40210",+8.36380000000000E+004,+1.29300000000000E+003,7,+3.82192990000000E+001,-8.57931960000000E+001 +49556,"Mary Smith","12000 BARRICKS RD LOT 272B","LOUISVILLE","KY","40229",+1.16361000000000E+005,+8.23000000000000E+002,8,+3.81046270000000E+001,-8.57017330000000E+001 +49559,"Roy McArthur","2102 BOLLING AVE","LOUISVILLE","KY","40210",+1.49094000000000E+005,+9.99000000000000E+002,8,+3.82299120000000E+001,-8.57930030000000E+001 +49560,"Keith McKnight","1706 GARDINER LN","LOUISVILLE","KY","40205",+9.05000000000000E+002,+1.89700000000000E+003,1,+3.82041420000000E+001,-8.56883230000000E+001 +49561,"Jean Huras","3707 RIDGE RD","SHEPHERDSVILLE","KY","40165",+1.18160000000000E+004,+3.10200000000000E+003,1,+3.79960640000000E+001,-8.56193770000000E+001 +49612,"Michelle Harris","426 COLLEGE ST","ELIZABETHTOWN","KY","42701",+7.27280000000000E+004,+2.08800000000000E+003,5,+3.76926060000000E+001,-8.58701650000000E+001 +49886,"Lawrence Grandbois","737 STEPHENS RD","INDEPENDENCE","KY","41051",+1.16364000000000E+005,+1.12500000000000E+003,8,+3.89301850000000E+001,-8.45117100000000E+001 +49967,"Steven Chamberlin","312 PIN OAK DR","RICHMOND","KY","40475",+2.72760000000000E+004,+2.09300000000000E+003,1,+3.77589850000000E+001,-8.43035330000000E+001 +49968,"Normen Carey","5230 BETHEL RD","LEXINGTON","KY","40511",+3.81870000000000E+004,+1.75900000000000E+003,3,+3.81346670000000E+001,-8.45877490000000E+001 +50127,"Cindy Fuh","641 S WOODLAND DR","RADCLIFF","KY","40160",+1.27278000000000E+005,+2.63300000000000E+003,6,+3.78298680000000E+001,-8.59440760000000E+001 +50128,"Steven Jou","304 ESTATE DR","ELIZABETHTOWN","KY","42701",+1.38189000000000E+005,+3.99000000000000E+002,9,+3.77049060000000E+001,-8.58786990000000E+001 +50129,"Normen Li","4553 MILLERSTOWN RD","UPTON","KY","42784",+1.49090000000000E+005,+2.49600000000000E+003,7,+3.74524060000000E+001,-8.59727580000000E+001 +50159,"Jean Jou","226 S PETERSON AVE","LOUISVILLE","KY","40206",+1.49090000000000E+005,+2.49600000000000E+003,7,+3.82529800000000E+001,-8.56977560000000E+001 +50486,"Michelle Smith","106 DALE RD","HIGHLAND HEIGHTS","KY","41076",+1.16360000000000E+005,+7.22000000000000E+002,9,+3.90449270000000E+001,-8.44476530000000E+001 +50487,"Ping Wilson","429 DELL ST","ELSMERE","KY","41018",+1.27271000000000E+005,+1.92700000000000E+003,7,+3.90098400000000E+001,-8.46031830000000E+001 +50489,"Brian McArthur","237 PARK AVE","LUDLOW","KY","41016",+1.49093000000000E+005,+8.99000000000000E+002,9,+3.90862160000000E+001,-8.45553420000000E+001 +50490,"Daniel McKnight","512 HODGE ST","NEWPORT","KY","41071",+9.04000000000000E+002,+1.79600000000000E+003,1,+3.90815070000000E+001,-8.44966060000000E+001 +50491,"Eileen Huras","16 LEVASSOR AVE","COVINGTON","KY","41014",+1.18150000000000E+004,+3.00100000000000E+003,1,+3.90600590000000E+001,-8.45024630000000E+001 +50493,"Peter Swagerman","2520 S MAIN AVE","HIGHLAND HEIGHTS","KY","41076",+3.36370000000000E+004,+1.97300000000000E+003,2,+3.90380540000000E+001,-8.44567140000000E+001 +50496,"Steven Vance","28 REGIMENT CT","WILDER","KY","41076",+6.63610000000000E+004,+1.60300000000000E+003,6,+3.90412450000000E+001,-8.44742320000000E+001 +50497,"Normen Kleewein","260 PARK AVE","LUDLOW","KY","41016",+7.72720000000000E+004,+2.80900000000000E+003,4,+3.90858770000000E+001,-8.45547120000000E+001 +50500,"Samuel Jou","7002 NOB HILL DR","FORT THOMAS","KY","41075",+1.00905000000000E+005,+2.23500000000000E+003,6,+3.90853760000000E+001,-8.44714990000000E+001 +50647,"Michelle Vincent","945 SPRING ST # 47","COVINGTON","KY","41016",+7.72730000000000E+004,+1.00900000000000E+003,8,+3.90891120000000E+001,-8.45292400000000E+001 +50708,"Albert Huras","167 WINTERS LN","COLD SPRING","KY","41076",+8.81850000000000E+004,+7.76000000000000E+002,8,+3.90290340000000E+001,-8.44380700000000E+001 +50796,"Normen Smith","5105 STEWART DR","LOUISVILLE","KY","40216",+6.63640000000000E+004,+1.90600000000000E+003,5,+3.81687410000000E+001,-8.58335680000000E+001 +50903,"Brian Jou","10709 KAY DR","FAIRDALE","KY","40118",+8.36320000000000E+004,+2.58800000000000E+003,5,+3.80921740000000E+001,-8.57471440000000E+001 +51233,"Normen McArthur","615 BUSH LN","ELIZABETHTOWN","KY","42701",+8.36350000000000E+004,+2.89100000000000E+003,4,+3.76777300000000E+001,-8.58598040000000E+001 +51235,"Mary Huras","3685 MELROSE RD","SONORA","KY","42776",+1.05457000000000E+005,+1.86200000000000E+003,7,+3.75026060000000E+001,-8.59894380000000E+001 +51329,"Albert Vincent","624 COTTONWOOD DR","RADCLIFF","KY","40160",+1.49092000000000E+005,+2.69800000000000E+003,7,+3.78419350000000E+001,-8.59635100000000E+001 +51529,"Yun Grandbois","1826 OLD E TOWN RD","HODGENVILLE","KY","42748",+4.90940000000000E+004,+2.56100000000000E+003,2,+3.75894020000000E+001,-8.57487540000000E+001 +51564,"Grace Elliot","206 BURNAM CT","RICHMOND","KY","40475",+9.45490000000000E+004,+9.59000000000000E+002,8,+3.77516920000000E+001,-8.43048860000000E+001 +51590,"Michelle Lin","120 LANKFORD DR","GEORGETOWN","KY","40324",+5.09050000000000E+004,+1.11600000000000E+003,6,+3.82031060000000E+001,-8.45788320000000E+001 +51647,"Normen Jou","172 GEMINI TRL","GEORGETOWN","KY","40324",+2.72730000000000E+004,+1.79000000000000E+003,1,+3.82886800000000E+001,-8.45608550000000E+001 +51760,"Cindy McArthur","112 GEORGE ST","BEREA","KY","40403",+1.00907000000000E+005,+2.43700000000000E+003,6,+3.75729100000000E+001,-8.43081990000000E+001 +51796,"Gene Chamberlin","765 ZANDALE DR","LEXINGTON","KY","40502",+1.63640000000000E+004,+7.86000000000000E+002,2,+3.80010730000000E+001,-8.45025310000000E+001 +51831,"Normen Henderson","11703 LEEMONT DR","LOUISVILLE","KY","40272",+6.18190000000000E+004,+2.62400000000000E+003,3,+3.80845980000000E+001,-8.58679420000000E+001 +52267,"Steven Jou","156 LOUISE DR","FORT MITCHELL","KY","41017",+7.72790000000000E+004,+1.61400000000000E+003,6,+3.90308960000000E+001,-8.45513410000000E+001 +52270,"Mary Tran","253 N ASHBROOK CIR","LAKESIDE PARK","KY","41017",+1.00902000000000E+005,+1.93300000000000E+003,7,+3.90272560000000E+001,-8.45624900000000E+001 +52418,"Michelle Vance","3616 WILLOW SPG","LEXINGTON","KY","40509",+8.81820000000000E+004,+4.74000000000000E+002,9,+3.80000230000000E+001,-8.44086420000000E+001 +52662,"Samuel Vincent","492 SHEFFIELD DR","VERSAILLES","KY","40383",+1.22728000000000E+005,+1.30800000000000E+003,8,+3.80384010000000E+001,-8.47376170000000E+001 +52686,"Albert Scott","136 WINTERS LN","COLD SPRING","KY","41076",+6.63620000000000E+004,+1.70400000000000E+003,6,+3.90287310000000E+001,-8.44380290000000E+001 +52707,"Mary Grandbois","8709 BROWN AUSTIN RD","FAIRDALE","KY","40118",+1.27274000000000E+005,+2.22900000000000E+003,7,+3.81238050000000E+001,-8.57760550000000E+001 +52752,"Rajendra McArthur","449 PICKETT DR","COVINGTON","KY","41011",+1.22729000000000E+005,+1.40800000000000E+003,8,+3.90651100000000E+001,-8.45523440000000E+001 +52760,"Grace Kleewein","1823 HARRODSBURG RD","LAWRENCEBURG","KY","40342",+5.09070000000000E+004,+1.31800000000000E+003,6,+3.79843480000000E+001,-8.48782540000000E+001 +53123,"Albert Winer","168 3RD ST","ELIZABETHTOWN","KY","42701",+8.36340000000000E+004,+2.79000000000000E+003,4,+3.77656510000000E+001,-8.58920250000000E+001 +53210,"Steven Mayer","967 SAMUEL ST","LOUISVILLE","KY","40204",+5.09020000000000E+004,+8.14000000000000E+002,7,+3.82299920000000E+001,-8.57374320000000E+001 +53300,"Yun Elliot","3324 MOULTON LN","LOUISVILLE","KY","40218",+5.09030000000000E+004,+9.15000000000000E+002,7,+3.82053860000000E+001,-8.56711420000000E+001 +53431,"Ping Smith","6501 SKYLINE DR","LOUISVILLE","KY","40272",+1.18150000000000E+004,+3.00100000000000E+003,1,+3.81127710000000E+001,-8.58810770000000E+001 +53596,"Eileen Vance","1114 GARDEN CREEK CIR","LOUISVILLE","KY","40223",+1.63620000000000E+004,+5.85000000000000E+002,4,+3.82613430000000E+001,-8.55614150000000E+001 +53740,"Normen Scott","128 MCCLURE RD","WINCHESTER","KY","40391",+1.00907000000000E+005,+2.43700000000000E+003,6,+3.79823340000000E+001,-8.42088670000000E+001 +53802,"Daniel Scott","4633 PLEASANT HILL RD","UPTON","KY","42784",+1.22720000000000E+005,+2.40100000000000E+003,7,+3.74388430000000E+001,-8.59295300000000E+001 +53984,"Hsin Panwar","4900 WELLSWORTH AVE","LOUISVILLE","KY","40216",+1.44543000000000E+005,+1.47400000000000E+003,8,+3.81722760000000E+001,-8.58368640000000E+001 +54083,"Cindy Wilson","6705 OLD ZARING RD","CRESTWOOD","KY","40014",+8.36330000000000E+004,+2.68900000000000E+003,5,+3.83517280000000E+001,-8.55061430000000E+001 +54204,"Albert Kifer","3017 REDSTONE DR","BURLINGTON","KY","41005",+9.45460000000000E+004,+6.57000000000000E+002,8,+3.90200270000000E+001,-8.47281200000000E+001 +54205,"Roy Scott","305 LYTLE AVE","ELSMERE","KY","41018",+1.05457000000000E+005,+1.86200000000000E+003,7,+3.90083350000000E+001,-8.46081110000000E+001 +54206,"Keith Smith","2377 PETERSBURG RD","HEBRON","KY","41048",+1.16368000000000E+005,+1.52800000000000E+003,8,+3.90675000000000E+001,-8.47155840000000E+001 +54363,"Mary Winer","10502 SEDALIA CT","LOUISVILLE","KY","40272",+3.36360000000000E+004,+1.87200000000000E+003,2,+3.81025220000000E+001,-8.58336050000000E+001 +54516,"Eileen Smith","2468 LITTLE BEND RD","BATTLETOWN","KY","40104",+6.63610000000000E+004,+1.60300000000000E+003,6,+3.81058500000000E+001,-8.64242440000000E+001 +54622,"Ingrid Fuh","235 JACKSONVILLE RD","BAGDAD","KY","40003",+7.27280000000000E+004,+2.08800000000000E+003,5,+3.83015560000000E+001,-8.50427160000000E+001 +54730,"Rajendra Peterson","80 EDWARDS LN","BOSTON","KY","40107",+1.00907000000000E+005,+2.43700000000000E+003,6,+3.77887320000000E+001,-8.56750940000000E+001 +55424,"Roy Carey","608 DUVALL ST","LOUISVILLE","KY","40217",+1.44548000000000E+005,+1.97700000000000E+003,7,+3.82079100000000E+001,-8.57454850000000E+001 +55661,"Michelle Kifer","5 E 30TH ST","LATONIA","KY","41015",+1.11817000000000E+005,+1.64100000000000E+003,7,+3.90537880000000E+001,-8.45030760000000E+001 +55709,"Hsin Li","4704 BROOKSIDE WAY","LEXINGTON","KY","40515",+1.49096000000000E+005,+1.20100000000000E+003,8,+3.79496960000000E+001,-8.44903760000000E+001 +55733,"Brian Chamberlin","8407 ROBIN HILL DR","LOUISVILLE","KY","40291",+8.36300000000000E+004,+2.38700000000000E+003,5,+3.81366350000000E+001,-8.56061800000000E+001 +56157,"Mary Kifer","24 WINN AVE","WINCHESTER","KY","40391",+1.27278000000000E+005,+2.63300000000000E+003,6,+3.79971330000000E+001,-8.41741430000000E+001 +56276,"Keith Elliot","1713 DEERWOOD AVE","LOUISVILLE","KY","40205",+1.16368000000000E+005,+1.52800000000000E+003,8,+3.82263880000000E+001,-8.57102850000000E+001 +56277,"Jean Harris","8013 JUDGE BLVD","LOUISVILLE","KY","40219",+1.27279000000000E+005,+2.73300000000000E+003,6,+3.81349610000000E+001,-8.56691420000000E+001 +56634,"Peter Vance","474 GRANDVIEW RD","ALEXANDRIA","KY","41001",+9.45400000000000E+004,+1.95200000000000E+003,6,+3.89614270000000E+001,-8.43629350000000E+001 +56821,"Steven Kleewein","5319 STEPHAN DR","LOUISVILLE","KY","40258",+1.18190000000000E+004,+1.50400000000000E+003,1,+3.81274970000000E+001,-8.58570180000000E+001 +56844,"Steven McArthur","3514 RAMSGATE CT","LEXINGTON","KY","40503",+9.45420000000000E+004,+2.15400000000000E+003,6,+3.79881250000000E+001,-8.45568180000000E+001 +56886,"Ted Jou","303 FRANKLIN LN","ELIZABETHTOWN","KY","42701",+6.63640000000000E+004,+1.90600000000000E+003,5,+3.77050010000000E+001,-8.59200270000000E+001 +57058,"Keith Smith","622 ROGERS RD","LEXINGTON","KY","40505",+1.38188000000000E+005,+2.98000000000000E+002,9,+3.80876730000000E+001,-8.44537830000000E+001 +57290,"Ingrid Li","549 LONE OAK DR","LEXINGTON","KY","40503",+5.09020000000000E+004,+8.14000000000000E+002,7,+3.80239300000000E+001,-8.45298100000000E+001 +57350,"Steven Fuh","6302 PRICE LN","LOUISVILLE","KY","40229",+5.09030000000000E+004,+9.15000000000000E+002,7,+3.81044510000000E+001,-8.56450730000000E+001 +57496,"Jean McKnight","1174 CLINTONVILLE RD","PARIS","KY","40361",+1.63610000000000E+004,+4.84000000000000E+002,5,+3.81632190000000E+001,-8.42549320000000E+001 +57499,"Lawrence Swagerman","197 OLD COACH RD","NICHOLASVILLE","KY","40356",+4.90940000000000E+004,+2.56100000000000E+003,2,+3.79789250000000E+001,-8.45875180000000E+001 +57643,"Daniel Mayer","310 HIGH ST","ELIZABETHTOWN","KY","42701",+1.33639000000000E+005,+2.51300000000000E+003,7,+3.76971690000000E+001,-8.58582910000000E+001 +57644,"Eileen Peterson","616 GRAYSON ST","UPTON","KY","42784",+1.44540000000000E+005,+1.17100000000000E+003,8,+3.74638540000000E+001,-8.59012190000000E+001 +57650,"Normen McArthur","2403 HARRODS POINTE TRCE","LEXINGTON","KY","40514",+5.09060000000000E+004,+1.21700000000000E+003,6,+3.79854540000000E+001,-8.45882070000000E+001 +57668,"Ted Ryden","219 INDEPENDENCE CT","GEORGETOWN","KY","40324",+8.81840000000000E+004,+6.76000000000000E+002,8,+3.81872160000000E+001,-8.45566980000000E+001 +58062,"Cindy Henderson","8935 LEITCHFIELD RD","CECILIA","KY","42724",+1.22722000000000E+005,+7.03000000000000E+002,9,+3.76272260000000E+001,-8.59866890000000E+001 +58192,"Ping Lee","2045 REBEL RD","LEXINGTON","KY","40503",+7.27230000000000E+004,+1.58400000000000E+003,6,+3.80101150000000E+001,-8.45194640000000E+001 +58227,"Mary Wang","2111 OAKLAND AVE","COVINGTON","KY","41014",+1.27279000000000E+005,+2.73300000000000E+003,6,+3.90662280000000E+001,-8.44972130000000E+001 +58378,"Brian Lee","1095 CROOKED CREEK RD","IRVINE","KY","40336",+1.38181000000000E+005,+1.49300000000000E+003,8,+3.76496440000000E+001,-8.40503720000000E+001 +58480,"Mary Mayer","215 BROOKSHORE AVE","BOWLING GREEN","KY","42101",+1.00904000000000E+005,+2.13500000000000E+003,6,+3.69737390000000E+001,-8.64868240000000E+001 +58771,"Eileen Chamberlin","276 SAGUARO DR","LOUISVILLE","KY","40229",+1.18180000000000E+004,+1.40400000000000E+003,1,+3.80824320000000E+001,-8.56791840000000E+001 +58788,"Gene Harris","1025 CLAYBORNE RD","LOUISVILLE","KY","40214",+3.81850000000000E+004,+1.55700000000000E+003,3,+3.81426120000000E+001,-8.57824320000000E+001 +59119,"Yun Li","4061 PALMETTO DR","LEXINGTON","KY","40513",+4.90900000000000E+004,+2.15800000000000E+003,3,+3.80036980000000E+001,-8.45787410000000E+001 +59524,"Gene Tran","107 LAKEVIEW DR","ELIZABETHTOWN","KY","42701",+4.45490000000000E+004,+1.74000000000000E+003,4,+3.77206250000000E+001,-8.58608510000000E+001 +59525,"Michelle Lee","2730 BACON CREEK RD","BONNIEVILLE","KY","42713",+5.54500000000000E+004,+1.93700000000000E+003,4,+3.74028120000000E+001,-8.58445360000000E+001 +59616,"Gene Pan","4518 MERIDALE AVE","LOUISVILLE","KY","40214",+6.63620000000000E+004,+1.70400000000000E+003,6,+3.81886570000000E+001,-8.57626950000000E+001 +59623,"Ted Cody","92 REESE ST","IRVINE","KY","40336",+1.33639000000000E+005,+2.51300000000000E+003,7,+3.76992800000000E+001,-8.39888320000000E+001 +59862,"Albert Jou","219 HOLIDAY RD","WINCHESTER","KY","40391",+1.22720000000000E+005,+2.40100000000000E+003,7,+3.79922350000000E+001,-8.42000670000000E+001 +60111,"Normen Li","1499 VINTAGE CIR","LEXINGTON","KY","40517",+6.18120000000000E+004,+1.91800000000000E+003,5,+3.79691690000000E+001,-8.44768050000000E+001 +60257,"Ingrid Vincent","21 LANGVIEW DR","WILDER","KY","41076",+2.72790000000000E+004,+2.39500000000000E+003,1,+3.90369880000000E+001,-8.44750150000000E+001 +60665,"Mary Kleewein","1314 JONI DR","LOUISVILLE","KY","40216",+5.54510000000000E+004,+2.03800000000000E+003,4,+3.81817140000000E+001,-8.58016280000000E+001 +60916,"Normen Jou","3042 WICKLAND RD","LOUISVILLE","KY","40205",+1.63650000000000E+004,+8.87000000000000E+002,2,+3.82063620000000E+001,-8.56883800000000E+001 +60925,"Grace Cody","11 RIDGETRAIL CT","WILDER","KY","41076",+1.05454000000000E+005,+1.56000000000000E+003,7,+3.90413290000000E+001,-8.44719340000000E+001 +60929,"Ping Mayer","937 PHILADELPHIA ST","COVINGTON","KY","41011",+1.49098000000000E+005,+1.40200000000000E+003,8,+3.90784110000000E+001,-8.45186640000000E+001 +60947,"Ingrid Jou","419 HIGHWAY AVE","LUDLOW","KY","41016",+2.72760000000000E+004,+2.09300000000000E+003,1,+3.90896100000000E+001,-8.45392390000000E+001 +60968,"Keith McKnight","5046 NELSONVILLE RD","BOSTON","KY","40107",+8.81870000000000E+004,+9.78000000000000E+002,8,+3.77312150000000E+001,-8.56409250000000E+001 +61156,"Lawrence Vincent","185 FOREST PARK RD","LEXINGTON","KY","40503",+1.63670000000000E+004,+1.08900000000000E+003,1,+3.80275240000000E+001,-8.45137820000000E+001 +61201,"Grace Grandbois","308 E 2ND STREET","SILVER GROVE","KY","41085",+1.18130000000000E+004,+2.80000000000000E+003,1,+3.90325570000000E+001,-8.43846490000000E+001 +61218,"Samuel Vincent","607 ELM ST","LUDLOW","KY","41016",+3.81800000000000E+004,+1.05300000000000E+003,5,+3.90903870000000E+001,-8.45544070000000E+001 +61224,"Grace Henderson","1128 FOXFIRE RD","BARDSTOWN","KY","40004",+9.45460000000000E+004,+6.57000000000000E+002,8,+3.77605250000000E+001,-8.54971490000000E+001 +61258,"Yun Li","153 POPE ST","LOUISVILLE","KY","40206",+1.38180000000000E+005,+1.39200000000000E+003,8,+3.82556640000000E+001,-8.57171790000000E+001 +61638,"Grace Cody","370 CRESCENT AVE","WINCHESTER","KY","40391",+3.81840000000000E+004,+1.45600000000000E+003,4,+3.79847810000000E+001,-8.41831590000000E+001 +61927,"Steven Winer","9319 COOLRIDGE DR","LOUISVILLE","KY","40229",+7.72760000000000E+004,+1.31200000000000E+003,7,+3.81130140000000E+001,-8.56553720000000E+001 +61935,"Jean Vance","304 SUNNY ST","ELIZABETHTOWN","KY","42701",+5.45400000000000E+003,+1.22100000000000E+003,1,+3.76897500000000E+001,-8.58517900000000E+001 +61943,"Brian Lee","110 SUMMIT DR","CAMPBELLSVILLE","KY","42718",+8.36320000000000E+004,+2.58800000000000E+003,5,+3.73340320000000E+001,-8.53504490000000E+001 +61962,"Gene Vincent","517 W SOUTHERN AVE","COVINGTON","KY","41015",+1.22721000000000E+005,+6.02000000000000E+002,9,+3.90484210000000E+001,-8.45113330000000E+001 +62135,"Normen Elliot","457 STONE CREEK DR","LEXINGTON","KY","40503",+5.54560000000000E+004,+2.54200000000000E+003,3,+3.79821160000000E+001,-8.45470920000000E+001 +62460,"Samuel Chamberlin","1717 MARLOW RD","LOUISVILLE","KY","40216",+9.04000000000000E+002,+1.79600000000000E+003,1,+3.82099280000000E+001,-8.57948150000000E+001 +62472,"Brian Grandbois","201 HIGH ST","PARIS","KY","40361",+1.22726000000000E+005,+1.10600000000000E+003,8,+3.82144530000000E+001,-8.42493230000000E+001 +62630,"Michelle Cody","300 LAKE ST","NICHOLASVILLE","KY","40356",+5.09060000000000E+004,+1.21700000000000E+003,6,+3.78857060000000E+001,-8.45638510000000E+001 +62654,"Ping Pan","2573 STOVALL RD","LEBANON JUNCTION","KY","40150",+1.44540000000000E+005,+1.17100000000000E+003,8,+3.77552270000000E+001,-8.57406370000000E+001 +62725,"Brian Harris","1750 THATCHERS MILL RD","PARIS","KY","40361",+1.05452000000000E+005,+1.35800000000000E+003,8,+3.81384670000000E+001,-8.41141130000000E+001 +62800,"Cindy Swagerman","109 JOSIE TRL","GEORGETOWN","KY","40324",+1.00908000000000E+005,+2.53800000000000E+003,6,+3.82050310000000E+001,-8.45774970000000E+001 +63088,"Lawrence Pan","4901 GRANDVIEW DR","OWENSBORO","KY","42303",+1.38188000000000E+005,+2.98000000000000E+002,9,+3.77860650000000E+001,-8.70335030000000E+001 +63364,"Lawrence Fuh","5410 LAGOONA DR","LOUISVILLE","KY","40219",+4.45470000000000E+004,+1.53800000000000E+003,4,+3.81722890000000E+001,-8.56765770000000E+001 +63922,"Daniel Fuh","5905 STEWART RD","LEXINGTON","KY","40516",+7.27210000000000E+004,+1.38300000000000E+003,7,+3.80979680000000E+001,-8.43659340000000E+001 +64134,"Cindy Chamberlin","418 KAELIN DR","LOUISVILLE","KY","40207",+9.45450000000000E+004,+5.56000000000000E+002,9,+3.82664760000000E+001,-8.56420030000000E+001 +64179,"Yun Wang","117 JOSIE TRL","GEORGETOWN","KY","40324",+9.90900000000000E+004,+1.37700000000000E+003,7,+3.82051040000000E+001,-8.45774240000000E+001 +64180,"Cindy Cody","519 MAPLE ST","GEORGETOWN","KY","40324",+1.00901000000000E+005,+1.83200000000000E+003,7,+3.82174510000000E+001,-8.45543230000000E+001 +64455,"Yun Lin","105 WESTVIEW DR","BARDSTOWN","KY","40004",+5.45900000000000E+003,+1.72500000000000E+003,1,+3.78198350000000E+001,-8.54709360000000E+001 +64558,"Ingrid Kifer","438 FENTRESS LN","BEREA","KY","40403",+1.38183000000000E+005,+1.69400000000000E+003,8,+3.75493880000000E+001,-8.42901040000000E+001 +64821,"Ted Fuh","208 GHEENS AVE","LOUISVILLE","KY","40214",+6.18190000000000E+004,+2.62400000000000E+003,3,+3.81679110000000E+001,-8.57651250000000E+001 +65024,"Hsin Scott","1601 TRAVELLER RD","LEXINGTON","KY","40504",+1.44544000000000E+005,+1.57400000000000E+003,8,+3.80448260000000E+001,-8.45543860000000E+001 +65025,"Brian Smith","110 WESTGATE DR","LEXINGTON","KY","40504",+5.45500000000000E+003,+1.32200000000000E+003,1,+3.80485520000000E+001,-8.45383310000000E+001 +65125,"Normen Swagerman","146 CREST AVE","FLEMINGSBURG","KY","41041",+1.05456000000000E+005,+1.76100000000000E+003,7,+3.84297940000000E+001,-8.37361300000000E+001 +65147,"Steven Kifer","7540 3RD STREET RD","LOUISVILLE","KY","40214",+2.72780000000000E+004,+2.29400000000000E+003,1,+3.81411220000000E+001,-8.57807600000000E+001 +65258,"Ted Pan","720 MONTE LN","COVINGTON","KY","41011",+8.81800000000000E+004,+2.72000000000000E+002,9,+3.90583450000000E+001,-8.45154500000000E+001 +65259,"Peter Tran","904 TERRACE DR","PARK HILLS","KY","41011",+9.90910000000000E+004,+1.47800000000000E+003,7,+3.90699960000000E+001,-8.45336470000000E+001 +65346,"Hsin Kleewein","327 LUDFORD ST","LUDLOW","KY","41016",+6.63690000000000E+004,+5.10000000000000E+002,8,+3.90868270000000E+001,-8.45516590000000E+001 +65369,"Hsin McArthur","9801 LANESBORO WAY","LOUISVILLE","KY","40242",+1.49092000000000E+005,+2.69800000000000E+003,7,+3.82806340000000E+001,-8.55713250000000E+001 +65424,"Normen Mayer","3400 WINNLAND DR","LOUISVILLE","KY","40219",+9.45480000000000E+004,+8.58000000000000E+002,8,+3.81324520000000E+001,-8.57002720000000E+001 +65520,"Albert Scott","300 W VINE ST","LEXINGTON","KY","40507",+9.05000000000000E+002,+1.89700000000000E+003,1,+3.80474650000000E+001,-8.44997710000000E+001 +65587,"Mary McKnight","7 WATERSIDE WAY","COVINGTON","KY","41017",+7.72720000000000E+004,+2.80900000000000E+003,4,+3.89813910000000E+001,-8.45245730000000E+001 +65744,"Cindy Vincent","1810 FLEMING RD","LOUISVILLE","KY","40205",+1.44541000000000E+005,+1.27200000000000E+003,8,+3.82166820000000E+001,-8.56914780000000E+001 +65905,"Cindy Henderson","301 SAINT JOHN RD","ELIZABETHTOWN","KY","42701",+1.05454000000000E+005,+1.56000000000000E+003,7,+3.77030970000000E+001,-8.58730840000000E+001 +65907,"Normen Jou","241 SUNNYSIDE DR","MOUNT WASHINGTON","KY","40047",+1.27276000000000E+005,+2.43100000000000E+003,7,+3.80435430000000E+001,-8.55452960000000E+001 +65909,"Mary Pan","818 - 820 HOLMES ST","FRANKFORT","KY","40601",+1.49098000000000E+005,+1.40200000000000E+003,8,, +66123,"Grace Fuh","352 BERRY AVE","BELLEVUE","KY","41073",+3.36340000000000E+004,+1.67100000000000E+003,2,+3.91017760000000E+001,-8.44830050000000E+001 +66124,"Lawrence Jou","733 SEATTLE DR","LEXINGTON","KY","40503",+4.45450000000000E+004,+1.33700000000000E+003,5,+3.80141950000000E+001,-8.45489170000000E+001 +66589,"Brian Jou","904 TERRACE DR","PARK HILLS","KY","41011",+4.90940000000000E+004,+2.56100000000000E+003,2,+3.90699960000000E+001,-8.45336470000000E+001 +66721,"Grace Wang","80 DOE VALLEY DR","BRANDENBURG","KY","40108",+1.18180000000000E+004,+1.40400000000000E+003,1,+3.79921400000000E+001,-8.61060600000000E+001 +66980,"Brian Winer","1713 ABBINGTON HL","LEXINGTON","KY","40514",+5.09090000000000E+004,+1.51900000000000E+003,5,+3.79866920000000E+001,-8.45645990000000E+001 +66999,"Gene Ryden","2640 HARRIS FERRY RD","IRVINE","KY","40336",+9.90990000000000E+004,+2.28400000000000E+003,6,+3.78189610000000E+001,-8.41091000000000E+001 +67094,"Hsin Cody","311 BLUEGRASS AVE","SOUTHGATE","KY","41071",+1.44544000000000E+005,+1.57400000000000E+003,8,+3.90747890000000E+001,-8.44766040000000E+001 +67149,"Normen Pan","929 CHARLES ST","LOUISVILLE","KY","40204",+9.90900000000000E+004,+1.37700000000000E+003,7,+3.82316150000000E+001,-8.57377980000000E+001 +67169,"Yun Huras","221 ALGER AVE","LOUISVILLE","KY","40214",+1.49090000000000E+005,+2.49600000000000E+003,7,+3.81663390000000E+001,-8.57672350000000E+001 +67459,"Gene Pan","11905 BOYDTON CT","LOUISVILLE","KY","40245",+4.90930000000000E+004,+2.46000000000000E+003,2,+3.83118720000000E+001,-8.55305120000000E+001 +67660,"Roy Smith","14600 DOMINICK MICHAEL DR","LOUISVILLE","KY","40299",+1.00906000000000E+005,+2.33600000000000E+003,6,+3.82140410000000E+001,-8.54839180000000E+001 +67814,"Cindy Scott","43 GRANDVIEW AVE","NEWPORT","KY","41071",+1.44542000000000E+005,+1.37300000000000E+003,8,+3.90785920000000E+001,-8.44914010000000E+001 +68129,"Hsin McKnight","3101 BALSAM CT","EDGEWOOD","KY","41017",+1.49090000000000E+005,+2.49600000000000E+003,7,+3.90013010000000E+001,-8.45718110000000E+001 +68453,"Daniel Lee","3708 HILLSBORO RD","LOUISVILLE","KY","40207",+8.36370000000000E+004,+3.09200000000000E+003,4,+3.82390140000000E+001,-8.56484110000000E+001 +68671,"Albert Lin","24 LOCUST ST","ERLANGER","KY","41018",+1.18170000000000E+004,+3.20300000000000E+003,1,+3.90187270000000E+001,-8.45990180000000E+001 +68708,"Ted Harris","29 DOROTHY DR","HIGHLAND HEIGHTS","KY","41076",+8.81850000000000E+004,+7.76000000000000E+002,8,+3.90259370000000E+001,-8.44171630000000E+001 +68709,"Peter Panwar","100 DUNTREATH LN","CRESTVIEW HILLS","KY","41017",+9.90960000000000E+004,+1.98200000000000E+003,7,+3.90313800000000E+001,-8.45767600000000E+001 +68712,"Steven Kifer","1838 CONNER RD","HEBRON","KY","41048",+1.22729000000000E+005,+1.40800000000000E+003,8,+3.90580200000000E+001,-8.46957280000000E+001 +68715,"Mary Wilson","11996 BOWMAN RD","INDEPENDENCE","KY","41051",+5.45200000000000E+003,+2.92000000000000E+003,1,+3.88966510000000E+001,-8.45097670000000E+001 +68716,"Samuel Winer","27 MAPLE VALLEY LN","ALEXANDRIA","KY","41001",+1.63630000000000E+004,+6.86000000000000E+002,3,+3.89278080000000E+001,-8.43670270000000E+001 +68717,"Albert McArthur","211 HIGHLAND AVE","FORT MITCHELL","KY","41017",+2.72740000000000E+004,+1.89100000000000E+003,1,+3.90382990000000E+001,-8.45514080000000E+001 +68739,"Samuel Harris","2723 IOWA AVE","LATONIA","KY","41015",+9.90960000000000E+004,+1.98200000000000E+003,7,+3.90537130000000E+001,-8.45095620000000E+001 +68741,"Roy Mayer","2317 GRACE AVE","FT WRIGHT","KY","41017",+1.11818000000000E+005,+1.74200000000000E+003,7,+3.90461280000000E+001,-8.45717690000000E+001 +69020,"Ingrid Mayer","8500 CLAUDIA DR","LOUISVILLE","KY","40219",+5.09000000000000E+004,+2.51200000000000E+003,2,+3.81282290000000E+001,-8.56715260000000E+001 +69124,"Yun Swagerman","1050 RUSSELL CAVE RD","LEXINGTON","KY","40505",+4.45450000000000E+004,+1.33700000000000E+003,5,+3.80643380000000E+001,-8.44840380000000E+001 +69266,"Rajendra Harris","1590 MEADOW HILL CT","FLORENCE","KY","41042",+1.16368000000000E+005,+1.52800000000000E+003,8,+3.89994130000000E+001,-8.46803750000000E+001 +69343,"Grace Carey","2407 WOODMONT DR","LOUISVILLE","KY","40220",+1.33636000000000E+005,+2.21100000000000E+003,7,+3.82335700000000E+001,-8.56231370000000E+001 +69666,"Lawrence Wang","118 TROTTER WAY","WILMORE","KY","40390",+6.63620000000000E+004,+1.70400000000000E+003,6,+3.78858920000000E+001,-8.46876830000000E+001 +69702,"Normen Mayer","1100 HORSEMANS LN APT 33","LEXINGTON","KY","40504",+1.22729000000000E+005,+1.40800000000000E+003,8,+3.80422130000000E+001,-8.45244790000000E+001 +69826,"Grace Mayer","43 PARK AVE","WINCHESTER","KY","40391",+1.63640000000000E+004,+7.86000000000000E+002,2,+3.79919740000000E+001,-8.41688790000000E+001 +69884,"Cindy Cody","1020 FISHER LN","ELIZABETHTOWN","KY","42701",+1.44542000000000E+005,+1.37300000000000E+003,8,+3.77251960000000E+001,-8.58460750000000E+001 +69916,"Jean Elliot","910 LORRAINE CT","COVINGTON","KY","41011",+1.63650000000000E+004,+8.87000000000000E+002,2,+3.90575310000000E+001,-8.45196050000000E+001 +70191,"Keith Grandbois","360 RUSSELL FLYNN RD","CRITTENDEN","KY","41030",+6.18120000000000E+004,+1.91800000000000E+003,5,+3.87516650000000E+001,-8.45453130000000E+001 +70507,"Normen Panwar","125 WESTWIND TRL","BARDSTOWN","KY","40004",+7.72720000000000E+004,+2.80900000000000E+003,4,+3.78186140000000E+001,-8.54695780000000E+001 +70564,"Gene Ryden","2404 HEATON CT","LEXINGTON","KY","40509",+4.45490000000000E+004,+1.74000000000000E+003,4,+3.80177760000000E+001,-8.44520190000000E+001 +70577,"Rajendra McArthur","4123 BEITING DR","ALEXANDRIA","KY","41001",+2.72720000000000E+004,+1.68900000000000E+003,1,+3.89564380000000E+001,-8.43739560000000E+001 +70780,"Yun Grandbois","2601 PROCTOR KNOTT DR","LOUISVILLE","KY","40218",+1.00907000000000E+005,+2.43700000000000E+003,6,+3.82094210000000E+001,-8.56590620000000E+001 +70803,"Yun Henderson","29 PANORAMA DR","ALEXANDRIA","KY","41001",+3.36310000000000E+004,+1.36800000000000E+003,3,+3.89730140000000E+001,-8.43948360000000E+001 +70804,"Cindy Fuh","10 - 12 WOODLAND HILL DRIVE","SOUTHGATE","KY","41071",+4.45420000000000E+004,+1.03400000000000E+003,6,, +70897,"Steven Fuh","300 WESTWOOD DR","LOUISVILLE","KY","40243",+7.72760000000000E+004,+1.31200000000000E+003,7,+3.82405460000000E+001,-8.55312840000000E+001 +71132,"Albert Smith","102 WESTWOOD DR","ELIZABETHTOWN","KY","42701",+2.27230000000000E+004,+2.36500000000000E+003,1,+3.77077450000000E+001,-8.58780780000000E+001 +71133,"Roy Wilson","404 N MAIN ST","ELIZABETHTOWN","KY","42701",+3.36340000000000E+004,+1.67100000000000E+003,2,+3.76971830000000E+001,-8.58536900000000E+001 +71556,"Hsin Ryden","7795 LAWRENCEBURG RD","CHAPLIN","KY","40012",+6.63610000000000E+004,+1.60300000000000E+003,6,+3.79153400000000E+001,-8.51917890000000E+001 +71583,"Ted Tran","228 E 4TH ST","LEXINGTON","KY","40508",+3.36380000000000E+004,+2.07400000000000E+003,1,+3.80485310000000E+001,-8.44880400000000E+001 +71866,"Mary Ryden","533 GRAYSON ST","UPTON","KY","42784",+1.63640000000000E+004,+7.86000000000000E+002,2,+3.74639770000000E+001,-8.58976850000000E+001 +71868,"Albert Cody","1121 HIGH ST","BRANDENBURG","KY","40108",+3.81860000000000E+004,+1.65800000000000E+003,3,+3.79985810000000E+001,-8.61745850000000E+001 +71869,"Roy Elliot","1153 S JACKSON HWY","HARDYVILLE","KY","42746",+4.90970000000000E+004,+9.63000000000000E+002,7,+3.72491610000000E+001,-8.57919690000000E+001 +71872,"Ingrid Mayer","5680 HARDYVILLE RD","HARDYVILLE","KY","42746",+7.27200000000000E+004,+1.28200000000000E+003,7,+3.72284150000000E+001,-8.56826770000000E+001 +72007,"Roy Swagerman","104 DIXON AVE","ELIZABETHTOWN","KY","42701",+7.72770000000000E+004,+1.41300000000000E+003,7,+3.76856710000000E+001,-8.58684470000000E+001 +72093,"Steven Smith","3501 SUSANNA DR","LOUISVILLE","KY","40213",+3.36330000000000E+004,+1.57000000000000E+003,2,+3.81701790000000E+001,-8.56966210000000E+001 +72479,"Eileen Jou","115 E 15TH ST","COVINGTON","KY","41011",+1.49093000000000E+005,+8.99000000000000E+002,9,+3.90739270000000E+001,-8.45055400000000E+001 +72480,"Ted Li","14 MARTIN ST","COVINGTON","KY","41011",+9.04000000000000E+002,+1.79600000000000E+003,1,+3.90746790000000E+001,-8.45072980000000E+001 +72540,"Grace Fuh","5467 COUNTRY HILLS LN","UNION","KY","41091",+9.05000000000000E+002,+1.89700000000000E+003,1,+3.89381600000000E+001,-8.48040790000000E+001 +72817,"Lawrence Kleewein","7718 CARNATION DR","LOUISVILLE","KY","40258",+7.72750000000000E+004,+1.21100000000000E+003,7,+3.81431370000000E+001,-8.58605940000000E+001 +72928,"Keith Kifer","35 RETREAT ST","SOUTHGATE","KY","41071",+1.38187000000000E+005,+1.97000000000000E+002,9,+3.90697780000000E+001,-8.44717410000000E+001 +73075,"Brian Ryden","3400 MARY JO BLVD","BARDSTOWN","KY","40004",+1.05455000000000E+005,+1.66000000000000E+003,7,+3.78441980000000E+001,-8.54453540000000E+001 +73305,"Brian McArthur","11707 WETHERBY AVE","LOUISVILLE","KY","40243",+5.45800000000000E+003,+1.62400000000000E+003,1,+3.82505190000000E+001,-8.55378080000000E+001 +73306,"Daniel McKnight","4314 SPRINGDALE RD","LOUISVILLE","KY","40241",+1.63690000000000E+004,+1.29000000000000E+003,1,+3.83060400000000E+001,-8.55784400000000E+001 +73484,"Lawrence Mayer","7086 WILDWOOD CIR APT 95","LOUISVILLE","KY","40291",+1.44548000000000E+005,+1.97700000000000E+003,7,+3.81758560000000E+001,-8.56235420000000E+001 +73630,"Ted Lee","25 CARLA CT","FRANKFORT","KY","40601",+1.00906000000000E+005,+2.33600000000000E+003,6,+3.81697660000000E+001,-8.49311360000000E+001 +73635,"Normen Cody","415 GARRARD ST","COVINGTON","KY","41011",+5.45100000000000E+003,+2.81900000000000E+003,1,+3.90872990000000E+001,-8.45058350000000E+001 +73822,"Samuel Elliot","2705 RIEDLING DR","LOUISVILLE","KY","40206",+7.27200000000000E+004,+1.28200000000000E+003,7,+3.82622770000000E+001,-8.56955080000000E+001 +74022,"Peter Swagerman","8613 SHENANDOAH DR","PEWEE VALLEY","KY","40056",+1.22722000000000E+005,+7.03000000000000E+002,9,+3.82985020000000E+001,-8.54748220000000E+001 +74463,"Normen Jou","389 NORTH WEST STREET","MUNFONDVILLE","KY","42765",+3.36370000000000E+004,+1.97300000000000E+003,2,+3.72702930000000E+001,-8.58932520000000E+001 +74903,"Samuel Grandbois","6157 FOX RUN LN","FLORENCE","KY","41042",+8.36320000000000E+004,+2.58800000000000E+003,5,+3.89997070000000E+001,-8.46816880000000E+001 +75704,"Steven Li","13710 BOAT DOCK RD","UNION","KY","41091",+1.44541000000000E+005,+1.27200000000000E+003,8,+3.88616230000000E+001,-8.47707010000000E+001 +75764,"Ping Fuh","105 RIDGEMONT AVE","COVINGTON","KY","41011",+1.44541000000000E+005,+1.27200000000000E+003,8,+3.90573710000000E+001,-8.45293860000000E+001 +75842,"Steven Kifer","501 HILLROSE DR","LOUISVILLE","KY","40243",+2.27200000000000E+004,+2.06300000000000E+003,1,+3.82347890000000E+001,-8.55355520000000E+001 +75900,"Gene Harris","516 COLLIER CT","LEXINGTON","KY","40505",+9.09000000000000E+002,+2.30000000000000E+003,1,+3.80591960000000E+001,-8.44552510000000E+001 +76190,"Mary Huras","1930 RUTHERFORD AVE","LOUISVILLE","KY","40205",+5.09010000000000E+004,+7.13000000000000E+002,7,+3.82247010000000E+001,-8.56985710000000E+001 +76318,"Brian Carey","209 POPLAR DR","ELIZABETHTOWN","KY","42701",+1.38181000000000E+005,+1.49300000000000E+003,8,+3.76988420000000E+001,-8.58622930000000E+001 +76322,"Peter Fuh","326 ATLANTIC AVE","OAK GROVE","KY","42262",+2.27250000000000E+004,+6.67000000000000E+002,5,+3.66573880000000E+001,-8.74095510000000E+001 +76403,"Ingrid Wilson","1703 COLONY CT","LOUISVILLE","KY","40216",+8.36370000000000E+004,+3.09200000000000E+003,4,+3.81761850000000E+001,-8.58170530000000E+001 +76606,"Albert Lee","740 WILSON CREEK RD","COXS CREEK","KY","40013",+1.63620000000000E+004,+5.85000000000000E+002,4,+3.78901350000000E+001,-8.55724560000000E+001 +76608,"Keith Grandbois","549 NEWMAN WAY","MOUNT WASHINGTON","KY","40047",+3.81840000000000E+004,+1.45600000000000E+003,4,+3.80417240000000E+001,-8.55692110000000E+001 +76700,"Keith Lin","1373 CORONA DR","LEXINGTON","KY","40514",+5.09070000000000E+004,+1.31800000000000E+003,6,+3.79816270000000E+001,-8.45690870000000E+001 +76865,"Lawrence Kifer","473 GRANDVIEW RD","ALEXANDRIA","KY","41001",+5.54530000000000E+004,+2.24000000000000E+003,3,+3.89613140000000E+001,-8.43606420000000E+001 +77205,"Roy Peterson","5641 NEW CUT RD","LOUISVILLE","KY","40214",+5.45700000000000E+003,+1.52300000000000E+003,1,+3.81392500000000E+001,-8.57737690000000E+001 +77315,"Normen Jou","6601 BILSIM LN","LOUISVILLE","KY","40291",+5.54580000000000E+004,+2.74300000000000E+003,2,+3.81505300000000E+001,-8.55955440000000E+001 +77514,"Brian Mayer","221 BOTTO AVE","ELIZABETHTOWN","KY","42701",+9.45490000000000E+004,+9.59000000000000E+002,8,+3.77213140000000E+001,-8.58188910000000E+001 +77541,"Peter Cody","670 BLACKBURN RD","IRVINE","KY","40336",+6.18160000000000E+004,+2.32100000000000E+003,4,+3.77121990000000E+001,-8.40347990000000E+001 +77748,"Peter Fuh","410 S WINN AVE","IRVINE","KY","40336",+3.81850000000000E+004,+1.55700000000000E+003,3,+3.76733110000000E+001,-8.40071730000000E+001 +78332,"Roy Chamberlin","1003 HIGHLAND PARK DR","LEXINGTON","KY","40505",+2.27250000000000E+004,+6.67000000000000E+002,5,+3.80533340000000E+001,-8.44715190000000E+001 +78404,"Ingrid Lee","138 GEORGIA AVE","MOUNT WASHINGTON","KY","40047",+1.44548000000000E+005,+1.97700000000000E+003,7,+3.80532080000000E+001,-8.55519250000000E+001 +78417,"Cindy Smith","738 GRAYSON ST","UPTON","KY","42784",+1.27271000000000E+005,+1.92700000000000E+003,7,+3.74634050000000E+001,-8.59053010000000E+001 +78715,"Yun Lin","417 WALNUT ST","GEORGETOWN","KY","40324",+1.05452000000000E+005,+1.35800000000000E+003,8,+3.82166290000000E+001,-8.45554120000000E+001 +78757,"Daniel Scott","631 IROQUOIS AVE","LOUISVILLE","KY","40214",+7.72740000000000E+004,+1.11000000000000E+003,7,+3.81695180000000E+001,-8.57754410000000E+001 +79222,"Cindy Scott","265 HARPER DR","HORSE CAVE","KY","42749",+7.27240000000000E+004,+1.68500000000000E+003,6,+3.71762250000000E+001,-8.58843770000000E+001 +79226,"Mary McArthur","337 RED MILL RD","ELIZABETHTOWN","KY","42701",+1.16368000000000E+005,+1.52800000000000E+003,8,+3.76322960000000E+001,-8.57998950000000E+001 +79227,"Samuel McKnight","503 E MAIN ST","VINE GROVE","KY","40175",+1.27279000000000E+005,+2.73300000000000E+003,6,+3.78088470000000E+001,-8.59750720000000E+001 +79235,"Gene Henderson","495 GRAND AVE","TAYLOR MILL","KY","41015",+5.54570000000000E+004,+2.64300000000000E+003,2,+3.90338890000000E+001,-8.45037820000000E+001 +79334,"Ted Lee","3620 DELL RD","LOUISVILLE","KY","40299",+1.44547000000000E+005,+1.87700000000000E+003,8,+3.81931390000000E+001,-8.55711760000000E+001 +79683,"Steven Panwar","25 CONN DR","WILMORE","KY","40390",+3.36390000000000E+004,+2.17400000000000E+003,1,+3.78238690000000E+001,-8.47197030000000E+001 +79755,"Mary Huras","305 CENTRAL AVE","ELIZABETHTOWN","KY","42701",+5.45200000000000E+003,+2.92000000000000E+003,1,+3.76949060000000E+001,-8.58538710000000E+001 +79756,"Samuel Vincent","519 VILLAGE DR","ELIZABETHTOWN","KY","42701",+1.63630000000000E+004,+6.86000000000000E+002,3,+3.77096050000000E+001,-8.58650520000000E+001 +79757,"Albert Swagerman","527 VILLAGE DR","ELIZABETHTOWN","KY","42701",+2.72740000000000E+004,+1.89100000000000E+003,1,+3.77101270000000E+001,-8.58649120000000E+001 +80441,"Cindy Carey","406 DIECKS DR","ELIZABETHTOWN","KY","42701",+1.11815000000000E+005,+1.44000000000000E+003,8,+3.77083360000000E+001,-8.58652480000000E+001 +80442,"Steven Vance","1405 S JACKSON HWY","HARDYVILLE","KY","42746",+1.22726000000000E+005,+1.10600000000000E+003,8,+3.72479200000000E+001,-8.57927670000000E+001 +80463,"Yun Smith","1064 HUDSON AVE","LEXINGTON","KY","40511",+3.36370000000000E+004,+1.97300000000000E+003,2,+3.80895000000000E+001,-8.45069040000000E+001 +80615,"Gene Peterson","3800 HAPGOOD LN","LEXINGTON","KY","40514",+5.54510000000000E+004,+2.03800000000000E+003,4,+3.79986390000000E+001,-8.45707450000000E+001 +80654,"Albert Huras","11009 ALBION DR","LOUISVILLE","KY","40272",+1.44540000000000E+005,+1.17100000000000E+003,8,+3.80959640000000E+001,-8.58658820000000E+001 +80707,"Gene Mayer","106 W RAINBOW WAY","ELIZABETHTOWN","KY","42701",+7.72740000000000E+004,+1.11000000000000E+003,7,+3.76560800000000E+001,-8.58658190000000E+001 +80708,"Michelle Peterson","11726 SCHMIDT LN","WALTON","KY","41094",+8.81850000000000E+004,+7.76000000000000E+002,8,+3.89016000000000E+001,-8.46434270000000E+001 +141009,"Michelle Carey","11132 WELLS LN","LAWRENCEBURG","KY","40342",+1.50099000000000E+005,+2.00300000000000E+003,8,, +146805,"Michelle Chamberlin","11597 PLEASANT HILL RD","UPTON","KY","42784",+5.64530000000000E+004,+2.74000000000000E+003,3,, +166999,"Michelle Ryden","11640 HARRIS FERRY RD","IRVINE","KY","40336",+1.00099000000000E+005,+2.78400000000000E+003,6,, +167459,"Michelle Pan","111905 BOYDTON CT","LOUISVILLE","KY","40245",+5.00930000000000E+004,+2.96000000000000E+003,2,, diff --git a/extenders/spatial/data/cityLimits.dbf b/extenders/spatial/data/cityLimits.dbf new file mode 100644 index 0000000000000000000000000000000000000000..766b04d21060f9c6fc9eec6c61cedbc989baa491 GIT binary patch literal 4672 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≪=0)`A>O%RGvST=U3(V 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�My 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 AK>z>% literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/cityLimits.shx b/extenders/spatial/data/cityLimits.shx new file mode 100644 index 0000000000000000000000000000000000000000..f1d0c64340683d2f80b705cd07a747044de78124 GIT binary patch literal 556 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 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/floodzones.shx b/extenders/spatial/data/floodzones.shx new file mode 100644 index 0000000000000000000000000000000000000000..a33e52fdadba1d282483d3c7f8807dc527b23684 GIT binary patch literal 404 zcmZQzQ0HR64oWyD_G^Yu8Sjf z?I@x~K%N5-mjST{5FY|!2L=X4HYn`{q$7a*WkA{jNI!yzGpRxNOi4g`1_J}rKZrQ9 z6O?X)$TJ^;(jfT&1_qWOh&;0%4nlKiLFqIoy$DL*gV3B(P&y1sPlD3tKr{dc9xh1$ literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/offices.dbf b/extenders/spatial/data/offices.dbf new file mode 100644 index 0000000000000000000000000000000000000000..a32287db0d9c2f64d8e64148d165f64933ca8743 GIT binary patch literal 1339 zcmZuxJ#X7E5Eam^MS;#8(%U+ zy#>ymzlXUjO7R2>y|X2BR_b;PZmLcBTw(37*N8<9;xI*{;L0FAI`k0ni338&Wc639 z(3V!$>dVX>O_+nQ} zn-)C=u}32pq&BD?utx$2ou`akFjA<^pa6i#^^J{Ts;O_kO8q3Z9YHp7F3=P#%IX>A zzC$@|yoRtCe&BkIW~)_Wy-$vLyJHEdp{rNz zwI$YF8=|Crl}D$B49DE_l!Wi_rBWL^tTpsXNZ?i#_y_6HAEwA%8J<$#YDsc%O&7n@ kJ#a4ofeLqO={~oavVVVSYdMO{%l&)^4#1}+q!JI zB^OwZ4JJ2n`QEwR!RC%TU06#bzJTS}VRF09r=?eMSva2GKI_%BG&_))956YX-wzcR zC)+xPA7wvx_7hkiCrs|kEn%s1N%oFw_a?pEYzuZLD15gTsXfCI<`uMM0+Z7x=(#;f2YCzIlEhDRoM`3WehDlm29x{sTBgG8 ztA(TE2F}A>kT?>D$#E>6;*r18!cof8PKezaY@Y;7&gf&x`o{Mbjs{hiyGv(+&6I@6 zwWvCO2)tCAbP#@S#X_(vz(*>$lGwdAGMIW54 z0y+sOE(4Q$DO9{9PsPsBjL$LNyapWBvM{;o7t7YWPBMe%Eugp@Ozz-z>+@V~c8)n) fr~0jO2Ae4llRLBHrG1I0jbp~Ie|E=TIyeFVR`T)4 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/offices.shx b/extenders/spatial/data/offices.shx new file mode 100644 index 0000000000000000000000000000000000000000..75ec7b861b8f4813f275e6318d767adb8c070180 GIT binary patch literal 348 zcmZQzQ0HR64%WS3W?*0h%JDdD0MCz1eCr8q5)0=AL;-A literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/regions.dbf b/extenders/spatial/data/regions.dbf new file mode 100644 index 0000000000000000000000000000000000000000..90fd678173f0e0394c535ad2b73eb649a08c1d9f GIT binary patch literal 337 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 F|35@coM-?5 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/regions.shx b/extenders/spatial/data/regions.shx new file mode 100644 index 0000000000000000000000000000000000000000..82c5679e7875b2079d7fcf2a7046ac2f7ed886d0 GIT binary patch literal 124 zcmZQzQ0HR64(whqGcd3M<%FbWN=j=hI&y8A7V(?k%JIm(+26&Vxi|($7p1QYadE`1 Z9YxfLfq|m|h_^8?uxBtZ2q*#B3;+o?54QjS literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/salezones.dbf b/extenders/spatial/data/salezones.dbf new file mode 100644 index 0000000000000000000000000000000000000000..b9dfe7afc7bfadb71bb83bcb5e98a08e76853b01 GIT binary patch literal 722 zcmaisy$*s<3`QGVjET|N$wvTxVI*<~2hixi$mV3tY^lLAp3wf@T5((5(2WG ztU+F`2TyIWoBOjoyJwsqxR+lQUa7$h%v?Nb=ONVcu82svoBP`r_2*^bX5oWHjeU)M_~w>A@2l)!EFP zdi3F|jq62e&qSw3Z_vx6%B&uzB1Or=>RDbXW`fPN4K`bZt+;9DI1K*)#f1Iwz4EgM zw6q=jx+H?@^(iXhJhW`)Jt(Zj43M_JF7AL0;*C+klnnug&_ z`s#CQcY~|x^EEUx3fjVoqT`rV_CwfWv&HZe?T6%MphvSy^m<=-xtQ2Dv=s3z!Ub{&d5>B;$2uSyeg?H0~1_wzqIEOo$co=NqkNswAvNko($5ptm{{8OwRDo;xrkUe%X6S(J?q==N4l@=XR@S@D z0!!Sx#a22GaE+b)OgiKnR>scF!ha{PCD(%|CH4Y#ZkhwFZRNm0=(YUaX1-W6*-D-> z)j@dA(nWQm1kN literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/salezones.shx b/extenders/spatial/data/salezones.shx new file mode 100644 index 0000000000000000000000000000000000000000..72db51858a4267ec2b20656748c2ef2a5dfa2f6b GIT binary patch literal 180 zcmZQzQ0HR64x(N#Gcd3Mwwq+hz|iVkk7~m;WGw7`SXBu08soBkWOM?V2XgqGtGg>Gra)P5daV9 B8L$8V literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/sjCensusBlocks.dbf b/extenders/spatial/data/sjCensusBlocks.dbf new file mode 100644 index 0000000000000000000000000000000000000000..94ee192a9dc5d46283f3214ade52d8620b7592c0 GIT binary patch literal 28046 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 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/sjCensusBlocks.prj b/extenders/spatial/data/sjCensusBlocks.prj new file mode 100644 index 0000000..747df58 --- /dev/null +++ b/extenders/spatial/data/sjCensusBlocks.prj @@ -0,0 +1 @@ +GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] \ No newline at end of file diff --git a/extenders/spatial/data/sjCensusBlocks.shp b/extenders/spatial/data/sjCensusBlocks.shp new file mode 100644 index 0000000000000000000000000000000000000000..b1816bf80720ba94e2c6bfc022022228b808c600 GIT binary patch literal 81580 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≪|W%XAdbH>j|7iZrw`Q;pa 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 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/sjCensusBlocks.shx b/extenders/spatial/data/sjCensusBlocks.shx new file mode 100644 index 0000000000000000000000000000000000000000..aabdddcbbe8e075cffed2e954f4fe603487a96c7 GIT binary patch literal 2012 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 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/sjMainStreets.prj b/extenders/spatial/data/sjMainStreets.prj new file mode 100644 index 0000000..247496e --- /dev/null +++ b/extenders/spatial/data/sjMainStreets.prj @@ -0,0 +1 @@ +GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] diff --git a/extenders/spatial/data/sjMainStreets.shp b/extenders/spatial/data/sjMainStreets.shp new file mode 100644 index 0000000000000000000000000000000000000000..37a2609dbe293dbe8e57df0ad7bacaa0a435b3d0 GIT binary patch literal 71188 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 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/sjMainStreets.shx b/extenders/spatial/data/sjMainStreets.shx new file mode 100644 index 0000000000000000000000000000000000000000..9d15dbbfbf1e5f2fb25edf569a9924f652afd547 GIT binary patch literal 4004 zcmZvcPfXNz8i(K7F5M*+E$Xb;d4rJE@F&>EFK-@W)hJ$H1kcMPEn1&b*r0aofJdl0fyzga`8p-45 z{quR>@B33lwin8;{(64)@v|cQmWh`C{4GD&eD95a{d3LMzsG`#g^6uHcQ)VayZzVI z|GpawezpDogB8dGKi}~a@H5NLW07a3;g2G#Mqn*`2&sFvn%riQ=bF*PpSuNzM1E6A zJS|c%hVBq~J_L8bn6usTznw=v7Wv(MJgI*{=T|}U>i5DFyeqQ0%i^o=zyQ4ruZtAv zKKK^te#%AT8lAUCWKA8!Z%qy+;3F7_tc^hG*EYZuoOG>u`d-xj04ANI9-oEmRa^?` zFIInLm*tD~{hD94_`0y^b^0EB*Ns8;S@+QL>kBQvz6r)f)@wh0>*wH*$c7fv8}xe+ z-=O#49ib3pPRR2i%?D`RFD z+w&0L9eNM;+M(|mfDa-0oxa~r_uHv{apIGZzOrK20do-FU8?EZ6@~ci()VWIvgzFw zFeS3v=kM0}X_42$Q#-Z_Z0Bm`Qw|qANe_A7Nh{rh!)_TGQT;`?=8TBJG&Z^9Lr z5P3^A^>2OW%)<_m1C^!^s6TTL=)LcX9Mt!aKX~8b2cJOZM#~|7(P4;RblRzT`rp>~ zDC;2gZ|Cg(fz}fbCL#Ur6q|l03IlW&UKfdJKRVU|sgLQtw?+OG!{>XEKhL4#B7Z4^ zzlhXmeHyAi^J;Y8|BAeur+zc1T|f_ryw?Wtdr#k&f_h)->nbf?=kw}xp2lb3U6J?M zU;Ey_0}~=26hY>Hp!Iv8`ej5u)b|9i2~z)I);Zyvhtwa^e)5N^ovqFh=d^Rt_)*9i zgB>CtO}c&r16GNcjyJg0eV7y1{h1SAHr9tNU+?qkeO|rJqrU!$u|fUN4f^+mcQwqJ z{e|i2FW`zE7j>Qzg=<_r$L;59x1Qf`P~<70xb;e=_EL;MDI!eUthH zQ0K*=-=}HO@}GvBG0416`<+wHWy>eRFyIsF`|(M5KB0NypH)NVeWrP(-X{TdUv#p> zS>rqhc~^2AGB^3i;)jbMeTQ{l`VL=n<{|ZmeV-#?t2?6m)`}dNvHX!0NZ;pWray0X zJ?whg^&(_$bHsGB-kWzd>pse-Fc3K!h4>w9gUmlV>UzfY3S{3@(&DL{#ZyzR7mUY> zo$hzc{f@ccG4*4gmI8=hOA8F3?!)_9opmKvg=vvfQPZdNJ;YDx_hQ~DeUEDW zUfeTX2k}kkES~m#(mF2?`63L5;DqJB(D(d9q|NKwv>u<+1(rWu0hx2U74n|bd5Urv$5JF1=PN4{gs^#jPBovSR~>G$kx^Z2OMbGK6ny$^HFH#>(RKIf-lLZqt%)Uz`<|BE4r|HV4jUCuG5-}|D!r&r$-i1hmWUY$>W?~K*= zE<^V0bH6_K>r+4K`sS>zf0eV`>G$c^`%u?EYh?tfMN i>A!j(2K-l42y0=JYkluyk#BPr|5opl5E<6@{`5c1yB3T9 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/sjZipCodes.dbf b/extenders/spatial/data/sjZipCodes.dbf new file mode 100644 index 0000000000000000000000000000000000000000..c3d43c9b8ec5f3ed90ea698967471936c067e630 GIT binary patch literal 13250 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

X9_&)3sdHF@71^zoZN=u_f2E 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%0AZ&l?-G(u~X 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 z zS*H#gdibq|99O$qR$6*4L!9z%+&}$10H?lAyA&bz9>-6y{U|gPA=y(SyB{`r+ql%nGmM1 zcMOTu18iajz|0u^-K@?wkup>fv7u9HT~6D-4ibA>|2veCU?kv_IuSvci3qKqVJ3)d zd0kjM^7@8Y+%`5k7&eOLlx_KprsEldvUKQgcDULCtz|;nang<*BUaMD8q3!OAE!0} zW-%YL0a4=@6dGQe=Erq5U%hJ38$;_sz_SJ|%$DwRspmz6HT34W>B);FzH9p_K0xIA zi(#NwRzNEM@q`a-e?C$8oL1j}gD03XJb;@$T%SHNn9PjWp^NrdL8YgXgEB|tkk0db z1Zr+(Gdr=%V62x;q~P3EWl6ekLd)(r2&RWZ_||X0fnUJ@J6_>M~ z2w-&irV)AQ$Ywu!gf^4^7#KmW(R10JjL{0UH{^E{7DZ$=6r2B?XtaAzc>z=i(e`2d zu;ujHLU&)J-Tv_r$+J&yJ;{9M3{#$UWBj?HCJ_9dF`kCL!{Y(w zB3LCzJSZN=iM`XU=DCX z7Bhb`(pRX2BZQO?B_4oAI2)jkQW1kyDNSlL{n~|^s?E}*Ut2Ri#=9?92P@m{c6Xl> z+r2qDS*Y8%lS{i>&9vP5fg=06&*Y&tUHP9`If~`{O$@KWI14){ZtK!R{;!Z5e1rZ? zLK#l_g<+z|QYKI>?r&xre)o0dL7+sTohX=Y)i-@KPV#w9 z&uWdLVy)+R0_KJ^JCYfI&jtJuLN=iozCvvy_u3JLR7avK>RSl5Jb{Md48B)_EIQ$zevgSf z(bwxeYoqFU*`%OX!G$)Unuw*3Z zP7k*iPjR}^md8!A#AgLgCAq<%6>x!^JYJwoB`2*JG@B5FH}SoDVl`|+Y*3yZ%J_7c zQ^jt@8{74k0E#KvZh^M!XDDMsi0R|;cl&&@RqsJ{cL8poBRx}S$PBO}Kd2ICYLQt? zW5`U^m{+d?DL^@k@2&5Lb^RTQ6tMcmU)Eeh$?*8I#{9)Xj4P+Chfs>vX?|}28c}Mk zE9Nbf1e^e%Qw^r;nRi3QwVqhvnQ)#a)3d!z<@1Iyvk^9~Q>|J3+NY_+YPAn6M zGO}R^OsZ9m^_|@m@oKq&9SHax!kmg+^0>aTJQC*!B!jV%1m4%()8JZ*DCe%CrBeua z*M%I2KRIDGD?tCwWvhsShxLfVQxGfeDJ{`&AP6N~DyGmUR!&>JW}O*UwV`&)L13iB zJgQi-NQH;8yH;FdT!vhnAQAk~2M&L(5%vQcXZW4*1E2CS<8)@4pVO@Z18sT@5WD+F zFx95!R#dw?0+vw;mG*exwyR!?v!&c>f!=StriKgr1NW()u(>2O(VaU1Fl@F!EK(<8 z74(Hs$SLM){;+&=i^*_*>*XNee^cYcBb14o#Ww7yRjoBFiHJx7G()E+TXGKq7W~5= z!k@CL=i#I1D`00~SfY89$QSktjKxNE&&+K;H!imBf`X7f(_wYoV4Sl{lg?MJYpWy_K(pY;?tLE{oA z9uDkXAas~}jE5y3J&j^BE<@cyk{kGPN#40=JeQ~Ht_s%hB6-526K%g@!`kjgp|84- zJ|W$|?ZoWgJJNVVxrcYwVn%53IPG(aVEtnkVoDLN-&km6ynZJWhqGliVBmLGCCNgk3*pzx=3}Y@nY0_%( z%-;SAu{t03rBoJ@%%szXP{x_8ozc?C^cAL(%p-4$rXIH0boy+F1G>XX&yQ;}A-X7*(WP zU-;@aA+>Opt2b$X>tXfn7yZ$(ElSN_xsrdVR(ZTr+k92)uM`l`At)04;p?@EDzT5# zq4*C0^#;e+n|fE{DFsAs9bcU8=b1XuIAL9>)7{{et+G6<-Mz7!*nKCV=Vqd9Uy43Y zJ1u|yexDm@r_gxvaByf{T&AW5**0fO3A(QUdPqQQ<8EoOe}Ch;-T9tKy(Ho5RpN6c z`Ay(Ix5=+f&P31gv4?`x?Wm-0qime!bzOni)pn#b@GX7EM%4oy53Q}Gc?olU7nhfR zKQ1fs+r4rHwy)^MIF+1JY^)VwD?j_n(2uwJO~a$ZVC)nZyOCUOXfKs8<6>^L5B$l< ztlIt=>Y0>6kG*Bd=nz{foiojWnw#rN!R9s{`xK48DA;PrEfR~xxugSPPZxErW0Q?( z7I5O!&Q^0=gnFlixBW$K(hF7mcnC1|LsPgAdBzmVjtQRDi7n`*pfmsCcAF6%C{JiM z=aRnG`$LQZl85qu@z1@q;7nL0=VC7v0SUO)&?YlgUKc|X4z^I_rfpFFX(j| z-j-=xTO{wdLSKx$NbWb~szd@5+r7I9SJZ44Ua(>F${u-Wjj_u}ILz32v-U@ywX)Nx zPp)ccf$coB>`CqwOlPmG?$bmihrwr}dsn1c$6=aByI?4AFAdX}Kd%==wo0RX-z{(Hu@@;@@R ze-r*IW0N(swEIuKHpBDnyw#e-U&Z{5ub}6gq@9^`bDFhTwA(~V`ViYUs-$;z>vR?< zAz>t(=mTIfHgoLXrwafg8QGk=d10+J_O`8iO@|ge!nEhN^l9gwE`!9RC!1bK;xr&J zeLH?dkwZ^{`3a3yO+;1@EG5KA%tWXxmKHOoDKLmp$sxXIIXvz-Ud#}-=Zq#TG=6LM zyJg?|UG{o-M^fr6Muat|u5h2TcTVdXkw1(iCU>iBk#t>rO>@k|Mf4NoG*IHs)w}Kc za(P1E>dwaXx1FY^nHll}PBtN#VZQw>TS5})EB2L|04b3|^M{~{r2t7Jx`_ihW{=9tt~rF&hAWxDi*!1L zQvMc1CX-YF9yF8k1hKXZ^e4Z@2tN>kqS?)11me#^0pd~PiG{16gd@=eF9QOKG1?<3 zv{tYQq}N0cZdDc*7or$zJXGbc~m2VuX`|&d}x|O=<~m)cy23ncUF8=%dvc zXPj_x3&BirdZIB=NQ}84rU6dHB7q9SdgL_Mb!fZX~Z3+IS>;)R9*&f z6Tc?Huidl1-|#!%-yW}hU0r=&ckz4fQb#tLv`^eQ`;GC__JWq?B0 zpf8V=M`FZ9RnX-7l{#7+!e~ly3YZzrQWq8H^Mu(rHQ^<|*rpHi$x@pJ3+rgpasH1D0KYgtI`1gwSt~dQ2;b(Q%hQ7Xoun*^gu%& zMtV|Tfb5h}Yw%frUDx9SFjEMpVKt0rX*fmRlrT!XeWrh`&MKz@d5)}}jdPz;Vo-5)S>4!QH<}?*y%>H& zhl-3pQ$2M8E$z>vb~r2b=2J$s8mn02m31#%+}*(pO>xi-6#&HG6kuGM>7c0C-6TmV z2B)^EpAIN{US~w&Yf#YIJTWH*}tE|ghs1;Y#8VH^6 zW@RU#BaCY_iWsfXI0LzgU&Gk}M(9-yj?#zNkSK0=a{(-P3~(5}=%N%bs>^C?qSD^l z9aF+VbTGi$%Dv>AH$>FIY^pDEdl~!ryU;04#O=Ld9|z@VmBOPH`(qaw)d=yqUD^|2NNQ_>BZqXO_7(gX^ z1gk}D)SgvhZ^|E2k_2Q;6C1TT4QN-^F(uHDOJbajij_4*YyMdB`U(5Rhz}b}iGPS8 zX*_yVHFlHkEA%z4bQ;w95y}N&6^ffjwt@y1AE{xomvj+HK|O*C*Oxc`HJm`z@z<1k z+S4y!j5^PrMt~7y5Vk4%Y_(MsbV#$1b{h^+?1mU5uWYMmuOH=&6$tKY%m)8 zX$En#qr^xdKz|2%09bQLeJmZy0dhwSNF@OBL@*);xho!Xr0ZoQ-;cwPZ*wM$DLpxK zC0Cs&ly0v*^tz*nT(KEngGX68DE4LH17WCq1>`&uI+g>+Ty zig_$DE8dDy$r=o}LF=~llu%ILnXo`_yRqYIAsIg3j3jE~#*Xyq>%x!m$IS1>aoB84O$29MfG zL631-V4oLe7ZpRNre!tArDUM1oZA+^hqi{lK^OcyxfxQ6N4m}JcP-xIzA(R& zRq0`?ilvN#pWHYF)h^lV5A`)hyR^*q9frQ+@!q|4mD^Vk@B#Sd`t|hQamOoyzXnrf zr;_gzKDvnfe6**&YlSQ?)FBCUcje4O@cH{_=1ZN7L?FTnt%(8H6 z*Rpn348otGZd-|h?N!-t;J8UNpc#D?DKY1$&0ER&0*}D$zwKIIj zE}7)PI%cq6118@9w-roXwS7%}sU0_TV`|y$dLfuL@Y7ora>M>4RW4_^%hUBN^4PZR z$)KbZT1Rf(=NC_2)a&^hf6Om2VG0woiaoj}V*bHPdQ_giOSRGRSbXP*&VOZDE4ZD$B zI$u(dCZC+c2O;zaT*VQUbym4Js|3s%TwZfaog<1L8=lnJ%69DEU(=c4$>31i+!AVE zoNJ5iygFMgrhPNTW*5||HrT2b#s*b8nD!&9|5?23&3xc1?crece`C^i4~G6~pDM)4K9llUcZ$U)@qO z!b>y4^-W)Eck#Dou92o2@QknSGb330W_jhs(YAu^!g~mFsEq($R;Ar!ld?}P4F%S0 z;m(_$RdUkHvJ;BTsZTp92+!*0nC-FT?hE4cQrvt8*@sUln$q?dbA09V!&*t_nKnPr zfQ3dsbzl>Y7ucM&pl(v@%9RgTAGW$q(*D+;FPe%%S+7Jr@$U-6FEC2o0V zIce+pIA5ljFPE=uDFfeKGUZD7;aZDHhy9m{(}RLvj>ZvMI`4jX?*4_86pSyp-cr1| zPbTLjurG?X{`zt(a}M{wo$9b|Um`vf+KkSpqoA@sRUw}Rhu2+o?h^d>rOSB3N0Bh- zuq=j+pgm?L(cBC=;Z0>7y-PKAx;Z~+ktI|KRhE>6Oex#-&6P=q(fSrxFE;GNT~m>* z_HWJMGf*f}6lhW!=%?z(pjNj(sY)|?)@}_i3J6Ii5WLZS^f^n1DVk5*S@^*OXKY2( zyFBl4w5>&CYqO3$3m7M;z;p+?jN``pd2TU2mm9<6-(oL0OrT7&J5V7<67WdafCc$9 zI}Y8>0hhh+nb)0zi60J~GQ_E~)+kR-E4wOH#v72gMEOm?81C8;vJ4z%zbOtbR$Al* zI+}ZU!EUMcZiNl^niTYn7nXWqVja;+;THB&p44^1cBq)6iS>_*ih42}nDr|LphvLq zyFGYWzZiv0b~7a4>BDdD05ZoCYW~Ss-s85F8*%oeZ-O8-b>&oGx>Xm*KR6B?`5C=>Av)uOVJ_^HP4SV|*n7}Et93Jt7OXR`n5H-DPc%hbsERtzIZq2O*@&Dy89Hh{NRXG0 zc0OJYVa=n(O$!D_?JmKNM7Dtp3MKZMs0&02f!RDpB}j?UfW$|O&5AxBlr05m+$4F4 zQ_zcti!B<4ZNp97oljR=3!t3*c`&}u$VL<)$fl=u3emBxLQI=0 z3dr|uR|>*S(DJ<$Hm#^Td8~*%tJv#Lh9!JOA#k}VcB^$*&zKq}p=DI=e^IPeh#Mtp z{vJ9h={;PGc)0Kq*1#@A(5K4E+2^LXHHP2yrL`zv=^Mgf9TNs0T4*DXIK=(58|tne zZ~{hSKp2iDn<~oZ(z?-d`P*_dKDy^_NBGP_@tH9x{`lIu>z!!cw36a&_OG3ddJ+j)o?`-}Zd%a0*3^PhShE}^2@Lzs~PY( zi|=2h^bMvdrU&L<<@67Z%IRA*s5h1g>aG*goGT$L9?(4WSFl;jsE4dQ$A{>V9Sk_+ zZ!2JgXE`4{saBzc(q~Y}BS`mm)WD^jyhS;uAmM@o3$gGnW?vk#{$O9{jSlwPSXTTM z=5HI6$dzMhfDcP$rjyylTewv-5MT1c#ctKU&Vsu@y;9J7xN|L~f_CSwfE#t4uPJG= zS%lKjC+qOiIcZ*bl%up6@FGbDl~;QjS%I3p$HFm#7)?sX_g^`!5FI;z&e-{6B)YN+u2F>$@89b@2U5X_g3Am>8Yve>6)tUnYDVl`}Ra_G`{lnrA_qx4oG2;H-{ZCfdE-<~t5rIxsudi(U0%JLOqz6{Svg1bJYM#ot9NYk z@`l5=4_dws2XFuW-~nLd)|BdTB~r=((nprmD`Ad$dlCsPz)!VAJc zmIEp(fS{@>>+66Z>RKR}K^p*|D$)KR!M!0cQPEgrSiQLdNQg6Yv$H_(3-hZh6)T$& zEL-b3Bru0CP?S(dFk}$t5Tsz|M<*a>_b^~`41X|qF#fQPd`dYv_9=y8;=oa3k%9z@ zLY2y~d5p>7iMx`(DHTio=^F{VNkvjq7m^InZ$bJu1oa1{Us|^uis?tZzF2PLcM@UJ zWCThYEdr*cn{NW#Vgqdp7k;vbJ7n25z~+NhKQt7FhMhe3rqr(<2_G3SCHaWhi}U>( zkgR-%7z`Cc#s}1-1o-2^BfZoZmIlV>1o2%;+82u_kRVckTy3Pb0SCUPN0-u4muU

sGZk!AUUlb*e`IT{HT;EdM#?0Hyocs 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

w*9!sKOc32vIcKw07C8mzweafRO+ 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

xfE$nzp|Z?oh@F^ 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

A$}S zDebi4SF=Jj!q$O#cJ(~Uq_7*2|M&kP$Muih~VpL0t_Ve#Qo#RntS2|z- z0K$m>?|?~Qqr-{%(tW9XN$A|-|mVuEB} zIpt|%T07lhc5AUzIrY-iM>Bb$QG3vAnO=Ndsj&Xj^0V7GwdDo)`2Fo|dh<+T!=SC<#* zGri+zS$UQ1PbHQq7?oO(bOE_x1noq2POchcIDWfhWCYMV2UF0Pv_iX+)Z;Ku$V$1f zrb7J_(|koy(;A;qMcmz!x!!!$mY?%gkf=YQNw{cX0KYWi-Bap^nUoOW*6>r-Mvk=3v2gZN>QWmN@~s-dty zKFzC!!ZlA7db%6~Xvk7Tz=D}nS0@V*lxc^A_XR$4MsA^S3;Zh8egO4_K9*PCN2)8- zK^(J;tLxJq3tNL2HX9Bi?tmgK3y0U1^-^Bdri?S=CKv0ptj&WU(xxITDb=A&;?3`b zb8h)X5`vlb%dn~V?@Lq}PxhiUu5Hjf%98F#8$)%jZHPS7s&}Le$%?HWfD zHwm255FL$LX^L_?8hHgf^D13F#ub4wb0J*dEc%eoM4%Doh_Onze;wikoWoJHwA%^@ znl{oEm*&U!(EzlY`s@b3O2)>we5&-^}$V&)iSE< z<)T&Dg|)RY+>i1s2~X!8CddmJlZa@hRIbywsAoQ3Nq3sZM!H_!#h`OHrRMZO7GjkU zl>aW;>pT_7K1){TUX}PX?Fz{)G6B>Irs5%T_oCnLazD}I=woJF{NkaJR0z;ol_pmZ z#lkyX40^DthP$_&eUrd7&+!3tf)x4wS13x{tr?x}Rxr8fZc2pk!H+{IiD_+&4ep zhPovk=z{D{G&wdSjo$j|Ebd3}Pq+=u)~d66L{rhrfs%uY`?&AVb^h<%-|MfqPT$#> zjoidb)Kd^R-rP0KFirt>h)! zp_m+w*=dI@FfTZ==KDEgJl4%&9~?MEXw=xV+kL>OYPJ#rL_vshoIg8R+Jmj1Cvh3^n^Px+Z>|9Dz(c+zEd} zWu#FJRnbTaBIgSt7e&x~=ZDcp(S;KnoKRyQ@7#0zJ~UM{RMB|nhl%HhF$$n^&kP%k z9_Pzvrq{C$_qAt$|2n6exG>EQzwc+$NprA$x>tmjhPQXteM7*uxp!>Klx?vq%DFh? z(^h9YJ2?539zeJlzFw_6RCSm)M@n67M*v(-4RcQpHV!WqQVA_fVNL{JSi{YlWXTxP z}3>)^|D62LKV#^s;3RRwfEg!6r8Z@Vq zyKjN9z}G(B4M#aiRI#_IV^5*Lrb1Fi5=mIrpbJCRA^`@~8s8tI=s9%3F50vr1@8I? z!(9$-Hy31H3bQ>5vyF4hGVh%2W4)6O<#W%d%hAGT#~^_f#ZU(M6zn2z(A|g{F}EH5 zdkc*Ns+boptnZqG3FFakqb zp&{*%uy$AkU_3+(7^_{!`@t8#iA2C>c)pAM>!=G3*!e^yJynJLHxSj3Mq{l50&v_{ zd!)jImoj{CvK0feaKD#Cc(L9V1Om|@g&P4?^UGYS^y8E5Cx9OJ+|b;k(!Mr*8=ErE z`SFP57_W44&$HP2)y*X7Zn=}2gI)t+9JC%<-xv$)(Ng@PBzYZ|I>yGr!_wZ0mW64s zw_DtQMKFJ8)qT94vy(g*G_|0gjZN4WoHF!Bl}86E3<0UniF!ym{YX#ZNm>V`bKN0-_MF0X05HSf%lysq`QhDQHVKX^i~bKs z?3XR?0I@^jF+R^XvLB3bz#&^F+vUmM-W)9{OVzv;$};$3cf(EK2k`lTE^@}<$r0-d zp=@%^E??Bz3<^-kDj8Ry8|y@#xX!gB_AwnBNA4qA)^@HVTviT1#{!ufi1t*O8<_T3 z8QFj&>%>pN8?(euAzb}LFu|9NBY`+2>j(X@()A;PxX_Iw<*`9)N6aJV%q&2UHW^$% zjz!Ygpf9dWZpa7oOmEI3>P&9X2lY&D*a!DaZomiOOm2t=3|5UjwslfD|16_KCxX*; zW4t48%CIpdf=`qII1*@p2(f?S)#Q$gNQ(p;!_?o4hx$2n5E zpsq2}P<*=j@#DDEjU$t|N^3`!BhAb%Y{zaHTfeRa(%OKo5z<_^cfrgq)CbN?Z-yhj zwIeA4J=?@uzpfopJ&?idN+6@RnjCG7pi(S%- ztb62ZtAf&o&*Ix6GrVx_0U@32`-Z`#!sn3kV`Z|hZGEQW0~U@Z%p8alAMXU-r^ z?cJef>{X&R+P-J>8neR>f*K}=Z{$^rf2t6XwR=ZguxobrIT2TL?PZ3a_1a*Ep4GIy zN^gyUSKYM>9isb}al~6yy@(hI{g)M-Ayls&JECg-n5_nuV)ad0ouSsbAl2K(ev;3*<5}H7T<6W6 zJ6MWL+F6i&hpqI^;eOCvn~Z?sL^p4cYT(}kEzAR%Z&4H(4R>a=F#l7N_%-T;Z^Jk0 zuWcdcpsh~@7l_^)-etkl=7mINU4S0aGKw3M2^IThdIQ4%DLbB7*15#$z*k5RT{qMLz!;G0Q#2Cl<@i_g## zdE|mDagN?F;Pr%#&*#T)kq>vS^Z}k%cu^p?CX(xj_YnoQaLOH_=|Nql@6W3%NaOp8 zJ1N4g6!3!wUu0wJffFuR6ey^CVFs}^tJs!Xj8@=|1QVdHowh%-He4)y>2{w*9?*On zwJ+m6qbljQ8X&U-q6-Dd3K(!!N+sRHkPYd}vnnD`5ma_5FCSTzE^Mhs$i-~}8`wGdV=sRje4-QC|VKLcJ)piL1$s;*O1<;S=CIVsTFg+Z3mWRUMOF{2OMum6+{5dEzc_0^T67HGGw7P=?a)(<+e1 z&rTlKg;FLsbA;tyWrAKU*pg)YY|=- z19@_=94j_&CrcvGomd`E#)v&~W{*KRs4i>zunZeeV-V>KF-QE;195xAYz`+&hRdDt z`h>zc&gl$iMg;wI9*!Mv#F2LtxVfL5xa5&JXDWDZrU}GdfVj^G{0@e(4~{6h$)vAQ zKk5#T3?r@@Jr2fRiOU#((WS+-Zy8=@IKx*n^65j2DpEHv`JG=um}_k4%6Y989pOfx z$hlOg@L&Pp8lN?AEi;SO3dLi97Jv5Hp_NnTgaR{IhrbYubN9*_qw);V6;Q|4c2g># z38(JdIxRQ!Bg`FD)f<+c4=ZgJ&qu%%Vp8qToOJo1{1v%?9br2!im z9-u`5$8ggP?s{=;2eMv@JuDd&>bKN%CrIUu7kg*|V9Zu2glHdM6?E^;%*37ZUrT<= zzmbgAPtmU4bqDBI4xsqswo1L zO@pWy8xx2`YE?SMxv|Z?@Z_~16KH_PF8uF?dEONAJ=o-W{$o9e@!h!bJ}87#O(;wIarPp<_KcJ9}7X;C4l|Z=xSLc7|xXQx4uxUhk^1$9(s~J5x$+^C7;r zf4(XBe_g|W=+?M43;rq>@(GB#7Dil&0%VrV;av&iZP_NB-5zmezT=uliKE&zP0*vC zJ&J=YnXB**+({MzSvFDP8<@u+D@Cg^kU(n@YKa%_2)0lT9>-@FC?sC#nv_LdAxCEz zZzkmvHz+Y%CTy2NBN4Lb7m}`jPwYio!$)Tb!I29^X_vc}?MAcgLN48cTx|M%`0#)G z=Ka7&pNiEf@ktJMWuH92YL3Jz;PA<&Iw0vxPdBBzE$DPbX1KHQ^n0C|>_~;aK_r=d zo>}=OU>vJJ-<}ftVvg|*7QTBJAEDWl$%W^kF^M-#2ffGy} z=L;g6#nN9Njna2A>!iadCTnDsO(l`wwolVs*biY;a?-%Ms5=(PN(prfd_judW9IyF z4&Mu?!{rxvBr3kyC^L$YNA3z`KjdFipF_pscs}P4#UOf+tq65lL9UwF-m_||nd}Y_ z&g}TA#9!}kJ7s#@LTjW)hf79n2-Xie{0?OekuT}%*%tpG6?_QiLkh*@!28gNyoUQa z3X(}X{nghh_4@k_p~P@MXTS_StbrXdFz=|YbgUv{1N1bMtH>Nt!2W{?`~@m<)JiVU zD^z)_p#AMPa3z+c#aGDwi6HQURPx9qbF60#lA(uY-hQ;86kWotlQ*2dz4!$!nh?e) zpJb_!6jPv#Y_0%)fQo&#G0?7vQ&C?BG-IX$&j(eOfR8J`hhu(l%3_h*oY>NF?xgeoR^uR&2f z9IxoDDrw z|51sKuF@8x>-fvE2 z)d^_CP!W%=~+2thjWC77tI~B&!)5X!V zV}29>1MV^a)h?z+{Ws754{jbg3{Y#@r!}F^(6^Za*irs((ZHk*eGi6-KX%U0k8KLT zrvBfOmf=xFvr!)*y*>ka-5+RjFks3)zhZrU6m)rD&?UwA`Ycl{7iEJbrRsV9R7@)K zz5W>>8Fc2A-U8Vq}3hP|+yMTF0+qfV1U&8c(GsdLb&bJPn9>joRPZlX;Y zIqpZD_o>>lW}Hjjg{n-#-1LH+bRfa#t2h@4FLsf}8}gxN|nGxstuTsNG%T-d*e7*QDjM!&;GzjLGC1EJp&q2D8+&jW#W2l;QsiR|E@*g(KLe}H#@ zfMEjx?E(SC`uyDfMg4w-`h5)adpz`eJ~1r3d+vuqxYpi7=Od$I?0Wcz-YyGKkHyA) zqc~Z{DQ8iMgc$Y_fe}pa-l6B;e&^rf5F>O)EI%evycF?Ahs!9QRd0urN=qHSBK*I0 z%N@RzD?B%4F5jxvUfQc2ypwrAUu}ge&sq-NTMCyS)tayWmN;(yw+!Q|jWoNL=iHZM zaL6(f)P+gr!bWr+zYz(B#mKztyoAEkjFOdydG$(ga*DlzsdK@^lv~HfwQ$FGN``;8LUihjAV+NZBdCvvyt%*pd%F4_+A>z;ijj z52ifbp9?0rh>ul%4vDW*gy)2Qc7N^uHrVx7P8`583IGdHIbVw_qzR4y|m zr&2lvLT=eh&n{;xk~(ssH-_bx$8$O)E)uZY#fqz&`JI9nAMDPL!86WfsFJPfp|r#< zwxKoJ7o1$qlSMO!b1G6gXrZ?4OT!$_Fp8_o`J3b}_psa3IA^L7I)cKfFH@=!vR)?= zYeTy_?omDL{)r5IcM+8*@7YO^IjM?G9Fg27*!JGECTWl64IZ#u6x6D>;<5kCK zQ^#9|EBBM8JiWo6g{Hv0b~Sr&)5+f0uVhmy=uehEf0v~7-v9*uhw`fbh9Z!xre%+%hVc_a=w)MZNZM08 zB%77OT2C@6naCW>*+x7A((0Nu(jTWNx$>~Fqr6a2sj^+fZ_(bwTuhrJr3HD6OHOw# zZ4^5Wos?=C!sdQ}kV8Ior|E9^_R}ri&^2M=+GO^6_4nuZv-j6A=I5z*_Zznl-nWvV z#NKXY#;hvc+jKsQ0tHQabSla8I!eV}rd0ok5$UALq^-q?Jd;JLc(6nPeG<(H^8hk) z215=rJxd{NR(d9jsj()+H2B9n`0|&2~L`7NbFjJ$sguysU9K|BwK}EF6oh}#AzdK+~a0VgNV(BJ*5jQ z(ZQ|1fbNyW&kguy*sM@}DjQD+pFJ@m(hw&iDh&mV#blD_RHB zl@fZZDUHUEU#aDq()v027o2$k;Llu9OkzPpG^N#t9?&5>$$cgw z9hS+-N1NyN)IH?!i)f{|1^nbt*10Jf&@1xHnfsqyqqcC8tHsR0Kb6jwFu7`HF)K7r zJ_4f}b@wguQt+kS(N>l7p{fVt7v>^@z=3>-jMg13*;EkoKY`Rv6CkS-nJnKc5`<*cxESGvb}NCGAk8T_CCCS0{sU6Y%zx5L5KF zrK&C$vh{FUW<&5635|(Xq}`prw^Z*S!+>-J?sZ1#DLwpr6KK;55sPn@;kB0>(p$ZU z;ii-0Te=T8lTNW@+u(_w0h!N{LNbTogE+}OGas}m_%-9~35Ux6fnUo|F1zx~Nst%z z98h-cpTbg<>Rq{~Di0V+(s6AliJQb>{zzjYt~hj?djtK+a33b_c6W}J@bEHP@QQ_M z+~Jycyei_3HR@`8q#0Cju$HXOJH(NzihMP-Ye3uXy6gdH*>jDF!1`2`e0Eo4n6Q3D zrcpEm9_>_`T#MHo)`6@PAGU|kK~kIdGPTD@7udPc=^y>Qiz#i$Ud`##=W+mgwciSb zy&Bco${T)z)w9so&VfBZ(%u$;6TJg46LcCUU#+V?rfi4j}Q6eKb$K?NvbR86;-TBxOVT{(vYlc-E92aiKQch>U}wiuHI63HT7OPj|%JTLh2VG zw#UCF3GpoI&*B$V!aj|mafxNorj#Grd7p^ttW;H6D#lbXW}pvBpwAnpK)JhihDzLs z!Q0_N%L>Xxr~8MaPJR!LLYc$4gaEIEj&(1D?$6ZnUyHuUNL)Gx4)tZ@b6241P`7&A z9X+CbA1Y3Dv`c~SXse$cfTc-5@}JlU@@z5g(e+Vq%X3UlMGDdD%`YD}j9Q)k1ZlPU z4~thg(QDwAxxb8$zr&pGek(sZfxWE(zsur;BS3_l<|omw@p1cz%;jSh6ur=VMdiPB zXkV$fcq?gVWohn6d=Ula46DTlJ z@0HT41FM;FHNCH@;H>pzzz{`J{E&cT1p*;dxE!xBN}VRAjJ zbvZ10H$Mxt!0Ov+T1N%9SY)0nfzdHemJ|>O4?6SYk!h)NtKN12KL*)x7Y5IP2O>}) zSPE^i)K8&T=&VOf7Ys}(zk1?=Pi|#8^_qAVV4!+ex2q|2}dO5mjlHH8zdsY-@M7}}K3^B!; z>3Feyj-d}k21OqkSU1&Q*YpAvx_L2Nd<;U`a`pi&VJfmygZ_K!guhnzHQor_nB0S| zYdl8%_uvl}VV!h9W-B(8x_%nfbGVwWfjDgkOS}k>5aa{8sd&-^6$X72`4}NtAp;0S zk%_aq0H{Ssf5dSZ*0iUJ`z?lw7Cp3@_F|nH^lZZJys;vrY1|7##>lD&{`(E} zHG}D#q^Ad-mKO>9{Nk^jm#AV?lpLGk$@@0FCgz>+_BJwwyrhF%r0u5Rc3mnk5&UY4 z^gKBA>bN1Skm6220NXvPhS0;2|HbE;y+}U@^^Mb!RnqO`*Hy#jlXSiD_zTa%r+cXh zZ(spe%pI!D;44Ttg|jP_>|C(KoRi;<_746>{FjgtYQ-wuV_(!H>*8fs0TbMI@Gv~Fo>~p7O?}R;!vbQxmCU~el2eaWh?{d z@<2GxTb1^aTmGHgCjKLXF)rO9N`N7GKDNM2D2aG$P+}cT+3q3#gYSWF6c@hR-R!0} zdW=t6OuVU}v7-*5&nD7ABx{&9bpF2epL>FLA__DO6Ey>0asfuj^Keg~%Lm#{UBTbEgb(LxFDq0|1nQ z|35|)|MNTLzh?exc(y(N|2^+mDns4$&gBDWwb0xl;r=>{1msMpoz{bq8=73 zBTPIhNxw2CO2f`L0c3?MZN;oP?zCq)O=9k-2bYzx>|D+;pdmvNlUr1 z`+k$n#m3|&dGR6U*!#JC%XR9ub4o1t^>auDSfxS(_=Zf2E*b4M0yfH3%K*lNRA{0>@NWlYO#G@f%GE)3us3}RFtSU)37?UCm+yO+k1 z1d}I7a3xch7Bf(Qu-?s%lZozP*ZP`5s$lQlD5!swpuQn(ijp$ceXr~|#bMKbkY5px z{deGIxs9yxUbyt?&S_En$2sRMW^JylT>g}^mn#M1I#T9tA|c)|{0eGhjFu@STRQW* z-l1pZ<>a}EEi;A;?#^>K#ho!{yMi8*7s^5kLY-WJVU*<)`HM?&&=lUpoL)Y17}8{) zYlF z(e(G|Eib)?nl)`MLmXxp@ze0Ut!p#$=gOSBur5CcQ@0N<>javV+&N-eAi_PzpEgUbl~dpJb>ZZYfil=w@fxX%)EP}&sAGIINpX=+0v=%u|_32vX06x8}hoF{n`w><;f#>PsZIH*N!Nb2a7Vp^~^4S=7|2-GTZa)j1dVzFr}bI zv0=PXQ6QiUnhs25IG&jTx9-`QpSqi#z6rm?_4tw$8mwLaSzmf_=5!U;uUglG7HV=d z07K)l?Ffs*r&Xy@vz6LCl=V zG!ayoOY-L$f^OE`umgW}FBtjqk3+1^secT|M>NFs4S#D(;eTMYzn;>IH%?kXH?=n{MyR*6;U68#iAO|{2AdRv;f@kJ)1XL^QVp_>brI{qVWX$n1rjRk zGHXDj6cs;~r%aC?PQ>7NfB?oDwbjT*{%bH^r9ZxvBQE}P?T~ILMj4O4>P|Vnpb`Cd z*bMj$dK0h~36wW z_Ptjv{Ck6c?U^+_=H%1mqh*+O_kCgsK9LNabb_7KIL()M8-6vrPpE6 zP8`t|ya~hjR~(LBPL-_GLfM~t;IGiP^S_9wPRG3KYb2oWbiliVY!nbS3cHsM$>+aj zLyuxE6*leHSz7|!;iVv>Opuw9!;@6ay$h>gjERA&y)EQhi%LuN;qEYuK*dUjJgN}- zDJ^QE1Hoe#0H%6w8WhO1gg4$O20vm!?|Q-0f2-(u2xT-xBi1Zuoi(~p`s|QZk6NqM zv!-q^+UZ%+v1hKjT*tED^&k&On8hPJ*ZXcAHZ1wgT*xP-*zVr7<0YX_XF>;YpQkHN z=JVIsmOXqe9G^Eu%G)^)ZAUH#f>V+o3@RjrRL1EQ4K99?j6y0{lk!jI!$m|{wGxG{ z8jT=2cU9LsS*O+Kzo(ZidoFI{W4ocj!n@YW0 zS{0MWT@(%?iz|U`GSgYKk&T^J#j&?CGo<0tI}aGcL%OydtGA4co`@4oHHDZsh^fh; z&8W>VDG%j1DEATpG4>J<>wO*BSL9$9KR9-M9hFa*2E3Zf4sS)gz1Yr^9zAT2*e{64 z>Wuf;GfEI9=(Gs07u7M((?%Y|oiV8hqkk-_yoHstr*}`yZxG(<6S7qEA+psYoaRGZ z)B_*iR)Xo}vh42nb^pv&y6z}@E(;v-c1Iw3rR!FcX!7;CIocTbAoaezYvXW)xOB(A zU})#rLuY=z^;8>ya(TCLFZ8G89G+dr@?P;<&sDKKy0InK!4O>GuVrJZ4iQ=mQkJr( z?#+(d1EL-(!dQ{~eK}y9&JwDFAsyEN?2v}|T%FP9-)C6juqyBhg!91(Cii?_5evK$ zfD)TieSk-vq}GgaOhFhHbbPoU$`jomg%7dW+4e?rQ4!go_$j1+l%{MF1!JBEy^IrT znjoz(#%_{uxp0HTeMe70O~6<(hQ9QZ5#0w6y`DT>Po<)8`BI2N+re|#u64d~f^4|W zwcCYz@U;Y`h73j?(LoM?1#vxP4QALR$ru6=WJ-J5SJ2)*JqKaY90hytis9MD(pj-{ zR9*@a`kE*sm6N)a!oH-!(6;WWU2Xxqm}~(*9i^AUWoi>JkUA3xHK`{33$?o=c)dGO z);VpG?wMH~`?+e>62aTEX3AiR)qYKm3U%L*<=pLD&E`}#5B;lYaPcJfFmKMWz8%CR zqJ>A$+*uFw+R@gsu8pQRY$qV^bX;fRv~8MMq&t=?*!LGXWRQX`%_JL4d!^j1%86>{ zVkm6)!AjA6lkC2=+hkizVQ~lBf;VLIW#>w1`kL&P>)X)FAc|Yq&Li#o5<$@?4dIR< z7QMX4`kMJqIR|Mq$tbCcjUCmUEZy~=+!0Z9k6bS`X^Vjc;4 zkPiMnRmaiRLEffbK}Da3gty@M2;S__s}l$CRFfVPM6}lwciDVLMU?sZ%UpInkMqfN z$0S1>;|(_62W=s_W$)8D0S|F8R)^t0b_*3(qg(5c;Y|8B>=iy-?x)I>$jh%KDO16* zJ2w0RPym%Dcm;`_8{b2*py!*Ncdix={w9>pE%?%t65Kt4IEOU9RDIc3RCJb}flumT zcK&O&5Th4=%dEU1w~@4GEaHI*?Whcxqask_e3=iSieJ}OD5dBz42Hu1t8;mEyJlHq z+g77ljd`@~(+sa8^U*-R{c_TqE1EJvuWVwjYC^}<+J!z03vb?{Fx|9i%f<61E7rqa zmF2D+o~{>)^Z7wTE#}aSk*8avNLMoxbI?Nhp294Uypv!Ec#GP5>yRqubQgVU z%#>(xr+NiJ11&yV&KM1T9aMOU6s-alOeM6i3Y-DCpkq+LB{teJP;@v;zvkt_V3EYMc4W;0fF1z7b3%b)d8+*3rfIT+Y~2+I1od7;vYpKn;w z0MG|*m!yyDOAF&Y_XJ=pYiI5(x1XYBk|;kj*^-(sgl=Lb6*(sB$3iOq12oK*@1%Uy zp`$Z`X4aQ5(n48_W`p+mI6(-kC!+S87<>M00^NV|&c!>>k=dSRgl<*5_q>QPH>OlY zxmL37|;r&)gIU%tSb9RcT7q-`8wx3rGV?2gXM-{Q{O<2VMo zs|vd!@YjU3B&kJUw4z zmxp+bvJ5Sh29nk$>D>4|M7W>vtFw)X^gkCoNw>bDt6mDFxOv{UX3jnUmCIoB<-Aca z7eZ@gxI-crL}w~+`;5N5l0L{rmYSD)icr0UfkB0V3@1ubU_u>%R7PZMe!nAf<$>^{ z;PX-(4#F-~s`^AWWISqqt$d@XeGNLPG3qa;WOqjZr*)-}9Vjjf%VsJZJ}a{tZ;luX zm++y`T#}q42Z^bhDR1lJZs7rqYNAD{IA^9Ae z9R$EE=PV9=qkkK_?X$N@WrA-6T*N=-KjnRZ=oEB%zmsgQKdM13Gna`hc0aRkk_tTa zUiap=Se@9n72t9RewRC@54~EKO{?9SHHzuz(p=U}l6|f`^VhD*O3`Cx^CWm8k1sf? zlxG`ret;BeW|ipXO!S0XKS;J;M4rm^4xcYbpeuLri+v*lFWlN>yQ4DSyffwYY4zGG z!=yPXG8`A4leQ;W_GP?z3T)ge6=$+c+#YIRe`GrYd-0a1HSjdPJ>@zkN++&PhAs}iCt_bcqDpB%R$f^=qe^|>#eznU<@b+GavHB)wa*+pMD~xD zbyHQ^E9|-1*u0zMj6`~tSN%em*#z%zhIsB)&JVqEr>cr=iOeu(g^IJ0 zqa*sHx@$-*H>y3)Ek6kA=m_Y*B+aRW-kg6w$oazQR8uc4V{!Xat4ekGRZ;(O^y3$m z0?@Gft`=pPz*#O5{74x{TvBBE`U~(+?7fBZN{R#r002hve+mx%zlgp6|IOU~{i65Z zBj0ELC-S{g3M~z=i0}{;q-H(Mz(KT>Wmp&qfvPwEC$CP)bwW3@SO49C*@7_r#~#?- zqq+BjyQx-1If=!FshjES*DKrU-x=fH@1F;hK1Nn&VsuuSS%#_#qpsxTy!E&q<^bT? zx-I#Sn!4yyLgd5hkoj3{gui#h`dP3`mpNTC9bpYEyie^Ck0}`JdwNxmf81@Xl%)M&iK`6k|1X z)(K!!>A0nzdMs9B^YlO7hV80t<9D=d^a|Z)?l%V1zm=3PcGP+Xb1mJ#=_Bx@?CiAk z(8mwS$YlZ86h+Hdh@mkEA=2xP$GS(##lM=$Hk1d(>rBBq2tCC)n*uT@k^AR)BOBAj z5$6rfGxSb58i>m?ni*A-cfm!ha>ozHH%bcF!`QaxX=Y>3TKF-WV+*iD+ek52pou$< zmq`QQ5R?NkWiilh9HtIL(cGvm$mlDe)WD-W)Cyc-({*v5yYg_cNs@CCB(W$lpYHro zrovIrxKX_2gJO{7AKOL@-M1n=6mHbZU+a%o)Rq5=?P@M1|8AlR;Gf44Yjuxsqu7Sk z7!aSyl}7U-B3*nbSR-GQ&PN$V-5fqWg(zc2rw@>Ipvuu}sB`u&fkBec%e*=a`1^=O zeD|?`hEF1ADlr(-2U0OG23EF-da`uNYE}FxbGfF$ogXuoM&mWSV6tWGx}8h34E~NN z?<%%b!nkn;uPjov$^uUeR-(=#TpboS|D|^it&b{ZHHvId#E8jeK$SCa77{fYbCz1G zXA23f5C4NZ`k_)a98Rg_Q6=;rE#e|D;H*M`005#v{#WOo=l}lP|L3a{l)KikhcBN* z3-&v)zR{?|fwn|nJay(DN0$TAKV%GRviNa({D8x}G09^I@y7W4`PNA-bBq%!uKE0s zR4`H2RKaU$05U7l_P3rIt2Q{+COWOQ*DbD9oz8QwpR@P%RZ<5nUJt}#AG5!IcR#y# zpVf4IZrjlSnWY%PbM;m1EbB;m%<7Isz2r>I`(!t1(tDJpxYL^#$JGmt3)ER#Y-V{o z**fc6S7(fAn~cU|`tyb10sGTG4cUe?5$lh3P|f7vj|1!-;)jVLEI(X)q&Qib<2td= zscDGqoGS6xdU;Y>5;gj%dDzk-BLmKaeCs))> z^Qc&b0UM{{XWUEf`0LmZCXG>Z$;vLW_KXv0ANHDXz!KI0xv*}ZU1^b$Y9q-G*ID~n zqI-kti?67fdz?%0>nN7ZLifb7gB$6k_UyDfoG`@$g7GPzlmde-z|TuPP$>}*v*t16 zHns-?y{?{)>vaY9~)cjKX<6FFx&U8H~=Bo1VCgGsx!=)l1C*h2Xt&@Y7 z)rr#j8?W2no9Y}a%qY8Chi_ztLK$5ndDeCdM%HPrYgm%ahd=OFAWm`|3xip`{pR(t zssliZNx0f5>k%>o+Ts+vD|}FC1v`=CuA3a%*toJ{NLV)+c&`=jl?C$LPnT$>W=^ulRH^}JE^n$nW*Zf!y8RGo7SDonQ%6=(ai|7BX9(?N4ln+ zGJ_}U1*MEBw{ftV0`&#b*y>BUOk8!0U+rXJ$UZj~&y_iYsOq`Ga8U=sqf_CEl-Mk1 zwAvumm?XxH(3(eI61p-*ii59$?LlhhBb;b7=tgd2NoY(B;MCEnmgo-m-7RBBKM!3q zqBhsCg!znan=)yj@n?KRaB#+@SyQfXVrv>Pp@4O=>vjd3ISuB{%}BE1a#aM1(Ca)N zI+Qd*H#0r2^R2mubynqG`t1qpc}ygWTSNEjc1`7_7j0-)JW6MPT^`(-LrZbnolUr% z(s3>~Q>3xU_sh34KH0R|Kw2S7T<~1(Y*1}i*;^0NWq^?_JEMul&5@`0 zWR~HloR?9iz~@JlP`U;v3_jeaHx8aMM-mK57)f0-23{4Q{tIXC7^PdVWQ*3W+GX3e zZQHwS+qP}nwr$(yF1zY0+qmbP?%S`&9k&R>v}+aHGKFsDDdht`ZY<;MM7js45a2<}VUAv}Ro=7g%<0v$^Lx)wd6MsOg%Atj&vVBDhaG%^n+gSoJ z+BcBj_;y19A@^T$b1qr_sTIkl-e7w0I}{M(L@;PMt97u$jOT%Z%U|2B%YzVN7Bblt zSW~5o&BjReaBew5WA-%Rr|WCbyPEEJ^yXme>?RLZW$Y&2CX4P@1aSMJ+4Z+$uT&1( z2+}Z{o9}Y`?e52~3ff8mY2zE7xL|s%w~=U~wB4ot=I|afgBP0HE^PCz1z|hQw-B|f za(<;Ee!OwJiC8+mD|zs0ds@JHOTfp+n`qyI4BQA)&Pjn#pQMaF5@9b$MB}I+ghj%D zBZ56nO$2$j_;JJ7J@>!d2y%}AW`nUstl^upt(OzhRZD(%f3GJ;6P3Q}*dHpWzqbeF zZk1-GNX4XI#FV%xYscsX3A>|81V71<8}~|}e(0h50(O_>eu`rH#9n^327mT>R|5+S zkXkz>&SWgEO}p0*L+mtFy(HQ!2m*LRn=%faPv&;FV>n$guKl*Xf|4~9Yf)zDJXslk zgOv!?8$!7iPMAH3p(N%9kLM~wfqm=MhL*MI(MLe`8qG}X&SdyexpfI~vv9gSY;0#q znHt?0pCEDjbz-xqAERFk}k4cOMba%qQzRC^o`avjwd#$6!EW)4I-XD ziMX#dXFt?{nPkEWC$K}xwRdhJt7XEqP1)UTAajDePTc<D2cKc>YHbQ< zOKh$s=z^ptsVRqs8jEVxyDRN$-==_&%(7m-J@L6}RowS^&x4f$`$#_BDdDzAqA5(1 zC7t`38MB}_8RhM^{izhtsnVJOeRx#qasD#m8XvLNc9hf|qi5Q6CvDoAK=75wAg$5e zr1`}7!Ah3)h|0^pcy|pW<-5yD3aY?nfix+5?zVb5PC=vVk3?8{KhM`DRoBfG)VLOb zKx6Xz`qT;~@P6;Y=|5!&o^D$7QOxm}WtfBdD)Bd~1bV39I?b9ifXr#8}z~VEZbcSOk%*m&pOk>~bDMhs)!$A_! zKRd*9ZMux8O}Sw5R@ioLK9(%X+=;tT*p(9HRYJ`Zm|~ND|Tv-?Es^8+3WhdOYCl-&KY+UZQCcu{?mjlcbWJj zn;7zRymye8wL|=scV713)0}8^MdCp7(SSdXZ)=EOxOQcx8M-}sw^qOUvY1xQkj?X~ zVEgER>T+a?yVpV*{)-vwyrt3R5QF?#_BIX)s_{NzY5l#*adbx)ipFGg&#WAS#_Ik(W zV}@W-$;Tg(wp@a%!fsJ|9%z1a^r1otM@#B}#oxZ`BsQI|->kgX%)9aZge!bg+q>@2 zcE~cQF?%yvOqQ48`b;7#(|%$L0PYWX*Q#nYx88pNdVUxWEP6z+Mz6VX)3%sHFDny2 zXG1xB7U39f{P*8l$WI=*zg}=aPCQ0`pdas}g5Q7xc;@1{6O>L>+rfen2Kx5IgAEwN zP+H^sIDp#w@raFQ`YApJ`w~`uIN$)Wxx?K?@py$F8G;;sG&?T!7zA{|HBTQsRw#KxBA_N0!#5 z=7bP=Uxdk(A)((F9jVH(g^82u6G+Pw&he8CK#t26G1Y8dj*oR`I|}NlF4mz@awg$b z7tEP1=)u0?HS`J>?vmBEm4ATKwDV67Y+ml$ph=fvchBJMh!QakvGkWYL`1ozWlcB% zdt`h91x{D{_c0XtP1@Zw_I}Zj7oECe>cj~xS^UTmpyZ1(A($B=4kY z<6dCjyL6ZRd_`#-Ohsh=&2?zPoSlNX)eyt(D#|{#@Y+vIX$-%FI zjRt3t2K7J|K!57b5+g$e*$9=YY!tejFJ_5} z$n4O&Y>+c8l(lR`yw*0cmA%!o%zU7D?GU|wf@M&!T^y8$S~OEE?B9i+{;V+CVF*T= zxs~#lX^izboEu8pT?Wfj%tW`$jA=7_y6jlys9X!Ttr}KjkVdUhpdX8q2-;0_d*jK~ zmO4-Bs19_J zlZnq0*D;|kB3iO2pz1i=9=+3^w3AJLz7^uJAv@nB07pQ$za;Fn3pvG%O){WbF#e^V zN<+Ng#(e*DrI8T)5-aYVwNX(OQ4C?qq=hnzIb8s59c<@&bzBo9HBBF#Ml0f6V2sg% zbmk&zp_?S^#AtC9nQb2xBL&uKipW~3aboB@2d5Psz(A`t@jPPOm9*D2{>;|clf$?i zLEAWlv2X%(i?KUiCE8`+oigU$H0GW&^-7i4sL_hhdj^kM%h^*p5Bxw(P5`c86^Rr@ zjjt!7u^0X$!NEk;g8a+Q)UG3O&{LkW3$hvf$W*C+4wtiDaz zo}H_0daSqwoW%`FaJlT_Gm><6@fESfM~1fpnI6;Fg$(-mdCEjzazx7z?wQrx%p&Q#o`fgQI^}1yHWzI+y z(n7>V)WtE&%1h0w0|qR7p~+7+o^{DpX36tsjdy^M8P8DeXCwi zo-^E)1bjxXlQR-~!`w6~U-444)*dySR0+z#pIsb>U8vzK2o&4XmNqGLhwMqVu*&6??OQL3B zhb@ZXJIcAmrNs`|Zk`7wl)Y>Z1@2Mw#4qN6>;VS#w7!&W9C-%2=_EIUrcHL-)r;Q) zL6VTDSuXuevMi?@h~NLS$1KFd+@)dHdLd7O;$dd$cH*(~;R#J`L#O)%!tF$mS)_VL9YGcR#=%{DWjUiqn zZ~^&MoJ)Ityl}a93rT!4yg)OL8-wvn*RkI5n>lGvWKnAvm-=<2$|)4me89@}aPR4p+}Rmmka3kk#8{sV=f2sCpSwHLnx ziNI3U=0e#~;v&Y2CSZrbE{o;sK~Yg1I(PLUEFPkH(`;8NPd@#m{>)C#8Hl&^&=z%Z zSux>EntV#P@WnvbvlyeI{z7vZ*sNQQHicdx8e(%jx#ZC&nkb{F{?4v=W*mbGGvKTS zS+afCfFd2{apcL6olZzS`g)lK_W|4{F^0e{Z}k8=u=&bp(-`jsoVJ*11uTQz`&TRG z6c{fSo&Y{HX!<3d=n}-YJ-Wz4$$;3dfwau4eY}VGp_Kx&Q5d)t@Qgk=i}bKJhfA~j ztq`Fl#A3e1{2(kigK=3O&Y)hAlQ2&emuW-QS;O+@eN4(LgMfw~(G3JaW!%Jfp0a%p z90St&3zfi2nUgIA2<>Gftj>8_hA!*u%nkAy&?58SZLu(Fy2661%cd_y0@V!bfePsk z4AO~9IrH|w^!25GPc(#6_W3wliVI+(jKs86w|e)UpW&-QBR@CPl@psoi-ufWozYB8 z@A;BN95<(_Mf_nv-k{ zCTqNgY@bqsbVu%5`zNv1Vhe3IK~kGGD^sDDx;@2*P_+#?6VHB??F@lCbk8L!ril%S zdSlRi`U-x#Z#+$I<4g-D0n=s;ICpyVSE}BR+A86#OkHFTRFMK-7k$BgvfkCn${(;PV=iif@R23&0|%hLQQvCHROVGcN6TMkU| zo)sp}gTMbP8L9I7iir1BmUigN9Z0?hZV_t5E4~loqkGt$C5tn*!6p?YhxIYo^8;bq zUA=(L(d?~!1}e%;y5onp+U`x&(N0!J{G4sIgv|X5`3s=eKtuY$ekboYXG5}t!^0Kv z#Q0d|J9;v7PTXhP6OgR!xzc9Hs`j^j{d;j7{UARVF4@7Y#iqTP@YfU?q zoB659Ex~Hc{gE`T58?&<{Hb-Y(Jk@@GF=GWZmVw_-LBp_MJYX*y<-UB0dzmbd0rqd zhDjd%9)th~hJeH`zz4w_fN69>mfP*m&sHOrL`0#v za=h%>k^Mf9?R_@N zCTA`drh9&xS$ULI+J)qqx?aF~CNlg*uZW%X_eh^}6O{vVyd5r%dg9KZq$uA=+DDb$ zOHC?NAoDogY2uM2^sO(5z>2nR(}G+bUjwh>Yu0H^4ubJ57AL?zTPX2Pp# z%rkYX^%<#rrs@tt4BO%$Bckq z5v*9-+^?vl=P|}%v|VbKjmBV{O6Eb#;~_@Aj=6d#4e^|nY4wjXDh7;NKwZa47MDu? zJDvTy`n+&P56@!Zgo=S?@{-E{8B$eH!AE^3vFK%kSPHmyNiYR0@SR|BwH^0 z2;Nn|0Gj@U0A`Ykhpfo`!o}NY!gZhV=0muBdD0oGO&xvM{%G(ul9psUZg~HE(71yASa;$d(5mq5C5T@o!-Bc zG=KpC{gWR5XKG~sAF1(QQ~dt>E7kw!fS#NbEwxQCgfX+J5p7|JU>4cB4lWD9f;E(l z(nQkeaBIY=;xfRJ<__1vdSV<&QZqg+{1?!dJnz>H)-6&*8qe$Hr>U9QY3WnnPtR9a zc%}-vN2~35#kk4PLT7xJ>fAhB;vs@&@tyiDpXyhb5FC*qzuw?YAuGdyq`C$Fub<2G#tN1|d6if|jIhw@aZ#_G9tk{+0jSIWJC zo5t+{!Kh+R;xjqF0kOk}+!idX)<5Ft1R&?y!0=vY!VL%vMjYIQi$yL*nj>=?oL@wRw;s z#>+jAXIeaF$A}p$Zfc{Q884x8uSLJKi=%7PNJwf@lT#+Uf~-m_6+7@sfzjjUGA-;_ z5FBR9RWy^O54hx%W9|ixx}zjwqWIhv;`obLrr%!|E&;C!fhA1z(VykWKLT zm1dsE4WqqA4;C3v$rYF;N87U_1s#dVh%+L#hSitfCCP4kM$J30QUT}Ef16b<<(6gn z{NtXWJ9p*#3#wOUO@^Es7($XP4NsaR7s5zI=`Fu06nb{I#skef2g<4r>zE|OEGWRy zI<<~(PEuij=McC8cVTK4WGm-!jy&GV7l7Rr4oPntN7eeNvGhReEWKg7OYgW|J4dni zu(A9gdMob4^R=-2V7^5T~ZW9))%%)QaQ{z$iFz0>5chN6>^T|QCa??GX=hu>Pw+>Xx2JmYH89qd^Cg3UXU>-8Jo9|ZwQu}?W-b$I zM4}1^5YRLD|3A(9Uzz(~mF@pMh5uV|>kX-|eBAQGxhvzCG(k!d4@BG*NRkvBPGbn% z2nIp+OGC7ogM{6{o(b8MjAm75S@Wt;g<6xAg4TQmSZXj?)yAq|Wlblq_qoNV<-*EJ z@8i9*yX5$Xd$-5QEHOhM@TYX5$LZ!J=f>OYE$0~9`wL&sJtMrdst&U_z1BR&bv3lr zb@jTjb+oHhgRzQj2d!p%r?sVp4MkGDL4rZM%MoxuI-{yZksdyZ*3znZ_i9LuVR3m0 zg?(g_nUfXD?UP^eCc`}2=zXn{5&f)Bjd%6yLAImJjjPF;D@T=R9Zlxm@ zS%#@RKb~wM1WcB17Zs;u9Ez`iYou7{Ua(ZQAbe$UyJID?2HFwXdiY!U4oAr z{^1lL`!Oz@LMB_JAXGG2ysu2;#!41b%mhK)K#O9g$>Hw|ejyb9(Hv>LV#;5!wKsI0 zmdTQ2%9t`*BjN{5IVU)l%Q{v(WxOge?f8TMrS;rxKnZCJfFf%Z{8K}>Pm9P~NQoYH zYPP{9{2-GlS6|i0w`u=XT6@r45fzD+$r2q|K$P{7fU8XnmEz zx~Xd_KSpN6NA#!&wplV880fG@U8AGGzcz#s3L+qtSik2Do*||9w05HtH}Zbrsd*)z zK!)b4k`N6!SF>VfHQ7~CUtWv3`?oC&F`$TY?9+Ss&nC?II1nT?Voc~E5%7l?3BpAz ziBL|e4Lu@{w$Vt@c7v*wD8nLJYrTDVD@bU4y=*$*9%r<-qvA*R-06N; zY#|#B1-}>+G69!t1cE^c3`}iA2$wKFg4^H18GoUjo`rmSaN-s*O}L^q{}ubwy00E5UDdsO(18_)!ILWm{GN zTPH3Dghoxn;08j_KFUsn;T%A>14ODvzHh0x$FOK5zjqpntkVdKFY3(pJznqyCLKH{ zs8#Z1F$~d4a3zAD+Hv4@9%C&T2>xYB9QGZeaCF`*>yh!D!w}?E6BpVA%*d-**A!MI zG#yk7uQ&|m{r3{7aE{gD&?AI>hwy<&dlxgXUOE(BVMDAYG(b{qtFnb_(@L-nd2}TQ zBE$+iQ|RtDnolwwv$-DB&?B{n(c^luEaFWipzN4)uTa+0%$!Ws)9%fQ*$=t8nL#_sp4dRxE zmJTZ>75I@A{mPtLaag*(nP>9S?qHkCrrEK2!cDsMVzzPVFx%L8QR)K_U}Yt}seWuY zK@oRoH#{r@t)D@xenp`Y>0UWsL~AQ8RI4V#sDbx#oY)--`Ddmc%Xw-a;PS7HV)`Yu zdJ&36(<|K-I>z>fMg@X1)}&ssvUHh&UUQZZQm4@KT8pFCPRZT;wX1n^yV#1mFX1F& z^1ny?8IQ8>XsY3Eb}`%oZpxxYMziDZOg>}9H<5&=VKoxshFO>IA7nk0xAMhBMQGIb zt$v{zuo2{DmWVx~H{-QGpsBpd105fovA*VueT#AZqjx{FN@|=#Qt5dDM7K?RfYeeVGOs8;k6W4u1ldwX! z>||f5zTjRU1EP1T)QhDnr#0;V2V_*+tp?o~@TNP;E`Yv>V0Q7hl7A@y7~ zyY6KSgEb1ikCLwfg7Y)1M+azTe*TH@DmUUAHqyfwK$(^S=#Tgh!`Y2Y(j2C-3>Pt` zQ*Le?Nx)y@5j+fI9_G5fqwK`%q}3?>(7#~&_EaZ7!daG`BIvuj`kTJz1@(K(9T3(W zC8AIjA1Cv%V8z2dO5Q$wGBk`G%8|nd?s>n#4-z~%da_!~=E%3rS(0h7wP%$9v*D-n zx|Y=_GlSRWNn`c9v(Zk;@jk+7i?9?rEHYqo~A8gf>j2R92jwH=nkZ6 zm^k`aZmkYvYECgWW3Ydu!vKQ;5oMkZU~5coO9|U(Tb*aHs=w)wsP`~$b2hBVS6j0Op~;X;fJz$&t^tKQdY?HNWJJJM6OnhGg`>% zkdZ)zh0{m2(4Go^2gwP8K_1 zLdDl`qdCHYaG7JxTMjF9GR(OaGlD?k5H(xt5TBn`mn9fJd!_B*Gxf@E0ZLdzjufyP zadvF)VG}n~29a0Ag}6IQL{=j*^T?m3V~Jsci3H2WhIPo$C3;z;gq&;X914`T zYwndp$z^r~`>2Pv|0G31AP%pm051(b%hS{r!3Y=%=%;uZbi7K4br2-;o8QYu!;G%k zl4`aA5aY?Tw+hT%N2+rQ%-e43G&*LEAn4<}xMg~iUN(*!mS$@?*y}f8uZViH_>CE; z9w>t_?e2SMLfj)UOOJ(NHf3FX>wEO>ehYNsQ%-XJk#vNR6X)uUf z2&u6D6UH=1Mj8UeZ*Xt)dE`-iNe9b+!~W(!&u~?|=}SDE$M#0xH~J@A=@OpR!F3fe z<*1FDB~)F9iv&S|U{t0GncQRbXik#ZgJp*nb|mMzheci~U>iFYY!k+put_q7dTg>d z+cJ4W^_53uQc+x%FV%ASnP1}ePI}Ae)}b`QOgbA8OXm6***1ju;SQnum?g?-J}}EK zpwIkPvecsEj_<^J*ybzqlhhZp(_iYTQ;BM}L*h78$Ty|W@HQ=A8$b|{NMT(>*_cvy zZ&jZZda`oCW@Dk-tT~&tNSqauy?~GJJ)k?Ju7bm0jB8X;$);3^akgrr+;CB z-#221{W%BnEFOgAYb_W~IjlBD6Rb$RXjwDHoV2^|*C3r2Dq*!u#|-ipOZvgd#VM)F zFX0^i4IAu-dTCiuHlX=!OtJf0!t^_9Vi(Cp7W>Gv9CX0k4V{YmyJO;JQWEHazQDOt z=i1lizVE?K@yVc)W9lz{{5b~-;2g|%vLIWoxkU)F*=+Vwl*wPQhe;`hv{wZ6CHa)4cutp&+zo3at;8ib-+&;E|EJM#en?B z=>F&aN05XKi$lRzLG)07&^&%$kK;3J!VKlFWQB11eRizA+!}d=RL0~Gx+HLNps4UM z>}yNJFK$NMQG%TnQ!*`s^<@ms#|h!Al}t*h$_^cYD}Pm2I9zoSv1-1-vYM9H*mJ9A zoC9l^1Y^ITk8pLmpc+#suRfg$GKm&Q#FTuAS{7znmrJf2;s-IWge)ph3t`Co7Ea)B zG=V9Z8-J}J8QrLjzDdVRt=t@Z^~iUd)sj+h8^RgKVK~hsuD#=!hroBo+ zrvMGha)4lNs?ob&IcnMPLz}88)d61Ukb4j_DSxoUGQ9vx5!7gR?SNrQmQP03F_~|! zOtr96S*_Ht8%EblMXA$VW#+yY^w?Q5{Gg($h%0Wc+%|1VwI+ro?3nWn3w{HY*5Ghql5Bwepq; zyP4E(dRgqaUpCVBgI-xnd0u`E{=SP(<0L-T%JM?LZ-f;A5n~E%#gs~V;9Pu@dul<$ zx?;Q|>A{8_ctq>t9DD;h!;&K}wF_IuH~d9{?@ka>0x?O-BDhc^vy8K4&WnJNINVRd!er30c zt_I9IU;@XmmewvMxTcKJm!iL?tY^LwKI`%?hF8D9GtT)G{O2N@Sw*?IiV?vOeTJ3s zRq&hoLI|wKIR#H%(5vP)_yOEl);t1nnCF6}kpr`ccz8@JL+6NUVHSi@qS-cY)rUJo zo|>|#bh(HTJf@XnCQ~P>(3>voUqD~NG^dhEKAME)=?s^*cv{M@>1+GW-bAZ(;(1~$ zTV&eAN%-9~46rDd7GhQ`)_H*tl&4Vzvl*>ltG3GyD3Rf(-&_(2d@YiwPbL{DepIH6 zH4`3UAH4_qh;J*WvQODuM7uK{dCkk}x|9}^QKg;{uw6k`;(m5QdYxcT$AdGRcsaXl zF1MV7v>9WhexHFAf26e3XCW2VTS7DmjWO>@6Z#*W0eI^}>`QdVy`9 zTu4$T(90N$vc&=>&Al^Ysy^-38L=LSV)(_7^@^in&-az?+AyXNb^g35gC8^j48KAd zEHb4F1Cq&@c;=;1f897h{a$vc{DX`ssLMMo4c&i%grHLjneohGuY3{TJxu5UVmdka z-Ae+p!plM|zareUG)xat``x*wt!)|8YR;R$r&}itsQOPMmCF_#RJ6Vz`7saAd zI$>Lex zOKl+^KQF=7U7)|sZ-Vmc^rXCt)b(KTtzBD_rZ~9e_+^FA5}*d%-F&D6UR)1L+`0r4 zuKWsTj;(%qdleLOUAVpH3FG@bAJd-oi+fubf7z=e!gh8Cx-J+c^46N()n3|(^?N6w zxC^CanFPRh6sX(BE(yO!Hpfi0c5yF?^z9u!m`9IJ8(p;L$mDWBP8!0wj%*<3 zu`Ubg$`EQh5WZ=k?bh$`yeQNOUFyMZGurg$ok0}9*O|muS+ZnuGqrNA>lvH7=Icw{ zBak-+MVg#X?2OWhBWz&)Bs%WI)Uqh;j8jzFU*x&B{k9?M1^CU<7(Z%>iLSqbB(;c6 z@I)~h9{nKrLE^(GJUT^al5mGvEgx=n;~=dv@rd`nh-25Gc2yQZ^g!aHQhYJTEgJRZ zp(4ozyN_SUsgmnx2j8QRMjj;ME-!^^>=HSun&Q>7HWb)PdjktGUvIXOUHD;>xQm>q zopzI9gj1L?pRs>-S<@MaN7$hF6H_1xv@SZIbhRnpb*n z#KI@ZZ_>ked4L`{>hYq~z>nX0cM}PxkifrNWcTHP$A5Xq3tzHrLmo4>OMYj;KkNb& z=mllyjWz2XU&-jfh8v2=58}WpeF1Q42A#AR`Ginz1gTsHRlNxW=KF=}jU>bm)PO(y zfDS0t=e=qXyHDF&x4sY~k^Nt3zsS$r z`#0y#ft{DwAv=SxqI z0?i=<`tGWMF23TxGJHdSfix-fPOoStexv_|e_?ovL$^D4XY0Ssfk~&A9^mo%<@xs! zRQKNA#udQsRm&m5TshWtvR8uy?x&?1I`(Y8!-u6y8)xlA@%Li?ZY7qndm*kNszv1o z<=~Z*XqKL!RWGnWZ^7iz%Kv9>VAKl&t8Wcvt`XA#b>Wg?5Ih(ak;=M47kU)} zt|TiD_}h&MOWf(AV{dk5dn}tHZ_9&sq`nM0eId68<<&7*bz?T(KB~G2Dee(90HV!Y zRJ&^XrX1}bjEKmUXt^RPCJE`sdB?k`n85hn$nfj|ySqqXaw+R?w}6v6v;gkn|-XcV3I^?BXRrxa0(F5!?V0XP9Bmw1%Zv} zk2ZdK&(~YjIGV@6DCdxYgaV!(?QuFt-CjVfzG+~Mh86j;1-*- ze>?aJP#a3{Pw{D3q3h%>yEJ?MWctexrP znEZX;bvn1+?J%PvK9yNM;QahBEz_(*&8uCsFiYeI^{?fVJtRRiK7yP9q^(H$LisI$ zu}Km2P?aEsY^bL!xU)uDCi55hR=MyNsFJI}sAY}kg^WR5;)u=KyXLu<=CM{ma(WL^ zhgD$~jFBNbdAq+$`uZx-`}I~pJ;rA5p(kZ4E4xJNN#3v7Cmq!>dnA5_8cVvp>~5hj zEsHAW)0H~1#*mdq!m#IESL*@!e~^EZsXpJgy>43kL0}F}>OlyBAhu8JYnm`9OzT_I z_6gh#mhtN!9FB_*Rpxmc>vdb z0CzSRmQWo7YRA8F;JY@1v!tjAkf`90Uzy?;#vANA+t+&n;bcv_SH^`^dcy3YcU_}8 z*|l7u0*JrJ{n9t_@bs45!{{Twjosz%ne>yr_w$MeeB$P&>(Jn@K=lIgQ;IKt0kDA zf2ss7mJ&c#Q4g`MIG5mWsSb3gCR3^j0ijQxwq28Bl2%S_wGF1 zLMoGbePm>9oV`eeda**OhgLzxOu-`E{8M~j^Qf~KMH9hLQgpnm z@HUhVLnOMil4CeGKf{t-r`C1Bu_cVH5}UHvws8AgwNrRo%xi_#Ij%F~TBU7?FPc00 zZEQsclT$U$YK7O5t*>+{^>i7h%-Um=Qfu;z&;>KsV_+u7l5USC?nGWjr#1^>$|9yR zs1Bn!i>%5+B3S`_vcOx_Q~SdBG$$af{R8EVlvA$qO-5Fwth}76B2^$&wl$>IpOq#^ zUrmBZ>!v;0vN~~@^{Jv_u1w`!Y06--%AI+lFu#EUx(S5rH&?-In%R^KqLiM?6Ll zG8uRB8^V%koR(;OsreUN^BxLq$oML|N{+l5JBW#<2o0-1MkW@xNu?a&5O*n`e2#KW zBtf3=xE=1;T3#eGAEe0yycn?dXlK1MC_?J8VE74h|H<61G(CUw*m({Yl!9B)@DtMT z6OI{Ga`V{p5>Id4;y;U2PfR*Ry@`a8w6PRoi#)Hc4Yt=F&GPbdK+2b04si7z`U=b*D1Kc9R*xxWOo(4d*0CpA~90+#)4DGn6UXDG&@_xWGHH+LZ+JRfDpN zm@AaYBxj;nGo|P9M_Vs5Cy-#7bBW+c|?y}^-kA=dSKg@g~5RzZgC& zeJUQFE$}vGHoO5nl1;1esRXwUe*(<@>=SM%E9s^yUV2qv8c+nNpH?;N{aip)6F%HE7;p&aQny zSyGjQw0Vinr<;@L98nT`aTi+%%3XLQ$;BOQ$D8Bu9AXaWJLAWn=?eEsw)I<<*zrVP3*y;hq^iPLmU@Ei@#Cc4 z(ku?rRGlZ8TU6aE3#kVD^3-w_8UxDEhV2&%v$f#TGs~%a(K94VaW^%gQ8=elI4?e< z0e6Dy%1PurIOi8LN<0U}FoBJJpdhf&R>U15z0%=gy_+r*nnP7L{1x*|Gf5H0Bv0rM=Yn=0V`@Qna>+P|GLI1 zaNsqpfd>Q>C;9KBY=Qr)l^01S7RpVRxE%fdr0QARZLM zRW{oV4y3`vp02};UGMMFKHr~LNPT!QL}r+|P2JtZnqF3vn!Q4DZv$BF+!b`(3E{c6 z;nUW3h>}xHyTtjbz62tc(BrsIWBKVb3ck&LDHG>;{lyycrxvyq8P1$kX;&mFk>PGCxU3UPalR;+)rIjuxloIiU^^u#u2iB!<>olK zu9havXR?T={bCf+0UCv<>S3X+vbHl<*Oa zX2y0Ex{T*Ut9=alN&Rv~y_sj_-aIGQkb5^M`JGU<2fvDwQaayYTj(vKgiyQ_07q_`k!~Om7KW;#Ylx%{Lz+pU;lCpi${mllK=w&wf+8g5h?or9+8g5hV;UAwzeil z{|rJkM+19%6Gt%vqkrsq{6FrB5_uhIU_lh#qN-9G4bw-O$9!InIRkYk1^@qz# zf8s9Ysmsd8y2`ZtFkb1zQS|89XruB$YkJY`>^tp0A1Akbo@-GYUQP zq9#7!hV2XncM$AKtjO|rih^l*e5)ec6Nmh*90;P3c?>Pe!U%g$mAWilwiU{uCwFOn zUNHWa1gs1eWU<71m9B@dvmcx1%A=F{F+MDqud8AV%Qn~RVyyENz$zK}c7{4cvq0L& zIVwd_lw!5~2qdNf;1ZNu?yX&{A)7sGz2wY~7U3FEbwa>LmT!jK|0OzTOm8bGTPuIg zKG|$W?w{C%SxKl-{sIDW0{(Z{2>*}R{1Xym17`zs16yNj6Gta{MH6d-f1+bxt!$?z zBKOaM&9Vme|A9=4ij}pJ35IX4i;Y}YEiZRJTdRYaHHfy!mI=t3j($;f`>Y`D?>}ux zHR~-!7wzRD#8M&=B18!ig-9?Mg2##BM0+~OkKpJF?$XP{(uORI=@|0qb8edK@uZm; zUEOmZIy*PKHy=E^oZLQ7uarQ?>ek|+0xDkJo7j+UUTfIh&vXu2RKoAm1=tj(5~HDkFgo{kHat z5r&F z%;&>e!(<5fMG1z20?px*FsoU_yI3QRntUrzL&u!zu#5yaF^}{Yj+Kyhiwn#;68`#? z2V7@8h$Cy{sv%Ja0=%SS-%lydtTP@c-G3N299`ObU7ujSppou>64!RIpvsGw@bFkz zvq&-y32p0O0Jk-rcNzHzMRWT@{zWNeTbA&6VL+^jFJ~Xbd+wODk;;|~TT+*03Ehz%~7Z1IGGeL;DlTy1J@!T&OS6Vo?;~YD1&2Fp7-3AyTN6B{IDz6+vgi z#Hf`ekajNu`EU8FZ$c zGfcx8b*88@Y|WZ=rn)T>cMgd&5SyYcw)DU^dFj^SZ8US-O?A|?n zSA`M#_k=P&gcC&D9RS+na?d!8D`Ulst|YEq0W>XKB58qoQU-5l*o=}dvhi&J$l)l$X1jU-}*Q<&I*&J1gxb(aoE!H@1_%G3h3O@jp#Y~ly<BHMiGQtG^6 zGeb>OYhvrRHTb&Brqrh7rtGFs-Bui$3L)EH2v{_s8mh1dl@4}sTiH31WGzUO$|MfK z8KT&Kd;p#m!D)r22#v}t^Ox1>#g#e#v8jm^IyYWl5rcs|G9bItn^B>er>RJP@zX;asKg64f2mZ$G z3rAmm`rMNm?40KYtX31Q^whG6X)e{iyqtf>EpLc6U+NEJjX!i z|LG`78PH=%9yz4n1N z^UBuINQ;a1{3V+)#K+TqssVjveIh@gUncMH0Kc-I^l$k0IzV0V*Glt^S*-ShR{TAa zU+i11pgQ0f{l5BbgE{X_(0{zJt?V$l*{x)*ZGo=ot%^BR3IFKw>mM`Bgl zFW{TJ!b-k!+gPew;#{-HGhC(Aze)C2Sq70DqbMDlD4tOy&tf;?&{2&2RKid7Y#3u=_{pIrfuP>~MgEl&FhyOw}wY)r52Wi?p&Ft5Pah7)A78!J&0lH5T`8 zmY6p+T*YzxE08zEa5X?s>s|gI=UH$1_?fw!uJ!wVe+Cgije{k@K+DM=GwB)&E5v>3 zB0}+AhkO-~jAOSpspETu zuHSEH9zEzstc_W5+Y=Hs&iKEoyYg_Vwmy8!Ge?e)dAxDaF`tsL44E^hB*QUJIYiVo zPd7uRL?Pqt5HjUvDpPTth11(7acp~3iq944D?`b zsu|?rE>V~9b}vUq8wbxQ%8c6f_J1<$(i1vbAoxd}w4J4E_6ygEd`_A>`D^s^g|G1v z1E#qPLslQF-MG-=d#)qI~$ni-xmwItVmjD zKb~}X_Xy*3@&h{_x|K1sRp~g+@N(%n4bf1hU#Jb&1umyr%8ATYQ7;;@^slR(3P6-w ztuqkvGq;ocgBmdI34|24HGH5ep(EajdssygyB8LTfZLhV z(mtlFX*kjS@$6Y_CtuQ1!)o$ULElotqpMuUBW|jnwDT-h_p#$Kvf>vtBN2MgMX|BF zAdeLt=L`fB3}_t#-PT>Na%Foa z5aN>w=*b&xVx|kvF=>)s!wvUWcEfp1SpRus8dbk08vF8?wL=SsQ)TVzka9RpPDUv` zg`|tt@xCV~sTW3HACS?@(dxw;DO7PhX4#_v?n@i(fF&FE5eU`TQrFb%5 z&x(bT?t`;Tg6`IJVp(O({QeqPiD&UV`#DgwP8+8Q)gc@svjG(yP@Ou%vft3@fClMg z?P{bAMUM<+>MOQLN3wRfrd(r>agMFp5H&IP=)(mdGoh=kVJh&0v`XZ$O3ti%=7b_-r}-~VUy^6mSoJ?n;U$9$stSA2TzAj1 z#H~uPCSJMzf@k4H^>kd&xqfZbGFL{i4gH)|>N_`56_&Ny>s;Z{oa)-^3B8mfg~P_~ z8Pu&~2garj_?j9Q>yeH%ah{e+j=md__~}e%=p_D*ht?b_LC##rsW;vT5(qf?%qx- zE-6IlpKn;m`m^}T#Qqn0Z6k(DE*HJ=&4I<4{FmCzO)hbTovb)p^DqV}z@C2mX>0A$ z=`*v3op)h7sQk1v@VARK_*DJ~?LDqM?|_&OHXXr zn%zewl&}7Ckom)%ToK;)406KbIyC*yRz|X7RhRD4v!J+;gU?#uq3%a|6xmsOf1n^J zYmb{uy$HmO-KjDc-z{5h?=f0ya;!!*piC@+J=mFlElHl)w4ok59i`w^q|2Cfym{`L zuZgJeTh}00&a?e&13vdM^rWWdjtP!BjKQz3-nU4gzQv0pYj$wKmCCsVu<>@whf@EO z=SF+f=BUZLre|lbAqAfG1d*Lddi~M=aOg;Ooe(WQ-=VA0T`b*A1X&RZw`B;)n77kp zbhU-Z!qbKU9mfn+P_)`UWEO_QSE{8!o1waHPaKwobb#+58*^ij=g_&;)$!Hm3Dth( zS1M=FX4&P|f?mt~igC!~o68r@Tl5d4AIll$W}RYjL(KY)(Xz{#j2sk$AIxBV>7vdQ zac+VwKgGX0!L}&N=KZOfaP$CTzs#Veo(3E(EA}pBoUa*Eao zDuPDJ%K|l-fP%W6Hl3RnNF#S#1)(2_T2vk8AIUpzXEI33sOCyls{X4%WX}l!YGD!= zO6KQ7C(>6EKQ+ymPX)g5JHFWHI@w$5_Sjm*REtJftb24yIevaxsk?lH=}<)8*df`B z(x-3YYmTc85qLG$VWDW;32jq7G#f#9io9Eh#y* znvlc(=FUZi)A;%)4g0y85;5|5*aK#4*1vR(`MS8BHS;Ir=0bP&Y0)HaQYZ0ONpT~) zxvAS_d=$wz5arEpVN`QRnyzw7Fi)b49I_^lChAyPY5{X|o?ws>r6qY;J8jYTd4@mD|;>P84d5|#HW3Vm(VjUf+n$n#*1 zk6J0h7}I0r+@1ort2>oDl$IGIuwL(yn?B0WkimL2AztD_5x(fDg&+3ehdejYf*z?^ z5*11sEw%$iIH5l^3%wP`qilVmZr?aG&RtFYaj4OoYSv6e)JH^JC0^q6O@(U2igHOv zfT}ZhfXKOhUe$NQd+{t<+VZ+{8^X%NR_o({unV^p_LZjd0e6{ZMqLC|4Q%h2NP_u1 z>?FdX`DzHsnH|y7hlofHsitE7WL-z&&`4iZJ}_X7pU0Z{4cw{}V@fZ&WZ{>>a70^R zyp#Juy>x#=-J3U4)5VF+`4Llr1ZW9cUpmGRY3_MW8cy81tZ!(8+ELW8e*; z1s=;XC~_=!l)VFxG(p=fIJRxuHr}yq+qP}bykpz8ZQHgz?-)DZfA8+Sv9bS+*y_%T zeyXFQy8Fq_Jasbj99A33$O6zx;lI>Ft^7Qu^NkJlR^Oi!b6)5DkvQbVA^cz_e||3 zLRZvbbYSrfJR|hV?o8=860J_QY)4j4#4CJ-S(%wm5=)7}MB+SNGyRBfrj}kAOPbjq z?k97)0z42q8!UYa@dnbuc!QvT<6HG&&eB^yGX^N7b8xD2)I~e&=Kt{h-StAOE=VM( zusFXq`FTN!;=ZX)MrEI@an6CRdc4-47oiahrH-M=jqjngIzcs9)F7wOuJowQdbaDy z^A}W#`r!{DDS}ul83_y~c1-RsTFk1OPKO5)g$vSs$11Tz5`$rRIj_XTnO|aHOkP^m z{(+7ZOgl7t2W@QwY^3JacP)k%s0;DQxi9qT?%HAuj`%sD51vlq%VbA!rYWm_InAih zQ$`>oGi`C#YY_(z8opZJs(*W1Aox%?sAXQEQ_$-NvNnj!RDC8bN8cFT z8J=96S~Y^yM9yoE^oh?zY(T%f5v@)civ= z7grCQ^%sH9WW2g%$hJA`D=PD46$BsJpBK*iS)h(ILCe6e*m-KTpZMQf{1QMNKzz73 zgnP@9>)z0@S8ptyRB6jINS`DzVGr#Q(`LR9e9=3S7aQD|A=VN&E|z}uOhdc+$D3mO zHq@pouv6~WPs$iW-Z7JpmYh~;HC9{Ui`%yI9})iZlXA`6TFhd*I-54<47wZh=mhu; z#Mi=7UeC*^>*x=Yi43S$!<)cYWTwZvw`oV#P}@^`2WT2)RY?TV z$~t_Sdl_la8fZrZLDY-~Ba?>k^gb6D6ar~A<{y`3L_?%IY_ho)rrB>!P^56oemjIR zL5w$SzfWE?L$?L z+$$BQKYK1e8zZvdg9zT(b*NLI0UF;xV3tlo@y?+p{om9m7FAYW#OWMlb;pn*6~i{S zJ4nO|Hb{lL%`uddsSgNYG&#I7&NbZ(! zA_LDhb}R_Q0p#KG0sC>iob^Ax49-97r*onmC`rM7+t8m!3Z#K=Hr>12PcY2&on zhWLFob;M6FMUs+v7Lt@CWv$?raMkHV&gW(AV*5T0oDd(JM&v<2GHmm>+X?NDLYmOv z?YdR6*tG`Iwl+-nd<+PH3wZDKF=KJPqHY|K}#+Buu+qWdLm$Yn~Bx9<)HU-K`0rd*_pB8kD!9$P5Y zSkKspsI(vPo=llUx}#L>bou3W6ThOR7$YlK_vq37O0%84R(>Gr@bP=^7M&afGd`;K zA7A!!gi7_QpWXB2zr%jUHy8Woh$c(eOc)SYWI7L&g*;vUw`rmk;fdEeT|FAKW|2m; z2nQeg@{@%MaD}A040<2vWBuIs>9XBxaXR1?UU*n>fVIy;LUMi{z8HWff=zdaUSK4qMR;^Vm?a!JI-zT0`k1x;tjTNr$#^jy#JUiQB zJKMR|mW5WfvrVn@O-@h1$?lrl;v4EEwMA~N^K97n6V>+W5>10$3lk&m~~?kUZjfirh3bZCUXj$*}cucrg)@12T-ID`l=M<_)5Rtgl=ka5Rvh zq(@MvBY9|Pk(PGVmPHp6unaYiNTAD~EP`A4!K*i|6(H@^SsH2IM$%R{%sQWB@lVGn zZEwIzJ1x&L1`32~5#@hcl?64Wi@sCbwrwEU|O~b34SpsS2q?KJuCu zVohf=Bg?uj+aJgIXrgUvjF0P+<#BLJ%Rc3hRnr#Ig~5)un%wxZ!-^$!eQ0QalbtEe zZYAb>5qFe-q#dH-Oh;4)C1p%FWhSTQ8~n_*MBOc$I;%r-BxMEhqu4yJ7#`JwTzvS% zeuaL36fv}6-&IU>8hgX!LsIN|XK8-mU}~*<^8J}0W$_^nY{8S@7u7fvHZR~(#32n3PCY-u z@jub_AGKqc4f4E^z&`EKoJc5X@ibfrQ}9*5e}Up{gZd*K*}AD&@PtXHG+**5rb-m% zo~`m7kHOVur8|Q|>?rXj3c)od*#>IR%768pth=o_Z+&e!QzXYUREF5^A{ukB1@Ym$>~!A(k7YXZ#|8jd_JL@L zN>=`>sO+g#Xugwp@A#m6upRT4!%Q1^%5VhYXPmB;V(^ks@l}?Hs&fyk2{L*Wm;Wp%y2;=lJed6--*2v>OLev~sTQ3ADS)Wniq1jRs#eKeq za#p7UY$gVqMZS>dVF#PRZ8_&n1grV7lGj`aR{eYMYr3oK%N#4|QlIZHis+*#kCkC@ znEp51y>-u|_ha%L@+M)fDICV#R7XD%A4 zTS7u+kUtkRDEv|6>nbE&2Z+F9{YF-)Yhp#ZWT@;3U-y?!9Z06$bXnhcn- zT;&wzT^@y@7!U0F;eHzL;`kk=L@d!OHIwER&%DFyFUhHiZH|f1oOg)jMNx}{drcK? z?b_#y*bFBr(6ATKM*=a2{lC(A;LM)5aEWQw-=Dv5uU5zqaI+ZT619bPIkN_MOgfE) zA=y9c^Rv2@lYCrfO#t?WbuqaU3qz9C#W|RrJ% zk*{=dBEVsbFe?Kx@JTa=_<|nXfaf@UKQwZ?zM!I9ueUg65ihp%Pd|DENkAvS5%58 z3O{FEN;P!4wpFYBR7QBU#-EIo0;)c$HQKATxN4vmDmx4ZuA!}O0=1`#bjWI6JH%(a zo@%>%-;{Igs(DJ|-bE2~AvC8~vws!(mtjBsfd7Na)q%@$RG|R?N*MlkR8I2$Lgfg* zsNBNFz|6#n{VOeZNX_ThK<0}KX8&o0LfCMqf#3PND~>X+G{9uO20lO2;Bl%1WO zm>3i#7MvQEnJK0yo~9?PDyb{0Dk&-|AR?zDAR(q9DmtjGG}<>eG$gFMy|6McCOW$| z1Yrz8OioS?&mIRtUmKiI5M6*czV`zNCIAO!0LE-8N(x3MAZjWw@*{?Ego%Nnf!Xg5 z2!)ZJrlG#R#>vs%768=(#lXPG#LQgJ(AdyW2Vi0q@Bl*-SS1)48f!fe5OF0LLL?f4 zjP6MB%Ue@mIo}6GIw&e2lc%P&1s5e%WORg2y+$sl4$pqQ~y>#eTKj zPF?diHRI7umgQKxGi&r_+hbeu9O5I73~t| z8cE|k-Oc^?ml;owCeNf?JO9^t?>jl!C7sW=(@n?f=*P8|n%{Pl!)ol5*2^we?mCCu zzr^0scGSyi%XIKv)r%Ely0%;Giq3!IBrn=G7)CeZFX=#32VWb#wK?vro!k5jbnk$2 zt}2(!?I977iI%9kHM-{=&#GPLSRon7o9agB-rY`0#r+&BJwEV{6RE2GVNn{TSC$DA z>twFHyw0mjNeqxDi=YMt@VxCssm#Ieon776exLXs&@tP7Kg>K|vwh#oRGPZqVy@zg zh1R;GE(TlQn`}?pQR{|}rzoqr*ibUocoSFFl}tC#8C5R)UDKA=2@kL(w|tW~k#}l2 zSf}F{47C22=k@k337rfJ5!HCJSib%C^H(E#EbG>J_oDUdTKw*Upvm%@4dA5 zRI6CpXdhZvAq@udobUvvX?9S}wyFsD7ZESC+ZueP_ z+%TKT=IN#N7Cv9+RT2f@Mbr=hM$1oq|B(IOse?ms-}`Nx00RJogZ!V`2-yGCM%WtA znOT@Ry*M}4Ngo;P8K#X**^jKblK~I@q>udk{HT474~+HoP2~*&fDm|qkri{gGB1Z< z+OksKOsgxP+#Oh72VTbf1zi}tF}+2_-2|c(@b}<-!_u}o7lRyN4xM0S^b9H zvSzzoxtsnsRlCRM0ex!}+@34IP>930W(Wn5z*7q{`ALs>o7IMHYZRCg1^dLdf|PtOEF_ zj6y_Gz1e$1uscxh>;-1nqqr-a=;Mo~^QSG89&{u?3J`B=22w{mL~y)Qy0*AR!Tz|I0BijB`7g= zLWX^_mq43I>+~hte%<+)(-E`aKoKuXe}No??zT1Rvpay;#FBXCUhiHWD}L1AB9_M# zLmMKAYpwoM;8bjUaW8<9azd(L7oOpkG|$X|>xXqRWa^OqKUGN?YL?x zUpJlqySoAYucZIR0KaGa*Y@8h{Xg8%|LmnimGle^Y+3$O4XbBA_!psp`|fXROl=D} z%o|*WOk>F;aFz?w#v17`Xl3XSmx~0G=B=aD8DF*(t)-nL@)=ScdyB*p$Lu)>)1}5d zmUC9$@N;J2Z+H1+XJWyvy_@@5`WOH>c!uq4tw)+f=&YyWru;b6Jnp8CCM#oN8SP}D z!Ie;uCA3=v9SpgCHx`KXTSgk21bD@uBn0h%w_sW_0t1r3mh_ypMLVl zmaB0I*+7GVs==?lLyHTyeWuy5OhFyiN-Kq(y6IGLC^kLV48U-@|0s6p2fQ^=ozNYBwnN z)I<-xhxWI%?eTr<>8XD+nsoVh`a3+25j`?K+6*|vrle_RqM$Xv-xv+nwCTOCT|?nsEd>-jHh zgfHyo^ZMBc@6pU0V1M136llDi2B0(pYT&`IL7b2+d><-No#dQw@KTrex;1*#W+C(L zH_Bm?tEjq1&*-5vZ9i~^vdNYPq1JO4p|0LXPFj@AwZj^Djg0%Y2V|wtzLMHi)}WS{ zr8bR_oArA{UIHSPn2-$s-ZPKMclV) z5lFG5MDsRr>8P8QkLasTUzdQZsE~1kcLA!^b0~&|v0MnTDiZWSf(+YC4Dk}~VpcN$ zi8(Q>jfA!N^g&}bkZp|%bjb^LUqhYDX-ts#s@`TmQZ?KY&?7mc>_XWlMHUircoTTN z`@iCJU#c7!VN4WB*NLG{bo7pRyLfk<{3R66-!wY_181&uA`V@c)e{#2WRF00BO=5EGBOY2iJ|Or&7aK>5TEbUgg)%3^e zH?{VDS6B+slw3c%;+RlsIpfPR>tKJ%t$gM%oeGnZmF@(tPXiu$G<1Ltnp8_JbA;S;#H?PblFWJ48 zZC!nja`;(PSYKbs{t1;M>qgIlvX&kGb3!UVc$B^QAHPs??kvHP@<|8oImboQX-kPwi3{)R zGQLi3O}q>yOjtXBSmhc0yTopP;~kE|4snzuKua&>dOgs1oaKJ#1JCzsF=Z=ix2Cwu z+xjFIP8M7srjaXwi~>^S9EtgQ6P$Bp6I}a?mN!&TN@U&{jR+aQbl&%^D1sM*rs?|x zX8v(wiiC6zx~*=`K*MO4tEO{H7nSmC`f>w?{4;D-`phLnHt4%wn`4-OQu~LVG8QJd z!}Dv5v4Uj9Ntf&nmaDzUMX`lYo+${3C{WfxL6rsF+_lCOM#W(MgI81-v(3)AYcHuq zmI95oFMBDxOS188cMRaJ&M|59HF{+Wbx1efL;x-m5V3t9q7dLB0!pzPNiO8NF9BzZ z7h3R9rN<1R?iY{TQ+rZ3|M%|zbl!(Q@hG1Ore^xp)fF3d2etL&21my|4b$&CCyt^ zWVF$HzW?p_L6PWh)Xhr&hvv1qRWTo05r4H*y^ryzhx`PYUud>2uY9zD9D=8M<~i?5 zQIZ_TehKZ`KJW8R=h84#ATGXthCj4*qg4DuIfzixm_M0{&w=ms+LYdpC@TY1aT$Yq7YqFmK=x?S+Zk#PG20+fAk7#prJ)QMnxF?yGR!;HEh{ zx~`o4-l~eadJCF^s4ZR#my-6*M}uvbJB#4>f#xHJyrp89Xq74ZO0Torf~RM zlBhR6@*-OyV%2J}L@T?|p*uHL#CGFYDf!glYOq<^!A@2>_#a@BTvk9r1OWiR z|6Bfhgu(KQF#f+_rIVF~trNYIfepQry|sn&uY=NmKqsw%qobW0oxQEuCCr`E>G9tK zLw)_de^2(1Knp;BtcUtxND_I}P5~)XoW=BhU9qg#YhJ}L0N?(S)*zDhzgdtTM~IZe z#8SRVltbmTN1T@nlt)k|hmb4T_(yU8dkbn~V`2GE{o?6OTAe!7F+)1Y2k7sg-2Hb- z-Mj#piyXRGLe$p3NJv@g9%#(0o$L@yG7y}1jel1AZV+bcqoA1JqG4gCV4yWLW_N5i z79f`f_RcR(8)hi;A^!_??O|ocH2i+!_TTc~|0ciW0f4lfnS`y7(ti!rY1lYnjU#?X zSKjb9u^$r@!%RjcFG9M~gK_fdNTf&(NE|0xuHouenV8v`0wgB=cy*Y$riuU&b!v}? zL92*AZqUoUJUy{|rN)4HFKPD|XXzF(BtXq@Mj>PJ_UQ~Ml>`Ti5`XTC{4DDc7%9O) zN|i!egY1yE7~=^uvGTAMx`Yaa`mudaO(o(9GncTi_YZHo96miAm5OdQg6tG0M2m32 zc1=uCAKX2BdUCvvPID6g**`kidoY63?tl2*!ukAoJHz!x*U;_DG%klG7?z`njwO-y z{M-bA?@Xm#O}(g9syHp%NV5JDYgJ8Q_a!PmnO+;hyU%C*z-NX15KRjXTeTokgtH3? zObEwo3kXPpr!d`hgSP+5)*#235}g;fB2qVc{X+M(V%Z4yAVDRbpHWPIz?1dv-|i{7 z78VneG&Th`{!#;3fL#&lTxhXboOm6C76g}Jbynw&T6%Y~#faa4{oWL$3G(g`XrZ`5 zx?+f!V*=+37ILl{;4aJGu_ZQq28bjNSeBXPI554ZOzF=W4Fsi;&@Xu6JMThSQ%Uyh^Og9bI2N9%;?BxW=XY>2MU>+ z)?j3;+9HBe<&HGY3C_-TXvoFPao9nPn5i+>Q1G|uh>AG9-@lkL$L0yGGT6ZAX_qky zuSAk=;T18^C}juxilx*ru%JAR`Uv5kWL(`^uIlnUTBPRmwMDC1jT3kwk_R~xsvy_` zH@X@o=*1Ouuhi~tF5(TPDKbZLu3PSHLb4ADISZcaPU+E@Sf=K6++yZq)RuY(8B4AF zP?k{!ScDqhzM~gI+h8e?l=%u@UwL0?FvSt;qj+MC#CPiEOS;?is>t}X1``0LhMmxnIR*Q zh`k2dGh$3r8j-`Mt~wbAwSg%DZPEyhz#(4(L?c*NjXnIs7@N1F(ka{SUixN6v_{5x zdGa%6)%FGlIv#-8R}69TNW%r~HsYP=D*Fzcj+9cu!jURl9XMy8*&MHhNv;<`s?qB$t6ul-~ohxto1og}H?y4%GrF<7^QVordMb?%$JK9{1xpca@b&1@@rU|RXh)p+g*p#Ib>vY)FlUn-nUl5q>1GxZyEH@^l~h zW)Qi583F{f3CC1ya5TWe9P)CSuqrlx+DFqP;KOk^4-CoERmh<@+PN}ijI*V^8$%${ z&`+|JRw-#}kNr#@NX`f(_4ccT*mU{Et2kTam7P;xp8|QX&?*}uu#xuw!+_VX#QHlEsdg$-%zL2~a2f3n6C?Lal^C!@`K|aX6A1nG{{5}Hl z4<`Q`zvMg0z%rHhdo_VN4l&Gdb#;jHW0kim3JRy^3SDANP8gzBGS*ICf?hp^V&;IA zfuiV0*)%!3V-=1KUR6u62 zC|SpH_hI19w0%pDB-v4VH*R=gMVO7aB~}qd;UT|kPJlH^61TWz-Im$_<#7&bvH(T2 zIi~9~pwQ6LiHZJm7PMc|T=q(g-1expSghw;6ejGv9LLa50GGOh<+>Z_{|;zJtK`O!CVFsE4kMN@?N#U792xrkZK@v?Dz+6_)PA zS^vScdXkH9OA?W(#gJ2qkXR#yEFRETBsEo63X4rI0WfOSOX4dq*H0C8$Eoc7jKRFn z>y6V;;{hvPr*>givg^%jeCis(KzyKha;1j4!ih%)Z$pRDt;L+r6E(`zK9eoT(&TNn>V+#qD7NeLgfSF8`oX)%9lc zMVd-X1(&Lq)^)+TZ(-gpYfGWi?yQmL?)M+;Z|wiz-=STQ*G5PHfH?gB6V?O!fAH`B zA6^dr_pJZP%bA-P82^WqBTXcPBQ-_{k_vRUm0*B?8K(#gGlqpSZ)gEu1D>L6>(2tv z3Bj7>JRvYv@wmN@8n4Z;=$*O!yiU#K=fCUgef@!CKtPcf#6(5N`x7JpOxrZy4?rBv z*bhWqRo@Rtp5@>{MJO13L<)(jEsk2Dd|ZK|pgcdUT&THRBMWP(e3-FRpxRs`gL|QT z+QHLWS#}_)Yb6*QQP+nwSrtzpk^zHlT|W&6j^i)|iLUK14GYh6KQ+0?_&fDTcO^d* z`&=-!V=I{~!?GjY*12+X`&=N-b1PBzsbaPJTqyT_E7dF#*JW#*TGo6|poF2AQqCki zKNQatYcb>5*_5FWbJiHGG2@^02}3F8?6HJtK?J!6VIZ2WF|^jkgKCPp<+({qeYK69 z894XGy{v0}rOvG>yw}E~ZcY>XhI=Bq>)D=AjeRk--f?(gEZ+&%YR9vSt^MyZ^CPs@ zj(;{c_NCmr$Lo1fbUjBZq!ji$CX$rLUHxHD+3ZD43p3nv(M&U&-l`g>-R82Kr?eRq z_m3}wskOW0cZ*hCwg;=D;NJgUzvFs;-cM&oTlsz8Z?L^T;r~-jm`;kXn|}FQrr+U! z|NfQ$<9{Xme-N>HHg--17DoTcJgS-pM^enHZ;shBBl8H~%E-pp!rG{+QED}0M0h>P zI+jRz(Ry^YfJhk_Wh9oALRr12gb?L*P|~x7ht%yYt={h2<)_1pOZErXY0oStUuKs@ zZ2e&$+8#N;6aUq%*P7ann(mU;(B%oJLm&oeG=jm{bH{ZLXOArnyCno`0U1#j*Oo_V zBmd?u{c2o}sGEdyJxl}45twLpbR-8_eYK&My#WJpTzz`)I^#%!M<}Kfm8sZu?Dc4C z7+RPuqV@XJCe9cf%oyw)_f_lp9@#E%kFHnu*|_s5huJ2BRwb=!3Sf$bj>Wvod;&Sq zAoW1dV~|gSH;+aR-Z>t2BAc!F)*jOB0nVj#RKdE~+Gg;EJi8L@Ck@3-5{H7ex`jFd z_ZVycGS}M1*6NmVP()7hPV5CP44u*746N+Dtm%$vXl&@l$wpB#Nve9POU~sI%#thH z&6bO+S|CM$$6w3=`1R!`E3dcb>NhPn_FGx5%%XzQhR3Iw*N)etlcTeVvm__V&Y7!7 zis-$V$Ay_vQg)J2+_)&Jh>fgn54p*lXlTsy>GKG3WM)m~7QF3@^^|e0QAxh!EDuJf z-4GuOSPKmsjVJT>@0PDBGS%netErSJnej|E>s|Z11%Xn8(!o@C{A<1p;+b)tObdMd z+|7i^^Aj8nH~-D)V`qo8>?@(_ur?j-Z&cr%<*v^h?|v1)Q>N3g5aP@8%cvT3R2^!n zE7~nTPd`x?(eZzO53GjYw%h#n(8v;XvM%9!MXsuoZ98`vpdvybhTSFl^?rKhKxf`8%-Br7u103 zT)S;zlg1o)9Yi6c&%)+jX5Co#F77Zc&p+m!PD~~DwD(xS*Sbh`e&GH4w{_dj=k>J_ zWYzuRWyjaf$-vHVXP)QR(kr&X{AuleH=cJ?e{`}njU8tj-Hn0m%f$2KZhrN)cGftb zP)gjYx0B<}$oTF38GAL;9pa_*sN`niMy@A2Lo*XS6FWmUJ=2|@>CSThbiG(!s+1T< zj?PEN<9@$)_!9T?`96yCYV|V<3eXLuZs2SweJkZ2Z@Sm{>zEswGq=&#hA625jc(y` zw{3o(^}Dh(K??$@x10LL_FAIHv-4hf_}WNK66uyNorh4$_kqB07uhStXoKrCyd~wF z!?DNq==zqV(($LHDIOm!p@l{?o3}^a<5ajnk9FnB@?)IZfgYPxN6xi{|JoqrETjlT z)Y;jlmO6vk3Isvj5hvqLgv7(3$YL6u3e#P=0HysC&cu#HPb2S7DRzd6o@s1KT18q> zmU-0XT)m2byV@qDm2c62wU)fk#v&=fKAhsymFLQVc)6I|99(IY9DU7e?R8v}TzBpl zt63FE!N<1omO9)+`*Ytuer;|o+x9~B$3L65o}WeJcFpH7y{X|HPJWl8-JfZl>$cX@ zr`xS#JAk_NxBJEtrq1NGeVaVP0sWr*IVF$4t|*QcTCfCpA@Up|pUkP$gJ9iyFz16b zi;q{qdKdn7#XMVHIvi#!FIHFfW24^4f~c$q^NHh1kAF#bUu_++i`WWEK-VcJ9)U{e z;>P%yGV=MGyb|U*Mn5~#gbYqH+T!WJ1h_q?uQEHr0J_GTT{RN99m0P@Fvm;@|*nl0-h!t)oyHX_PFeO+IKY$lla#Caxkj=R}vCwgOss9n7+ z&!HT@7yN#b52^D@j@;cnmuC*;Qv7Phqi1yHThk}kS8uwqlv#iOz@r~>J`dQG(>|*L z=O{J`TO#6bj#?iN^*!`%mf$D*2W5x72@94-J4GXq{%40k@>H*SBp$*QUX<5v>ph*K z13YuJ)qSA$$nviF;0ClbxE+TN>-%{#b|(~0`;)~!nUlRdjUM|A-r=dH{F7bJ&hPEJ zJ*mr9Et^G~Zge3s^Bq#W6Q-GkQuMQ~pe5^^T@y>&{4ariFD@6)J{`{%(A$Gba{SI} zm>oTncy+bVJ4%+fV^x~0!3g*Hmpx-x(Mbm3gSN`}ouq|7&sHW3fltF=X8PC z52m#f{7oL3+ewdZT1e~SZszNsv){`^oZ5(F7H5}Lbt=;nO%{K0;i z?-E9}UG#i&xq&8ZW|ws_CvC~iKDzJn2QLQnkSxm)^y34UEsFb`7XUn0rmN98L8O)~ z2y1ZPxb<-(Fyy`HZGCjkk)Monw!7AKW9QvC?FM_F*wdf5?+nOy>2Fino#YO~An)bw z)?EB_Rit%La2v6kh{#kxAz~@ZGMSo+;gsd2)Y$sbkX&`TT~o%mm+hy>v|;(TvT*BJ z|4a$M;wh?E9LAavq*CO4g)8e5C(<*sm@GLNcVC+Q{9z}3xnls#$45T$fzyr}=J<|) znD$v%XtA*(t~bBrekQnFIs*VgsC|3V`;K#PSBi6i?Lk*}x* zw|+OU9(Ubsqx$DllMXTQqjp+$ifOlAx|j}gv4&Nw%JpY!8K*n${5S#pdb%4%2pfz&H{N{vbi zZPbc7k{826jt%uxC1>Xo%7Q_5sH4TlM&uPJWtE#k4q1ODkvdv>fsnU&X0>=Xhb2VL zjOVkucrK-J}*aqwRd|OCVhV9IN zZjX(;hi+?Sm*8wO13uvm^@s+wQvwv3?apDN}qBu=V1?p*cJigqzCJEfEs5*`2*e$Hv6B5_!1%FU;S#({N)ZTnx{fJ$&okW&h- zEre-i-{#50`&_O4{cTIOowP|zKn5PLY3BSR$4QbScd!|94aW(S$ll4^E!WclCQ4{SdnL*Ts_b_KSaN}8p3_oIR(*crm{%3 z=s800Yx+1l!{6n2_by*C@23|h{SDqIlJWjNC=}gz@4rR!`V=qbcUv@gEVowS9Hn0>9-;_&TQ9dun)os{ zU!u|Z) zb#Q+gtJ7*+LvIv;xYJPPw))=Gv+S_w`c<71OrM#OoMi|Dxx1~xUn z@>l~zC@;B+L3$-)a_*R4(VQGukg!8M`h;m7hmlGsP@0gKcs;yYks&&^LwtBQh}4s% zqbGHLmO+4&YbzZ#;V6#|n`4q}OAj^%$s3+{F>v)3S|JpBe7qdkHnJG01{5+j$#73_ z$$&9(Q1MQE%-N=2eB}l*`H_g_HPqQ0JNK4bmThwszg86C#ZX^bnw7CNBZLwidO^Y* z4w=?izjFwzn;auidW(U#MmCaIQiYm?d|5%Q%{G>#7Rv6!t$uu!;^}#vxKfFxt_QNrCUy;_0wX1VI}_;#%%o z5+I9c14$%hm<5+8$_$YD2kM>danjq z>`iU7{W;`7&`jPi_G?J6lzby7lL~IXk}uM~Hd`bmAc$~%A%;bC0Hsp>!c;lsnpu?~ zoAd(c3jv0ZRPXf4bh+ZeYJhDDh_*0&*(D2;?R!^e61bekpno!mW+q)lH*?*^NS~DE z39EYj1*m`-&-~92Z{KKOC*`-FBPM;5&2zew877E$g8j9X>^vFv$u{$F0aDgq8B9;G zEGW|3a5f6iMi8u8j*CRBS z4C@RR$Us1I!%gBGkkP1{OOyw+%HEBh{J{G3AdG~|Vk8)NA|XGw&Wl0CIW2!pk*=N~ zIYI&Ti$Clrhq@C&!w*MGRfW|tEn1T@w9Zs+q8OnzFksiRy23#rplV4EZ?+?ZVMbVA z8_C!n`^Ur(iS?3J@%Yg^LU(_o1V67Ty%O|ThUq$FW;K9=D`R}CJLw;qMbPX`Z$vf~ z0I`8UXe5({<yh6LOq90Y6F@0_<{c6%-()CLA7 ziSEBOZqE)@MhpnwGx%T$`9uiRv-*&dya?Yge^?!ijdUgAI*&`;?PloBjoBC#i$&DZ zB2kx$0n!drd$jb&RQcdsozdT>;4yUAK*-UU>eBd!-Z=v#oFv1g9Vfc+2DNxBIBT7OwB<1Owpda+4HuP&k!pE-n$nN65z-|-Br++0gy>8- zWK(IMmHG#8zUW%dyJKtUYr4_ZDu-&S{OMjq9uXPnIy$smQ|TBYC@znK6w;#2@A;gB~h zM7NEQPSA}-Ik{-B~AO^8v8bH-FiX*T- zncSZ)m`pE<&-(ikIq28ND3Ep>c7l;eOwG^1V2^x33!Qf?&N9MV8}e4&B*V8fFj!Gi z6}akDfNB2$N`Bp8)`2<<4}S$0`M@nIVSHo#kK%Tn1!%i63KU!@Baz;1EF)Tt)S(e@ zk9XdJf;z>q^l_vwr4EF7JL#}0z%^?;BJBlyNs%gYL06~fsiY_V5?FB zxRh->8mH;`Gw~R>kbNxYCOI5qWcbl!hwvQOI#{lLG`0>fBgJ(LywcTl6@u{8m0@pc zKJaeJQo(K{uS5e8*U6TZPXf*GxEXEGttH^ApX}~w0bF7#Z6k_#AWK!);8a)dT|> zFkdXAcR+}BA~30+^h^GbPNx0VY4MDhie}n1xqnbLh)akKsDy`NB;5UBo{vbJJ=_jy zfGiZc_D@o>NQr8)B9`*t(g58$8mC#t%g~LXU+D*?VFb0T@7NLddH&Tt7{DK(bO40l ztQRkGDC!LrpKD?<6X4 zD8!GM9G*_er*d5|LxNFM%w&Jtxa5UZtxE%ykLd%# zyy|^je!GLiq!Pn3*VU$d$H77t0+2<*);NT0*3Dok8MG`kf{O&RlCkBAyt+c#+Q8<_ z#h}Y09&%g(cu7tn3C*I&pB!eFdFeTgfVj2w9f{-2iojA>eME2Ldl85{JQ%fw+i7RA3sqKgXs(8?iaNL4e*Q8Krze>`8Pe zFIeY*JaGA1+AQ1gI7d0fOx>kd@Su9f3z0|Ok&?kCY1dbCDT=9-jaw1s<%%y6vA||p zj4k6u+b%nFTiHBBMXg?k>r7j$mceT-)ng(WAilhvUneH(6_5d=X}}sB838a>^pXqXL>3e~12lsXp;sc3$2=T^f%+@US2Z5E zaQ=VMc8lgcjpVNWX`O$GN19x z@f)uzJNM|}ZHX9ZkiaEWpa&-8F{%XajGmlpU&!F8+tIhx%GDftpF}RuDD>iOr*2k&ckF(*~n}2v?2tI5p_f#)jgy4 zWgvw`WQYKmiw0OQA#xCW1mM;o_pEHj=?ugr5nK~0+95tgtc=7Yltuw@aGYH9$ej5B0@ry z`P@hR6@^slQLb7&wG!9uCx>{WU;MBFsf~#@(-@c$F9q=>5D6=iMv&RvNNzMG%0(L0 zZV1o)SO>=1uY^KuPyEQT5~3J~(Z{O+3YR?2_j(go9#QFJTxycGy-WRH$UjTUfQBrx zd2AlYlKTbZ$b&d&V~+Bk@1#|6CY-zGNBL$chd7E7ax~N056~oo{zf<{xyG~-PK<1F}0j1YE zP?q1oAr#jzlO<|ScD}OxWslL z{^6Qzl1g;8B~-KjSpo5Ezyjql|JbZb;cb!~}ft-X5b4)Ro~{7nXwfmuAV83IVvJKTHV~c?OXa z_|iREb+Vl#_j!zd$(x^G#Cyj@9aZwFSh(y8x96#f?d5^B#|RQLK<+o###v!{nponv z>Gi*_cf!b@iX?FwaxW-Newu&v*nIx z>B^y^*=kB=2zz6#E~yDQ-q8h(OFlAVl|@G>2BwPYk1uq=6Nw3E*3hXEFr9lDVEKEI zEWf-q!)WkX-N1nYou-qC#IPG?G|57WXx+laDuE1Zr-2LLkx!EWg+8rn1icP9;yns) z?*h`rOH6yVeyXNYnt}*QFgpqcSZgF`Ff0ohAWQ9-(Ffkf;X%8dNW-oqTH<}hlFfW}A?V6hzM&FL33emHn9A>d*#gCGOgk33N zqiy3>R5Td7_M(wJrRt(+Knu(Fw*2kVVQEGx{_nXspI1Bt>bO^cJXA~Et-gsc>V_e# zP*OeSTFFaLhi4k%bS03cO`ibLt-vas)U+W@sI7W_INlTlAGWzcyaSheEYG(U>{Qc? z`jO4FYxryn?MCoMws4GEH|^8vAF4RqrsSn!2WLIEck}qaxYQ-9K<@V>lJoxiF@s6% z%=FPzRdxH~?-thg)Xf&(wWO>wAZ!nfW^J44#Zh2{#vZ8CN;Z+o$$bl-=iz>S_VC8Y z)ZKcJbWvdx4cH>~NkI{ZQ>t-U6a5=sGlLC&c)8OW_ZgSCil%k+2DO?6BXvQE{3f>j zlCyve-Xg4>9m{9@lQxkq+%)Ywgv8c}dteT&m86PJN+;0!d{v7o?k!QnEp?MRd|R0e zIvus&1wB+-TmIXM5IN0M-S0`Y2Xb9BdD6G+soj>wLB*KfInN6JZt>mFUPg=o0M(Da zXOvxmr2ux}GDXq|I)<3#fGEL1NU)yz98MAry3&PLO{iqjCBi@{^SutQF11-6EJtJWk~4-Jeyt4)!D;cjZ1C8IROV*7^FyJ1 zJ}(?cvbe66mA#u!d=l7|1u7ZLR4^_(Na%Aqm>F{oM=DS}^6H_-9AFsd02Un=UND)c zc=8H3sk?AkK{X zBw(h}y3&t1)M}hV3v&t`rpDYi=$===C6)Lhs$|E1JDiI*(cWiI^+CvHo}fvnHkM~j zQ^`qkeigZNh4VSl@`K2A`1JwT=1&{rU3X9YRQ(G*aamCmmNQ=>HbV7aWzAF}m5MnA zcwQo=`XPmnQO(9=Cma&jgy=gWCwRl3t(0W((7mUxMX}Xp=e7VND-QXGd=B_b0X@+& zg?6&yA)YC>HB9n&Y%VRD)mIv|E6GT9fHA2TyaP)%34&L`f*)daACWK)8SYbQfVQcI z;CQ3TZAEfZEBD5^ee{YY5*rC2$NPfUa3wFb-M1C~UsNpX9EUM?0u>8QfBdEdnJRo| zyUy?@PRrSBitP@ltW}0H`;r)861Xnv(NPnDMFJ1`yuwg17Cmz>TogPVocxWcF_UQ* zYXweHFT_x!2ajwE3}WlR!VjUUgf#9opS|Pch&MFQS3tIDa-pOQACBcKW25=*grr!H z88c|?B5ptR297F~)vyE{opiUVvXc1@ZWD)hK5=*JoSIq|HoRbcT^9DKUveu(q;m+NbCCzr*e5CJ_mSDxy(*^tN@`*_tA(q!OSXXWf%-$+yY0~37rf*biz`idpT}*QlK^P zV2+ARvH|aWv-Mhmn=yEeyrYz|a$&uXzj>dj)W&^a`)bbp-BU11awb%I)QRhmoo+1$DzyeJ z*c4Bm`o{Rdiv)nxY?T*j`NuTQW2&L z&uhEgbozK7hgvyrwddC|vh33@VlaLwC2<&H5bn95E~3^S%Byn(bYg{qYv$DrFLGj= z)UZdR*D&@D1|xy?Fso97r|UHfGi(0mcIE8c3CD+v$z#LHdYOU!d^%u)Y1e41*gSjmCE|_qMV{S)Rct{) z^Km^=&2wah+f~rRa_`NP@FGF}98*qXsP3LwGVmZYd!wlme@4@Y)c@~e=y+>19FwUH zl2FfS7NPL2NM0*;>Atr4^|SFd<|xdedD9sI8tj|qolXLdkK}gGWKh2iC>YkBG}xxa ztpOBM2#-Url>Z-00r0-?DLmw7Msel7WVmc6qPWkX9y0s= z<>5TU)V{7mER;UJY@XQ86KhlnA+wdkmsJgWy7qgPkAj_ve^+%p=#&b{upAKaXARrk z-GRi-yA^IA8lo-gL;+ykdILx`fDa|Eu;4;Yv8=XPyZt{rA&dx&XKTyK^gMXOrs5zd&=-|) z5R2@(A6F-07d&a?^hQCLguM?U3+FuFu{=)7qb)21AVn75D4nKPn(q_OZa4ECYa!+M zW{(+xTb?~cODfbBfiG;x#|ENDnQMoSY@o;?_tVBYa0CxDp9P2Cy_BqFwDyRO=OTb_qg%7PRbk$0-l?-Pnhs=$RWG;x5ENGjxu5JWY0Aa zfAjC|#mxC(gCkMocy7_e-dtO`a>UEB0Lm?L?0G?<-o(9wfTa?gZSkmHUf8+aRS!Hl z;+fPbSuMukKp04-Asb+&_iz+z43{V^=GP!brj|{#rF((O& z9L@~ke-yL28S|4`vCRADiUjr!t`rOTWreo0POcmg53*Vnga=$xcblH(-D5U!Ddu;K z?mizW8&6{*NEX2qQ&c)@r!ZbBJhTLPFucFE5YMz8`EI%n1>VpF zIxP;Yh20iHyoy2E0|T2yAFn}p)TnTvOtVj}H+AUdm|N~;NV#PVenJV0GmU+_~27@Q#2Z)Wtfjo5te)YV`Ak`xEHv$@5lzSgD#n*A$ z$J&465za)kbsyo|1;Zd7f4F0VdiaM&h!0xJ^SWM$UgG%a{9xaaKpx2kdPEwkyNc+^ zMqZ{Lan9#kmlD;sia&b@n(f71>l{YM#6|&( zlldvb@&trzqQ;m=!;Fk9fn1ygpKW@*p)Ty*JQfmuwZ>_Xec>T#uYi z0S;~VzCHjozUfi(phwscXWT6BhrJdimH~Y#?T$tl#xy8S?9Fvdu5%epiy;vSu{A;) z+{}o1GVZ!H8LP4lRh$nC?fbG?X5t}#P8^;xf{3dth#yg05ul_uK$0IKG#ZK^1y6=j zN^<0a>tWbw%o>hj#i2;HJD#&R{Izj6_sUB5F@*^Fd5G|l$_${J0-BI4NI^DBl#jy3DGHZpA!{n7B3ni zm3TiL$Ui^|<}bBhG_X6_5lbjRCO?(Xf{UXcT6t^?g+w*c$0Nq# z7Xas~35~$@cJ)j|Yw%m7#%<6!_vC4iLl0*+1y3 zkPl=fuE*`j!o71z9A2)`r140?>%-`OPPD21sLuwZtEqaGZh^#of2Q14kV1B~J!lGD zG54k^7n$b?x}#&h5ro~ptdpeW=!X`ITq{Sj`-etJ>CO|oiViweB{!oJwn8&UU`hmN zC8Yun!beuZz1WiChJG{H^Ioicb=-Z=nJgB0Y@EHv;0~*Dx?ZVv7i#?L)%DhNCQa$o zQfiYk?>&W;jG)V!m8vxnY;)ruuQ$m*M*V9PLYx{V9I;5C5T%*nsb!ya=69SvpHw0G za>^vX()G&Zwj|2J%a?*AXiIkt5oV$2?|es9SU!!p!?0_!zV0#>BRSpbiYeKzlI-7i zmQACrEhae5QBLo0WB#~9$GZYaAHI*VK({I0u&v=nK%HT5`jF%OEQPwV{#w%(t4bAA|XJl}AZv%D7^#JD>4A*e~ zxa@;U=xM&D-a6s}?unc%>P8sHp*MS`CZ{DWRV2Uc&ZY34afyLdM1bz*J1!bRHq;<9 z*c&EF(2$=kGk_tL3F6|-%$$i1N7-M&OkA$Q%bT2tGJ-Htd$e%4!kL!8jJ))kkP#b_ z|7v{6lO|9S86WqQ^v#<1^$&of)c}uxZPxluw`q-;k1)0U{L_5&FiOExlT)~&TPSavf^iDKii3MECjI3W z1Pknbet_o)F3=-?D5HjM(mb6=XxI$+KNaXF&PbWkL{ue#lD!eTjdz+$6!@52ApjE6 z7)p_G{yOwPA-7zOK>rP_QALWs5}s6k78NmhU`@*#;Lx@PEg4_^P`xoI8a%ndUcaQU zxe={F3pt27wvdd~#y@ILBUy$j`-|tyFk+qJZsJy2zyU3FbLFu<5n6KR`7sK?K-?DFU=`oVh+ z#~cxb(C78vq55I^dPU~&x+D%wpK7i#_s5^bxzUPIrHf_y^Ou2heVorW7sbXG+MtOQ zFUT^9yrrlG9dslw>&cqzqRpKhP;k+=H5ru(hM8isb_7U|dc>K&;Hk=bP3J|!_e>uZ zjg=FfFerWL02NY%AfhptA50wB8MG6>*EjYHs|8P!ub3`sI^8l(wstYwSsw5ve8|s-S2+`fVjuP4LU>UGQY1Q@O3~`Z0Bv z^_XzzzJYrb#nEGc{AS~<0N$e;$&GIxj}lUqtPf}}I)O&(m4mxyl*R5-Y)*Xd5DTBx zG$78SkS0U@Z^q73tDv1t_FR2C85MD5nA43Uy+>0Y?=PMPt>4}73-;p~`ORu5-SfyL zdinfef&89t#v#65q9xK}i}>MZYH;CbqZ(9N%C&<bU9Z6KWOf9j zLBcZ51Ib`6(-y$^gHIC-kOS97?y`P(KToC$rRPjVyfhE-&s!Ot34RsCC7CgtAuQ&# zxB{1fc8E$scV*xwS0GA*tv8h?fI=r&@*E8vZtMMek5Sfv;gdd zF!*lZ^4(x9_gAb3`aG(XL{3NG6DHvwwhJ8#U`Pl1>h%)8W2hs>-U!%cI2NZ8g7vJu z%SO>Pz0_a&T9pCgpT(g+$=>T4yD|FEjr6g2@8;H%BR}Us?NX%J$Kn|d*l^?Ru4_pE zl~$f7l9lTPP`z_ZuT!=Q8-RKIsMb#rVasbA2l|%`!jbaK7Zv)pQn88rEL|l1;uxSB zGt7iHd;F+`AhC{&p#|}!QDm>=W256;>I4ZA(MC?Qiiq58X<=Moj|lG1wvEMk-<5%| z444hB2LbthZ4lT?U>NTd{o{fvBG^is8op{A!A>@b@RgT!-Lg3|+;yO4bnkZli${;Z zj!7Ldd8-79P*G{_jz#h`(|nonSZz|wP;=t3XXvTx*`0SwmA0?Fmeon%Mi8iU=CHN( z@zMw)so?jFw7DBC#MW3y9qeaw4mh(C)YZQ(TuKwTJqo1`@b9}C=1u&h*+19v+)a=I zHj^UKS%a*jj2%lax9gLFD)mNZ!;M7^doh8NASb7lA;c0y%L2eE<#VjEO%rDE1}(XqI0un<8#0rB4K)8?Svl!@htfI?EmyoZGKvLU-+d3vI0)Vopq0j9L^ZXqW!Bq}9+0p7G5+brXo&ACgLtXV>oPO?e zXENlHf!u6KE$j%XDi?_bjyT>N8wb!Aq$$5Q=`d`e@0^)#2^I|zhFV51k$y2F+U{C{ z7jZR^a=?{{)yruE(JTvu7Hk(~t4NWDahDt4jUUwd>FXtI76S+=Y~uOylfUgcFj4TZ z$w3vN2cK%ke&L~5eruoEvjA-0qztd5LU@2JKfUjIK~G8`;a$g{TH$KxV4Nlksg~`G zeAIcu9WtB1c-tPu>XcV<02ku~*00s!3-p&*>oKgIPC%XX6o>gy7pvO*F|{UcYxZ8@QAEjF(reL5v$QZh8@p%+`c>d%DjE?LqIQ zZIpf!D>bz_Y`Zhp>FYIr5`HPnDh~P^dz}+yuR_iD$%o4SpeHhgsQHQcqDY(Auc~_N{b?`VmXR(d-XTB%YE{rDKh*BlY718!Zsvp#H~XiY4g z42^6|P5u|D2{T!o%KG}h*aScMAaL@4z$sEe-~OK;W*z=vXqGs^t%YI6qJ1?bp+IEn z8KV-j7cjvRNJ4O5v{S5A+F845=}Urw7XbGI}1`hxoAO5>c_CfxYZCY{NqrE`n= z#^aLQzC3u_xTJTCqUW6VG?n2$FX)}GU}(Fe*;#D#rP1;vbs98ik;6vyolYmqhAtl6 zV>8p4CQdEMn;TnSlN@jAo_eaSiG_dIB;g{6`fpqs#?Ec-7&GNHiak@z02v$H*(8L2BKZ5Z3Z>Jpi(U29U`V#@d|`B+=|%p$pJ zC%O-}4?D-NtGT&bU9UIWUC7@yL|OIGG?{eSWK{YmvjqxY89A#a z%oI^2)k+qKDiL$nh@|T+Tqd{}x$()(BOmX1a*IU=@*L|FSZos(OgRS|M8658Geo&& z_T<&>OA}9K5*Dl+38`fg4h3EBPGuoQ@h|Ig0c2J0sH0Ss!w?JCRJXI764q8{=9xI< z`ON?rWFwq2P;t7uu3G;4c`ZGdlam@817Wqp_Ydbyw7l&|~n2 zpFi}D&*sB%Z0PA7n>ae`YNrs3&1uX<3J2#tD|CctZz`)a$zZgQ#`q{f(v<>8J2%ss zPJC||!KEVR`*SO%U$pQ&u z-Tdz(05>z+yb*q5;XLtt;jn-Dh?sz3JpSqazCnv6i&Va{psWVq@9{fR<%`KbkNzJ^ zJYBkr2XO97@NZtfM~>J4H zsnbc)%ubs&j2xIei_)=4cr$ML`PetiLQU91X=GTNb_xyxD5>r&y~Ak86O5hPZM~8# zeM34BL4Tckg04_>UVvTyx;q9#p5KRdaNZg*4FIiqCoRG^fz!zR{(&o!jhv|8 zlDj2VfiF-$y+)HXyd~b;fqL7d5%3Gc%U;<>F3v>nFB}^Uf?he>z4dvI%1A$x(-KxF zcm$Sb5`V}25&>Dlevm3~<`yCT_jCE3tLu}aqXxs?>nr}%{#N4$YVrQ}%OHuXa~tod z*r<6mA4z!wQ@{vWaPxWrL+NL|YDFQRwvLVrovmDz$j0o%6>b^+wXL_K@#nhnv6IK>85wHgGn-QLz^rxiL95eytz>zP7w}V(|JW{(y)eE`}Ukw>mTe z>5VRTo89<5q;|gaeC&P95d%VGoO}wl&`ZHyb#L_mfLUz*d~2(nb8q_;nnup($^Ecr z)}zu3^BRLyE*a_Ci1uMjsVj#ln)mGM7J5#KsI(X~&ZX%}J(D%yl0nKnG#&+3CR(j8 z1tD{sIwYl-bUv&)-r+BaJcLv>#m~rFg{BMI^?+hp`;Mt~4mYPH zj;B$m<9{q=2R|29^Ub1B{yHPw_|pgUFk3Jv(zSe~K<^6G&#fo)BmVfjMD#P3ycbEi zfn5K6)P`LTt=CnH2QB($czo-B?|$xbYhvFQ(uBd zcGN&If`ha~uBiaTZ0MML6@2wzqX2Lr!icCY&^7?>g;6ujG&}|JWXuXohmz)`@ByfB zB4f@Uau3#P0mZcCOZO`BBVOC+cR&hKn+c?g#_$sH_YWdnp^ywDrWfZD7Zk;nr!j$L*BNPUu|SAl()L;7XNf^ey-7elR$9Fv?W{Vj zBnVKOkbu@S^=m8ke3s~c%uO%-&VK! z?dMoZLSd<7%z>Jj4Ab)2{<`Md;VhLhG^7;>vLla_7z6jN{-MS*uq%;gkXt(dGFp{R z8%B@=SwCaB8si?<9bW_^%yW`*7Ua|%@Sze40{o9Ti&T$V!r_IM6~Z9b=6NwP4Y zY(@zEf>zmA==k#Ny7pr7PaEt@3`-HrhC}4~&gao~Yv+!)Q!cxo!t^R%(L;;+EYj60 zP>x9yAWpt(gA!qUSN-`mW0Q8SCU&^0TV2dOVtPnsMu{=Dy3$>l%Rlre0{Wu5BnGl# zckW*@cB;)Augryw)8w*Bot#t7%Cq%W%fq*es-bmEkJG?&Q;Ui7v#VPZnUFLI0qBA9 zQ>!KqO-jAj)zXNHOXz4V5=Y zgLGQ|Y+$Z_N^O~f6fRORj-c~^0zf7+?$LvtrpL7m>jh$1k_wEE_jo)sX@)kHX7Ken z9tqkB|EXuXOeA@>*Y`-?dqCZd-K17Bv>S|(ckGpzXG?+Hua)46qjT|FkYc0_0$m8B zZYAziU!?IkJS(+=X7QTfWt(T!6u|j$fHF{3^)r!4umpt6!=xA~q)jp@*&Sp;G;9c$ z99uJv^}^~FA23y3%>MA3FpWfrPzJ~LZqAGoRt?;f-z=)B5kaB4(rj;Og#ZCEIe87V z&1~f^u-t;~irw)%cB@?bHNO>g4`yz8Hb|e~O{0HGahKqQ-M6c=#8Bkd^@!1KV2ejN zTk_~KN-;v%`;^MBd>l=CKHQ#n=l>utayQfr*sgX8+7#C0LYeZnTd{a3^b%+!o~F;% z4%o@b>Gff*GnDXci`r6wy4Zb@R6LY)Wu_P25n?pinyDh*FAi^CU%&PmfuDEK!Dn&< z-^{cV94bp8!mnP9S+D~Ok=Vja+}h{inS)j%FALt&6axuW2D3nPh;6@DqusXEGiR z6&o((IBHwuU9PKM;?|`-oB6q4F@Wdnz$YiWI7PlBd>NYCiJw{JBR_Wrz?HlZ=O$9` zsgU}Lm_}wGG0Xf-16jxnfe~)XY zU^oZDW@NG$U|GIwQ9kCEdxC7mCr}ZG==8ZfqLwmp@>^#zZZg6f z@F>$Ka_sl*#AJr)1`{E#di*_Xn+16{X#>shfe+@G&}xt@l|#{X)>8p_{F85BdYW*UlVU+worJ&^qhWQ5i+`ZB zJ1ETIDSGPrzgrRAoYzi@0W1MAaP@S`Zk2*y-i9#xNDKv_a#Kd7(?(9UALEGni$Z}; zy;&IH=y3L?L=zw86O21_PoXwGck^{=Q(edyZ-iFtI>nc?wEESBP(p0~mdyW}vL{EW zhAsL+$QKlMG5mVkMaO;q)>gfcNy_?;`VA2l9~oOrsL%Sfw#aB6*~cB#&TgUy0bWbb z<28|Yg+A_goM4D0?D$Iiesv{#!?~pXVNl=z3)em))uxfk+^b2KO^-yO#Bm7rDelLx ze1V+whKeZ8{lGFtATYE!dnWP^U$!$?g5MWjkf1b9*+tdT1Shyknz7I=;AUyu=qT)O z7gB&Ykr9t@c5wG6XZedOGCJfRlE!5v5ei<~$e`hx;CS0K6S#|zFwdv~ob&7vSV5uM zd|*JqRpk#$+e@q9Lsmn5?1Q+%WKK!BA8S0Cjun8Ap6tlFb2+qbW`JLfp0i|*1G$c= zqKv+oI+5ofB-VQ-D+G*%+_PwW{|KpTQW<(xv&Qx{&%bf!ce&YaoKy8Fn_-^tqI`8q z+mjv|9H$<*w3 z|G}z7XBWYNxXnd3G6*~TS&WeQBEoo>k%Ut0*%@`dxDhOB8s^K-WTp1iWftM+u=_X1 zdS7*}_b;`iuBCuKq`frnT-?S#U*=&Z^eOI7v)rB^ENhS%iZt`lN)w`Idu#V7}qpD!SFDVEYmd$*;fe}CNl9NhmrKJ<^zO`_lY z+&$`#5(eT(pf(N>R@v&A49MX8ssV<$Emgxo8Y#{EiaIVHUO(HNuAZPzJPoB@5H1jV zc2Op}6lT>OEcMsh_~ey{Q{>71oWVNu`hgN?&CZm-w@_VN0Gw-nuAX>*NKqo45A6eiI^r@@LGv z*~273mP73@kV@1eCbKsWX@#z`Cbc~*u_?Sc`H+APSeIz6nXTlD)Xga*7LPgQP15u$GJ(G4}LQud8{F zL{#(bahxFmOpDiI~r_8hf2i6F%Fngj9@E$tW)YF>YDFr1HbdXC1E#gx~jV z2HVI4cy>|s*u=Y<{@4mppM$A&vkPigbd0$&#L?Th=@z5zAo=(@ zTe@DRQig)EJ1mwWdpv%AthTx*rO-D@Pe{!e|Vh9YEqXmgx zDXn!7y(r=JB=JF&tlrz=Uv;yjrBv+VI(#uh-L)^tbIW$~se6dmFMdYJhF}O`1L(nhl`qdHTet-ueLuVmv_m zYo{O9gZ;s{!qE9lPfZZ)@j%1cOnNl>2;0Fgp=^V#k`G=Q%}y*mQkICCIPiQ0P+s=A z_8ie(SC5sGzr zT9X@~L$sBSGCXxSi>1aa6Oqe5)Srz;2B#d&xBC~^5 z_+93jdN&W3?cy?vMTBz%#6(M5i7my4G@(VUTL4rgK+rj*QzoeEDWp_&&)F9H;sKlO zZtDzg1Cy5><=5t5mYCl3CM^1ziGNZ=hq$ z`;6!}5%>9lU7l)2DNdjAE?m;vl?@W-!Tc~yE-M>p^r{PAKUu{wLn#&^-{k<_L4gxWYry>Kt)eM!5~gx!PLqf8}hQvX&@S0tB1W-1V4FWbvSGjeKzrndk>k3 zst-Ks+x%DjvY~%V?>cc0Sd0K5DZFwgvU{ibdUrG~Ue5(^9B)>57S~WnQ-;&<;1ipMskKATQHAVBP=2KZ%dV7kB}0`bQSM za_wyG@F!)B2{}NcHk~8YG(X?P;9}ok-$ogJ!0b2g85h7BI0(9;4(S<`4hP7ceh;@vvO6nK zAloeSJ_;WSr}4%ZaT0P{+Qi+KVQ9$eCrP+!Rl#=JzW%+oJ{VYV7ydALZ#;Mv;UOg) zEb~%BEnNEGD-@4S8p#Sw`4H)#Tyw~OK3-Y&IYITe45j9Hg5(R)ELqkp?dezsx!w8& z6$V!rGARz&u$A{XUH4yn)^RZt>@w$kyNw9&E9O zjwH|?{vrr4`78=_?v-C|D<-O4k!gZFY<~RT(VP4qMCI( zcTqW;Hc!}xrRgh4O!_TxtLs7IM3Dx9H+s?)NH+YX7Plf}_8mlzn3Q_UMn|c~8x~it zKe!uVZ{i!6Lwyn*GnakE;mG#ekh{Ld);~^GbpT#s4C&kW%+^ek#(XsjLSItQq84-` z0+P@F+`w7V4A?*!A*fgmrG}0b&97I0j#gdKa>QxrGGZc=W_!4@ZLCsMs^H~PNKuRv z&L@dwd|xb+F1cj5?XQodaUQT=(>Mfs5`PvLDj2G)wK6VQ0tjb^5Lrans&hCvToJjR zetx{R&FYh4m(O&TpSx&ezN3^h_j48ryVP$}*E9Lohe9%F$(7e!VLddvSx52<>B^Sx z+a!JSnxbWB)coTXvb2heI~UoPSB9v7%-+XPfYX`{a1?01{hq5QQOAsZxczbzPc7q8oTQTZQ-?CAX zYg}&7)k!d ziZ^xEFa3uZPc>ankGl?KWxx){AKLPNQdh2dV~i(0SN=M4lWTuUpROJ6nz(^*XYXZH z{+zdDPwi6!y`ipzi*Qin=n!$z%})HRar4JnC#cZ@yW047_+6y1)7xBVFT$V)U)UY7 zObn$XdsJ2Y4mcPHuNeE|iE zYi+7(+2R66MF`<03R;95cGS z>D?1G#>2uT#Y2Ci%29SCaRd;(fZL2Qz5}g~m>Q2@Rttcki_6LDxS%bm{#%CVYM*eg zq=Mpb#Zv+Nz^@K0Zu*t+Ko>erPW; z^-&VETA1zPPMfi2C#b+S#-e|1ox)z56ltqH2|cIS>qdM_K|Z*o4U>pEeII;_t|v#s6~0Ws`cgS^h12T|b(;?G zq$Y5D8w+)gq6f}13T}KP$ZiXEo+f7XoiA434I`6iMdGO+)J-nX23T9aH+0@)w7@gi zQZZ8LRv}SEBH106tS?k4*1FG;V6s%vqL-O0WvO3zT4L0q22j~zK_GIms-sc^*OgOm zP2xNc_iak*rb9&lj&zVY%FIgX!)kdw?Fw+t?W-GU7J(Lcbv30o;VLPHLTAs-TV8|Y zgY6VWe~tht?YE6M9s&Tndl<@Ze%H2{GcVwcU6B`pgHMN|S20513WSo~)_ zSxGr*#9sG%EzUqD;my7KIL1;5c@L6o=49hP&ZDj}=r@9U{A+C~`AE+NX-9`LuE8x@ zh}kH+F$b>3MFE{ls10k@fMQpoa8NijFK+Du0$MaY#9eFHpmu?pzcg@|t?s?GL@_CUv`wUnPex}E& zb^xIhPwCahnCZ|g@))-|T0#sdZ|77Z{H0-3i}Vggia)YSpgTu~L!Pw$t* zc;w_kuvvh?5r~PM@>)2WWGznJS$_B z2b^R%twT!Xko-bN%ruFiq#dNZu&BP!#2>lmIU{Q|*M$P2k*b3&oW&bMZ zdj5_8V4_F49hTZsufgLgXe>q@rz!$KJ?wx;s!>^&a2W76gxI$QmvVXwLQ&+QnTUAVimSUH|)Qa0N6{P@p1~N0A?vk%_EK~ka z2dlt`2kQ-JCdM1H(9RIi-tzzJ9f12+w92dtwS?0nD{n+r!b=ijOkdCQzTKU>v6`|w zlHBy}&jc^6B9s1C8v{7WgL^~w_tT5&xAF#DpB&8hX-wvE$0Cy?vvA{@I|2O~c-TlUl1(5LHVvbU7wB^dyjz ztTHS0(h#K=xJK4fm*~EQ9N9k36&-)AasGalaP}BavCT;^$rO5V=qgiI!uRNW$#Co_ zUepy~x1~DM?D277oPWtJilZy0te)nJv)uC$!TzX){ub^$Chrg(xRYGm6?pe zIm$(xzkMM#1&H<}xf2zs)oz=MxccJc1X73H z$R43U`2^s#c3|^cN_z2u9W@I`OD-^pRN3zp6tv}eQ{x^A$_=L84JJW$uj((?DqP8MHRWve*>UgAV3fpk@*m<7 zQ#27JB5LfeuURk=?MlBBw(ZMm_;Ga=_ND$ddx|{k_^&{6CT-q!k$oY`mXof*IkS!| zj7Zv8hCVk@61R46-GCF(##MbHNWech;jIk&;j=$+`{MF>sRRl{{k(FpA9xFXQMCdF zcI?^{_Ga)l3?%CPPy35j#p~yo9CL}<>p(uvIWyCOF8|oG=w~@E=_JGydhLKEdC2VC zQov+3wM{BjOF~n`pGi~B$=6d;ykY(wfy7`3SoaQ?r_eJY?h6=W)^{1L9qf>wUb5Qq zY4-zC4}xKc@n9fo6B<<9b0hBISJ(~)Z1bYEw4NkbHScK4$18vHCY9Hh z0J7$?!d}nj<>RKisQq|IG|L){FAJc;yUs?--a|W;vee&hek@N9C?+2q(l()VU7)G) z)C#-j61|vJ)>D_s{OnxshFos8-~3}M&&6>eO0!aKf_`CA;l_E;w6m(;%VS9I+jE&a zIbE={!WE3dM#WPZUce=9i7s?NHD+(GG9Pg1#p|frVAp>qdOw;F9f>i@hzC1W9k-G) z7uqih`+6}Efj=J->>F_WovIDNJ$JUu{@X`O+bzJIaS>coDn@^Qhx^_<_cy-X_kJRF zbwIgJ)iQF4_kZuq(8uSia{1WJ*^U(WibvJrzN5aFf#9i!As#V&Ha*Fd#~Kg4#F|3J zii3*g1W7S=)sJh(tlEQ2sDJ3=c-z`4vL9}IHq+_SF8~E2pisA~{Z0!2ec#%F;iZt0 zWf)p$PZ7&(G6SncIHT_^OT>5G7Y{T(fm~#RhQLG*r#hU*Bs4c0c#UWnKDV%Yw*vw_ zjwLzty@IJXo3*4e=W{CX8ocgxg_sboXRYc=5LmZ*ln?mtMs2 zTbPhEsDo3)DWSvu?cA0h!JSwoz$h7uV|W@H7nBKT0h4(3Q=IRTrnmJ z4K)QL?u=m&5BT9i;|PsnGf7TJUq$TEga2&2ct$6NZuexTi6fU8=`T61!p3MP_1+Be zLQo+n&e5hw;+`>Ef-$#tM}Zd{kys{NqWT40r=U9U`~d$||r7 z3P1LR-N^e!HpzDNNu1~b`X+XC^JaJ-d+AI6O=#eRqaXCilvzh>)7~0_!G|$nDm;jV zOFDt|eg=psDEamoup?rKKsOJsu0W5@lvj(|^oc^K4P}1;e9);#ZVt3&vzlAFMnrA8 zMj{bIJq%Ep?E!N!=iFq33?Lt(34=j53QlH0{x&4SHnUdJ-kLHO7#HNQEBjE{`zS9S zYb@_H@vZMRves=6^0n;RS`iQnww6oXE5Ch%;o}lasRw}ApkIYY5&*{DN`HguZfLEe z&*9SAVja&3D z@rwZgd`$jj4Mc9VCpge~vI;jQWtl;F4^P&vJOJj?Hm7{HE#=>NwEW7Tzc%?=YL0bK z__`Q9)0B-t#2QENMW|_Nw6u}STn-ksTx}Dq7JGDGMf>uRJ8ewWk36$(Q()Uge)^-H zy$bm&d9R@+jF#2~h{l0nlQTA0o~%RgWAxD+mC*vNY6;(cb`Hg-%Zv74$Wccqs5X?j z%L5KrmjN#a7laV&N_d9^0{ayWsNoCN0Y12UZm8IIm-^13cnoB%5Bc`t*F|9-kr-Tq zW>`f920NF1G@K~US+X?VUb=qEO&Zap-SS+83t1c_zaIzBOk|sJsaYFFg~4V9Ve3*1 zb?v3wvIcWjr|mc^JwEJ-uOBHhRp^UZL2s0dAF~4J4i<%x^Uink#wGXNnbhV*mOT6K3!fL!+Z0L`}iu@ znrGmoe>`X3H;;2x^ML#_z{|TQ+4Z_R@;zGY833$yAp#j>OTa0(8IAobJWNrMkMBO!b9)Y2WJP@M*eh zYilc8H^++K{mttGGt+74dCS_Z?Bl=K36i6V9KN%_v^)Yn8*1ZhwI=Dp z=mgWR%9BqzVJ=YqzR7=lWsD--ANFGJCn_zfJo5_kQu^EU5n|lkZ7gPglluN17{nTv zR~#R3Pc&)d;+JVgeh9P-@e|qSTRY&(hb4F&I~RxxUnfRbn7ZMcsYVY`yLM#FF1kf?k}GWjXJ^GnNo#hu|8YW-_-@zUDXn5EYW#sqV6fEqp4dpx~V;IdsnF9V}1Pp1Zs5C7~*J58ew4yOa15@LvF?2x98+&pUPMwZZd`iWdOUA5yEX8WQzwSi>U|HmJlyu! z#uh1oGZ}BI_?&L@m}IvZps`pHiJUJ_hKfQ=Js|k<&yqSB-m`cFDvPRRS^DMul2gh; zyK?~D04u4F9%mlHm&$2ufrXd~90TpcQExC->0>Rr<)dF)Up3K-xHauN=>S(oM+{?>TOt{mugu*mg?p<^?@PKPnE%Ak=4;&tqokkYI> zCYF6{LHS@c0KC`KEf_|UeALP&O@?jH*mTwp0KNo!VBak#SvQoEX5y>d!1u!d2!-VQc4KWhcl?ID-xw?%G=n9R&VleYk13V%!OxkoMyh2?+o` z-96Z^rub`pbEi)Lh=8^Pbnw^%$Z{5riItFf_SmT=xt_5-wY$b*4z%F2Y9O!@*m;1J zs#+bg?z>FD0AYJ))7mCqE71`$Pp2-vSoLQ@tElfc3Pb=c2TM_C6*X;o6W;H4#cb4+ zA9NbhZ}HI_RPLy)L*t=z>MSPeB=q*Rp$M>g+}7~O0;D^%*dvCGCAztCCN8^x?}?E` zynY@J!vqNBv}T}duo?8I0@<31x}9Fipy&A52yTY;^b%`UwC(jA73wd z+Pc4@iH4Eo7Ie3xf5w5A)x;riTcE)0+S54#w5(>{ri3~evRO9Y=hIobSxW=C!DP_+ z({?|FueLW%6AeHFbZDuUHvQ6h4xlXJlTD}G;rAllxj>V|#%w4AWz-r%5NZm(T^v$v zIHB})oX5n0VmXsKdu$)f{y@FWM&j|P!lmw(-9SPQkt>NM(@bBby{KX_!(KD2L4!f*797@zA;)O}S~B;$wmGskr& z_O@~p8>TRQ_1#FpjNs5Cm&{z_3|%L8vAN;&R3a0TgH4D=UgMD7S?rRVA+Z?;C5OC9 zEi|23t<+vlPpC!M9S8(0!!yzx2FL|LOT>c5j`3F9}FRhHpc4Gt_konP{;YU& z1yfjQA>dgUZ@E-xzN00hD)2)4Ji%M+UnENSzL6jDX;n~S4lu#=CITQ+PEfF!X)1k1 z%JOp(vT{UQ6{loj8G0$Wbj4%efQgRSd4{wID*wgE3i%mko|#)x*H-bSxV+!x&i&R? z@m|8TeasRU3xEGVmi2vApi$-Y0VtFDMQzyENs03iCte-=Pi<8DU^0H$sCFmg!6`O6 zZL~9*hM2SA0xfpuU6n&QdqmmiU*=DoArzt7A^gGw*nWL@c1D>~&YxCRA2gC+oNdLW zh7d|au~G@`d?FX+WM7+CbwmzF+Ix2}A0jnnH#e-(y~`>N5cm+K2M?Ly_z*`-)9YQ! zM}`L-Xkzq?3LFEq74XBq^lLsq${0#_D8JS4l#(s!s6ALXqU zcIKcPXHEu67|K=dgYK^No7@F!T=OoKQt0^;Oc z63a;U5Mn0NXh2v^gc`S^ZRp@ySeBVMQy8jRSXmTqsSBC`YaI)|qF&-bq4fHwoAaL5 zU9sh4YWr+qA0ozK(26z2d65xjZj`#IQz0U3xMN8Hoo#TBR(D^R3SwFi2F-Aw($(BR zT3N(OC!RfAGt)VvdAgxIAN*QdT8`|#IkcJ)tO^Z@Qaumqcmi zx2@38&OlNbXurGK?|$^XIqsPSw)SYV1OwDf=mFVhs!1&#<;-#h`{ z4F-~Ug;?VUt`ViM6hy^%0>dgZ3v2Hl1IljZl8_g+{dIm#ac1$^`Lb`9=2AGk5gc|t z^MW_rmVX)M!q!X`_QBeVTzbNyMwWuZu_owNa*Y8@90H~qCBlFA<`rAeuFNHJ#u>lb z!Z9sg^KDWa^`)t4zz~6(Hx*W~>f&pa2J-}vUyD}cS z*xtmfCjN1%S*XQt(H_RH;o_*5&v=>_S_627a52dF1ND+`Jl5qyItJ#lK4TT2nT+%k zn3g~@SY1F`5SNf=V0*7q^36wU7MFpZ$I7qdAB%Pb*M6#z!rFhcgTOGJlP>UdY`{*L zx{q%Ss+7T&up3O#%vU(g!hEb|gY;a$rkWwziB$Z}F)`shXGd=>3BARJudleyAn1<2 z-0=rwDyO8kPIg0Sv4BFi ze@&Vle{&C3jCsXN#n5P1xc=(d-tg16K7B*W!2FXoIrfhU8(MSpI@PPBhWJK~^tr&n zbbn)H{p;8pTfO|99ANKIGmFlSRv_{)upfV zLIhd%ga-Q8yeeUrJhAdZTdMDqK|u6j5qmq0Gj0&U=S=Wm6;@3@f89f*Rc6N-F1r$Y0RvaH>};qyj6m z+Icj29`M9nMT6iA#0ULsf8c)pFBFa&6BVuDaLN55=V6d@E0=?tH?hZ;C}d_@!df!_ zlE0a*dXYu5hPO@7SmS_N)C7;JIHK^VLGl!h=?xkk|DYC$W+!%wmKrWh56}lcMJ}eQ z%R7_CBM8iTkML9K?&CJn+@!hDm@?oqO z%RC8A&N8gb#Gc!bAE^>W@aj;on=(q)K%>y4-3{PaUChpDz(Odu1Z zv%b}u9$&ZYVdpLIqk~?nyV1co^+7h=qKlhvr6KX02Y7w(>EXjl{HaqG?6*;ezWV_Y z_rHKT^8r0SeT&Vj<19P4#$E~zqmiIyk|!KHGFr{GEzg^1-a;ZKb^dCo8XO)g=(9IG z0~&a8e>hsxb&0iZ6#a%R@|Fdw)=28+%6=5pfg>s};hI|(xUq0Ztb(>z zagqu;6D*D9){}CsF?N{C_D`9W=9z$+=h&+(iy=c|bs(lBxU}c8;Mx}$Xr(m3oR&!ALRy&Ffj)1^qc#)WIX+32zd2RS!? zxDYOpygV_&R&&;#;MDQTeA_QH)B?dN9cOvOET^^sO($v0H0H(Jz~OApMHg(uwh1h)*uMls11%CqS*D zR*^_D@tOKU@sZvj+m}s5IN|0TvxgJPv(zCEQS>|O64)g=83RFuDDwYXGY08saV;l! zXvCC7nx%Vh>C4V*T=Qhm=0Pg)KUDo3*wS5|DxjLd%TDoxcNx4n6tf>PnvC#zDz)w2 z8TrX$h=02_!l^)z|%!pQ`^XjOrb+C@e%9hutVQJ(NTP#3p)^sS_v-D{@@+~kVa9PVv%)BPGH-7-X!lptADmlJm@*)`DU z%q&E=`t|>9KPI$3<)hzY6FbpVt(#>M3xg$L3JfsYoLP|PpOm37P%BVQw69JMJUd)C zrSKeCa}N-Ri9dF}0C2XssgU^4Xt|>A*YI0s0T$DKAFy9ObbahZ7+Rf5YL=+Z9jFu- ziqqgaOhd&KLEl+X0H#}!tb~kak;{4k;R^pdgA0xDG5S5xY5+hh(%MkX1F zjYA&IGc%Tcm?-j!31wO>!_iYI<)Qc+b;f28?U9p02@>{mUNPv&$!Sa#3V;byb+)o! zNOX>vUqvKX=oZ1sDBDF;o3`VATQ+gDFFo`ELt;lLnK7S1Gu1&}IAmpE3rjSf6{RIA zmT4LILfAo;|3%z!4I3GeVyaJGa6CkbEz6Fm?$}N$LBQ>|G)%-3hWgje{tjy!aW1UD z&ne6Y7%4U$@0g8fdmpJD&5t3|1YD#}BIK=MKx-%{2sgV*=xHPU}rxZZ5} z0_1+PNrH|4Ab7K6RvSG*o3{Gc_V=AN>6POs$fejyOht{z)5uv!*#@5@Af#1w=S3$jOyK@<5r-dD#{9C1%(n(Fcw0DJAc+=bmMak#V; zJ1J-2gAB6)LQPQ@EDywu)(%DfOKWwi-kt=VNF!3*#+%(VpmwV5Q-VvzW2FlCbfhZp zYI%~~e4JY}Kda#7ltv0w!Yb$8;A0>I+TAdU;1zHliiUTq&3S5MJp|F zZZ1;QR#wz=Fm=RMR#vCmjxYX$q|lok61{|*wOi`@8nrl8%mmhs{aBGSl%W+L(JUw9GA>&Nn>Q-@Y)+^Sw^VBjUt%D2ayWscSgI} z1-QH;NZe75=15bhdjW&LY>7xm0&~qm&!p#3W=u%#xShznC3mP-BW=~;YH9=u{Gxwr z?IGTuP>3R4l-h~VcKYf~!$F7^iu);=p!G2T-Rd#>@d#Xmqiv+c$l)>GSfgGCvIP)T za4HN}^7q*8U*YxooqeI%l1yUHOsVw!rZQcr}T-jZ} z^fS9bJ5m`H5jKnt#e}2`V{uOZ6w#srrJO!N zqsGE}`=~^{KIs69gCED2!{x9Gn)J16qcJI@|4+o~BalIEQL-p3vsAI9vOd|rAU1c< zxm0HH@^l{YYgwPTY^1LH4&z55AXN}1s{8L%T#I6P0?ZQ7X6-aE1;ezBWBra}CqDKW zZMRc9iwCc)VrVjgH+S%!M_5(FI0=0!W&y4l?wL-Q4U4v`rIzY)MJUAS=iMQjQ1gO6 zR6CGje|4mu1rN{|?L9esE}@_Z)>FG6n1ON{Sw~@JS?8OaOXXq`JNDSE7ngl{GTm9q z4gQJ?CY(YYn7%NT@3*7T5`O%#@|D^`9VxT8nWM63IK4V_5aSfA5^B~v41T%uv)>G& zx$XFnm_CfE9QuBLzt}yWV24DyYkBMV3DXX^BkiO{Hk>|c8jDl{TBT^+Hb3M(k5K@5 zM)18nF{~O7;!PXe^W4tjzNgRaaQTxBf(FKoK`rbCbC4{^0INnQbls{yE6!bQ2d-;W z2}@SbLN;F__4w+TnJ1589~7xKq&ZGvV~69DEXMTxr*S|g#M#Xsse5nyYZ@~Qe@;%` zJ>em8(=Jr-HA1qbox~lqS!E9)r+lc?#ECkIzeQ}yB0l%XSOY|+W!{9k*O_sv-RC9_ z84r2XFbt4&GA0oXT<@^@BQbu(@KM}{QRiH9%gemY?_$E;J!1M>fcv=zXyT9U+kWCo ziE62n9UB9O*0PMVKQ7}MDU;JUa?{1AKRMM3sava-1%PqSJpU&^M#lUNO8_dIS|}q5 zV+_9vzSapk+#mP?05USeAI8T0n=M9d00z*L-x$fy>V7-%v32ePbSn-rx#5TJ*<{C) zJG9EG3^{#qT;<5gQh>8>pDn(lOG_8V|J{BVg~Z>@1{}y5)9}@KTlQh(ghG@?+X@@rMU?h%R|-4f-{EO@b-w;7m=ao z(a(9l6-5hN0LdJRis<2?diDJ#3qbM@7U~pMP1$F6Gj*74h4TretS>+;FbVwuz+$&$ z!d*pfoQTfsxGX>geNuh1l2>kABCj<@2s3GwComWfpzV&ADfXT3+bwpl+((k1)r1tS z>Lu@iH0QHJsI%TsBWnwh0#_!xUU3`oP!b?l1|VQ9@APRV%k}XZFCa`sNpHP}Qgs?r znPRk$OJrm_tC}0BIW&>P8ReHju8h#l_4%BXkzHT^4pog$J?N6u5PzTDy!Ev|l1`hv zBz5LW-FWK*}Ifvo6T6R{wdLTa81%?k^=kXh@P9kfa*xE(e;`FP>A$s1Y;CIpGWgn*fTLzH zW~V(Q_?M5tEetnneCH%h!7AfHR>{-)o5-;s8;bw?4%APQZ^q{FyB9k8X$Qqk7pqsD znqQLE?;AUCzBf>2rk5EZ6l4}X-UR6ZNFEInY4p6-{_jXWlq4p`EOm8`n%E&Dvy3%ZhV;ZVuUVaQk;+ zA=OX3_CQs^?BZXv(K2q%{DDD}UOje4M>sB%o9pglwXHOy2ry5?6$jf-u(q@T=Fuq} zyzZ&w>Am-yf;Z;UPB$U&G7y_In}p=e?u}-dTd$RCU-)VL=ZYTTlV%HNQ8g{*CYLzb?8yx9u-7T24dl=%U?CI~_hR-OcSQWG0{bhhcmM zh1+;lAh7)fP=we=+R;U6Y}2Mm&qJiv)()WFLLko(H!vZ~+h10pPJ#U=Yp~B%2OLC5!oyu_B)=@tE zQqreJsX|%@XVqJK`sAHt78SVVV0CAni1887IcJ3fcHn4=EwLNv3c2Ei(v2pVjd}hoMl1RRmV*b}VjR9;6<*6?a>OPgdZ3Oo zP+n!+`!3#6FhsqN4;K-4LqtXuik3lHT$EUj$|Qsbj$AM0OK)0QI#D4qU=oWeTPQDH zB6}7ZR7?*)$(LN;4}#Y;IQduuV7M}#dlo5pQUWJ>H=w9zd%d|&!XpIEu__DRMB9(z zf#8d_w1linpuvQLjt{n?O%U>4h@UGG?We1)Yp$?cChNE(UZ1{@W@x^wS1{VE?7>mf zPb(Bs!)I52J!5l;CpdS|4Vw_zs-;N0vB_$n=~t+*yt|HEO2=%M-A{TrxvqB)BxdWm zr>{?ouM4LUp2{nw1@||IDR4T&fNXOzCSn40k}MDhBhiBf^;-~gxWXf#Ru$}RIO^80 z|7qmzHNr;5BpheVzCGvpBBHl|tpbk5GADXOd4-r^{36_D7CuD?9rrg0`qkdv+2#7* zk)=5ZCzTTr=lA&^7AYfjW0pE!T^a=^sS4Vp(Fks;NL?P2!r#hfu8f7R=3`*bQ$}7H z`BY5#QdJ0z2qvcF`T+G_KXCo~hth)~l5J^mUrk+TjLYQ5vCHEb2CASP;tKafKR*P% zms%-^_=ZC`M4mmPkBf!`N3Ta}KEbq^-NMBbx4ihl6kp!<$3pZ*2ws*MHj>fCvkGG} zy(&ofr1C)WTZ2uMd5B8%=P9<-P{0OXvEtt|B39mMMYOf}2!GnlRuOX7W%32TmA!h2 zkRn*GKn0g$wVhzrjPq~wV;bw&!2hy**?@nagJf!H=VGFfq^bgpV_+(2a|Pz~^ajIR zi`5zc3k$N}W*uO(w$=CN!&ZIlhKKT}4VwO2HM*oOxA|kqo}Sk$=4B&35~%JvBPimD zCr7F<)2)C8P%?^3)DKRq$w&*@Z4mr^8p($pS6}E_Cdd>OTq#t> zkyZTQ1P~CeAtS$FWWLaR8EFKY$k%UaRiGKVJ8m$rkZD7P)^48$eh%-0PSql8K#V`8 zk>$^LXz3HxNByk`cN?SB7Pc$y5`Rtyc)-U*pt`fGZI@>G`uwt0wu^{xn|yhUdND-g zBEr(!vE>=kUo{i3NluhFxNA9PN3nOD`Mg+?)M_Uf#3kyN- zxm!}mc4~X42 z-`)^Qg1S|&#dyQbAZ)hJdy6oRGDaVu{fuARuE+Q-`b4C8GXNmDi|A)?i`^dkhRA$k zXD7R3v{;@!E&Js6MuO0$`k7uH!=ud5Y=O&bgou)xTU8UIo0lbs=DkR*SR;l6MBfmgBmq$1 z*>3o_@~AzQlwfQfM&%()g`8==8b=-KIw~|`ZF0fszs&OP*lmWtoDf$uZZ9lgxHB*s zC%y=x_*I%Goh~*2Vk$^Cj{Fn89O5EHPfISGgyqND1xX_cFe230v;}K z0mr4;zKfZnS}utpgyyG8No+T`pP?ETx()BjVIi6qQaEvPVi27>+b<@#WLIwD;XRW7 zHB{5IB3j>tIPBeT3aAy6JvURti)PnoYVqhZDo3~uNfbe zNU;%J-gLa&Y~cd#{(%37JM~G3(5+Ac09b|v`oGX%;eK(a#tsg)4l>3LrpCXNQ@bTK zO;rixvtK|L}`7D)Uhe?NOb9C=Jo^WHB z(bj9$Er4j$gHSam_u15}uLTSK(E8&6)-bDCz$+T&YW9Y!2?JawNEj$oUBJ{TI7-HX z#pcDZ08U&3D>YyrJAx9X&}6Boa0#cTE;B^p$&Fg;XC;HA6Z~r&EfxDX^I7Ht)()(1 ztDL;N?i*)fF}=mo%4CO3;Tqf@gL{#Yu?J^8Hgx_Fy;J<6H#Nfu&ik*qBL^JaX*#{J z3l}f9&MhmU|4il~sFRFDaCCjb2*#^uXZGE?bX-?Pw2M>k9+$`NowX>8-Pjw{g}uzC zzGl?faMbjn`93M22{}8Fu}X-#4$wp;xAM~hSMhrvkUJ1|MQv%1`ZM>{ z6ql|c7D`c$@3Qa*(N=4AQ$-_S3DtZb)xMyhh{c|uo$zgSl{?TCQ^~7#KLt>|WWe{| zpf?hn)2Oz^iiC?>Gy~P^FoI6OfmMAVR>rWdaKpC$vB>@|JEzzJ7xMB50|Zkak_t+k zWw&^BdR#+rZ^PY7V!F}G){ICb%(r`3-FSg_n(V`jknQB7S_3PWx=bv^v~sh5+aEdg zsx%#_^vAqi=nd&gs?5641Xg;5;IV<4qbwd+*H0%}rc82Pa%x0!+w^iIQEAEQG5svG zl&LXyb&rl)9Ohs{6 z(|{6Lrc`H_sRK*9M^$Qxq5ln9dY#9h;=+Gn9v*UzAEx@HeC;%}CxW4PKrqgtR}~Ko~9pqAm;|Uar9GW<9$PF$}dtzAIlpj^kW}RcUU{9>pl? zeJ4lQ-yL@Srcg8oDwPSi$qtX(mM5hj1X-8tdhDw(&QB}aKGkP%Q!N)K=@FHt7PTJM zink_zsI6l`JUF1+Cm0kHLiVORe&I_}mT}ZnZCkM$ifFcN3*$t#QXOKY5Umq=LMo7P zS{$!TGU~R*FaMlcma!9ru&Q5_(69`GIn9w>&4@%{Bm8sBJn)kpqI2Lg90(2x2_HUb z0Fa9Qf)=R}AGRi*^O>Umm|-{u~c*gRG9eY->{+v3t9kjwL`dC*bx z?4|iSkncM|;<_tRY$29?4(_SHubvT(GiG90!tW9$M$Y4?)ba0&7ClrGU!k-wp28_+ z*6cRWR;A%!&l~1rtQ}!%{=<>?$-IHRUTwnwUO~sUT_A=1%<#{V#ISP7^;^in4Zi^{o6(14F69wG@cQ3SxICnglTluY_l^OCuVp{+#;90}w-|kw z>UV=(Jh%ExB_mSzWIX(zil?waYSFH(8sZeSJBLEKCfd`{j7xAE4<$&!=840Z340Ub zimYWJZba41irB!f9JfPTrT1}n_R2I{AM{w?KCuhs-RKyfc2guKv{d_kurYe(TU(cv zwWVJr9EAP(gTHraq3uYA(e6Ff-0;m3@o*8HTi&(Nv_7T1S_(nkkgn=d@*YmY-<)$) zKtinvDixLYH)_&suUb;nRc+Gjb`#Kj=wU1mw!&`l=Ojl7=J_U=?Egx2=mBZx6qC~2 z9E2kpS6Mw$f^DhDoaG34Qpu}^``jE}aZ*#w3YVK#qqHMNlr$1^S#YEI0nELDIHTe7 z7t065eoW9OPWIY+Q_i|1Z?XV+$Tb{#E^9qWnaCE}Q?Wef2_bYyE;MSPrl+Gp~T5Y^4FI)Xw0;Z<2PJ(NwA&4i^7J~Mk`g_8j$7-%R~?S zNWW$OuZJf>j75Zj0|0QL{!gNNlUfAlZ`=O=4*c(%keRWerLv>3gOK8XO*~sg+jfHk z!As@0iSq&q9LvZAQQM6 zKYDaY-Bg#OdMAdWO?>A-;PwWEGTr4cO{+vs!>4GMBDAB zrKVvH1)`f5FRRYM>+S7!dwwccb_4^cq^yY^a+a+nzSm=6pVf~jf`bPTI;V=XnbF-d zN6yLJA(jtv)TeI;g)VNDRYfpKN$62iiP#q~6-Z)&1Z4?><{!!_l+ZbIbILo9Z-X|; z@QDgRXA5NV@376uZh8(Gi}- zz$s9ZMft{l|H>O9y7W2U?NCH6a(lm$DM*OH5ZNw7c5&XlD3xZo1wx{KXZHKd!?|tC z)&}XFz_IExYh74-k1W32h>o{kA=n+q{JN>-#`?-G-|FB=;}LTvMhyMu*Cdtp6~6OG9K1hOXf^Di)5`qZGWfavy6pGOCLMlc zNjgS5rDx0#`pn1-aX^O6jMhZ~^N~3!E-TX=H8zOR%T)?2-y~(0kGJBAhPBnp)2pK!o#Ebp_*6>k8JS5uFciK8E|rrU&Kc*D6d;n+?ksVr8a>k6T|uFW?cRr zq!Z+~KK=rhLlH=^gOZq~GtB3o&9`=FuR>mzSa!7SwYAk-t4*%DJ3`i}EOao{qD(;e zL2QQf%5XPQD`a7rE_ii~^(%Gh%^bLEN?Ix6U-izyJW}5dX6Tko^Bjz<qF>X2$wP#typXHYT@9%$}o_^HSWAyaX<^H-`TBY0BXZiN$4#7t|&&S=NY=qAkS#Lws_&Kf1p8K=ydq|BM7&Re7}n5WHK zXD-@gE!bu)I_5697OZ#`uLk^E53bw@uGomE-i)r>N^06kY1vI}-OX&@EABh296qid zJ!zOYZ5TfuSiTxtzggP9-#C8Qzj!{qdA)gje|Y(<7&>U0I%}Uj>t48++r3*kyl?9r zJ-KATJGCu!W3%JOHz$WzNBb8C z8~dB5w`a%KCmTnbTgTggi~YTGz})Wq!rtQA(fSf#dFyn0?Qnf=cWwc&uy(Yzad_9 zoeiZ3Geu#Wj>zLp6quZ0aqY#Tr4?ulX7f!>pvUsK92SFW719!AYH`jjOy~;~<2ig$ za0Do9mWViXl>bJ#ZIqC+>p3d(Gh8goNO&F0ld3={84Q0%Y-`n9fyd^J1nqiKTOGm| zjyO`Rz%5Yjn+CcsJBAHt##v@s=4UfRl+UP8YdjH@6s47>a(J2BJdlPRU^Ft`tCeUE z#aacQw&t|6S7Ok6Tv^U#mcVM#nr%;he$#4|wW6`~8MaqQmrPj%pEo=fF4btbYd5$a zMupO*(dt!>g356m$8aink+t2b;Oj3IOBjQHE-2FeEl%2^YZxptWVpZakY(&#HHqeH z$?l)x0TVCKz?ASRj<9BnC5{k2vmB72sk5bo4SPLIf@Nq;At|KqY%(#U?NBmB5cW|b z9>R%pdVo~&BIcas8Ev|kp}(F4ko)6)c}Da7Lz13h=l}~grya=_Rl-qGyA7ALU0j6l zE$h6KiL3G)EAsyUrdCX}f-pTP=pfoJ6$)k>m5}tXbyvY+MR}NEt|(91ayNX!nuu?G zFfq&QB?FzT=*w=0r9Opw2tza2{O(gGWbZ;Y=4dW2%yG{-1K7}g1h&dnlTd*#WA#-jN<=!J;mImmtu*Aqbgtmgi!UCV^2~KJ((Ke zs^s4q2zyd#%ol-GgUZn~og9zH-vC)TmUqtHGYGsVn2e#Yjxs^hj6>~DP>*JVj3<4; zsf1#BT8cr+t4%5+aaJwf74da7ZBB#}w&;;D6=YY!lSwZE1%b)Y4NUTllLb#Qzc{iI zko=M|J{0nq9TYDCsX&$EZAejpAx&uNmrd;a)9{$VMkoqHDK7;C0{aD37eKZGM=HlI zN@yxq`PDg|DeRW(Dj|F@`mG{M*CiJej3~_47eOsm=tUzi63{P%z1OvkqIK@9n z<#NR_GI~BUYGY{zArFHhCPUK*bR`B4yLbZ(FGkb{M%G7$I?kMow-<~+50w%DD;Pio zN-+p$ipVsY020MXwH=r$VLV&BAyloDBTFqXS=S5mm2x8t&-M~9h#Ek*$MX!*oDTvl z_~%9hbycqsZnGGxs8}#OW-nAiXLb=FbX#XYolOJ^8DK;d$J7T&Cj<(Ol|Uqj)C=R^ z8-%I_1og);j6J1***YNz@9PB;r#wG#C522EbZm(ZfD9`I2Mo!!O8~1zgoKF%1V)Y( z@umUPiB=o{MB)id{GC4sr%YywyErQ$2nJGyGEc@2T7gJ!wpT>)A_T&70|~1k1oBj$ zA4Gj439FGGgrUR)PAX*z8k8VxZcE~|xEm&PHYk`WWJy%31WxNs7D*%p1S#kk@+L`K1b|v}GK^OS#Gff7Po$e!*c;c|i^2tnp`;3g zlwtz;@4p|5223lO0E&QT1eKd$$n_))?*JtRuZM&$f1#A16b6f_P$vWmG7Ewckq-vO z6bLPa6og!ypFx5I46L;lh~U@@0)b`1N+%63{{{+gIxDp;hY}jJI3kPF4^9?A1Pc2n z0GyhskJJU}I|#|v2uzTu4_d(}2+2_h6l)X+3?=|fPAC|AZ#4`Ll{t*fve=5UO&7*y zj*%U;Y-ToZ0(hE2>>bE4gke%?FA!Z3WP+pu1VS4L&h#?tuq6-q7iLW6k1*ae7gW|jZ$x|`~BFs92Vqw{WV>t$Z0PUefq7QM- z-^R0kC+r!37c5E3P$KCWO9={}fs>NmfI!?VK;Ztd0;d5Agp?x!!ygs0hSd!qKr_L~ z=^bQGNsM(9v(dqgT$CO}LJ!O*#cYm{DgpEt?_FW?fjLnW*DxCQpaCr99ymM}Py#C)C>Gh; z_o#&XT|iNys-thPR~V8gPT?RjL@Z_~;ADu-_aF*!3Is{$L>SQoDH#7I08+$XI7~hp zpitF1zA-yYHFz7(X}kBEKzl}d6^Yz_R|Ml8Dv8!QFxJu)fRb4rQf0w^E@w$Hu1avu zA;BEwOjU@W*{bTCW}3tgcR;vygU)b}2&;p%k2w?(##a1ehUWoTU&(c6{%O%_X6cPa z85D#y3^Y{nP)erjStqzC3{RL^NO0Q<$;=0QX|nph{X85(nOondWJ!vjN9kA>xH1Te4r}$&PZwh z?u*sv9q2DX8fHl&hBF@ABp4rUWBHp1myj%i`*AYTyXSgWBsLtPG8;<- zcTFk6U6UfA^3R30PuRx;L`3S0)QuMyT^s+TWlAp)bpcBn$ z=_Ms%v#b?%ZJG}mx%lNl4<=C?qjz&s?ns)4G*T~U0Fcz90ejW~!;*^Fgpx~QQbvMV zYYNO)EPKw~&nIiU;Dc%pb|cN(J{fkObbUpdxlT)oEWDx+fLyccE60bBEYU3`%R`7} z`ps2qF(%od46D(U26xVQlsH#t%3uNo=u^u9 zMZy)DO$`Qnnd;*c^UIoRJw}U)Onj+EC9%Qg&kM}&-u#jT&<1PlHAX`s>zk3;^;sPp zOCQ)$YGEPyr}v~<5Xo6F+G7kv1gtFDJ-KztvKK5W$W~yI4y3AEF)~?@qJ}7JtwExh zvC$y$YzQ`KDY`Yf)-pc7Y^Qv?PdjPvhQC=E)NkQ9LE=;oopQ#HpgvE6~Z@ zf(Kmab769!%O>^t&eIF|@+ce&L(v%8x06LiQ%Op6SoNmN`}bM{F@E~@QX|3}ConxB z2_~d>;uOU#8?%}{lwXE?LGR_uKJaGEIMzjnM~ARb^8FTWLn%S|565ynD>`?lDvj-u z=~2?P$Y7@|(l}Uy94UJiV9Wz4-Fq}eJTVz$EbZ`MeVxp5-h2aYRr<8G|rS6x#a~e@gr3Fz-f3uYItC3 zJo{>GT?eyc@dw*5@gTrq5=uZ+wiLiibgV)Y-S-9N>$_SAz5B<*#{t%#wZP{%fp`w8 zlP#|@vI&8kg3rIW7$y#w*s?c-Jq*Re?~g&*lDg6N0|bv*{QE6F$`@X0R$kIJUI?l( z$EKVA!Zb5O$sU7Q2Yax3zldE4Y;S(S8WhEO=+7%nVXQJzbx|fNkOS=4fZ{{TN0vJ&y|C{FV9nIt_8R2_I-jNkD0q*!Jmuwc*#_3H3Ta zLLSg{nx?&EQF!9BrfOghiY;FLTmQ_tfVm2%(pRRt8wm?bK9IV}i1j)Z7nhI&U&-Er zUJ${Y0wQP0X;B#F?`ex!+_4C0ODB;uGVIt%tKM$mZ=`k3jThJT%M}Hn7WLU`SriJj z3M1;%}f$nGpDMRy(0)M z4kON}p6}LlA%%RtOH3MU`0NRTleh&~93(>|CO|I<2lrA{IY)BdM z%CM;&mxcZgZB%jetmO9=6l<1n+7Ni#V+l89RCFe)8?k`)7Jrp!0|sR=X9JC7WxyO~%30UNe;lrp8`N9t zGR893?ia13hZ)*ul_U$Q;?l*%VahR}K?`?KFsp$XJc+v#@N$>}6*UXige6(A(8Z5{ zRD%jrDTp*yN4Eh#oOhFB*H#7R#ouU)kmC$RH0VyCGxG)a9tbm2fjP~JhR&L15*e*W z3JeGBW`h}B$fZlGV-soaEf4hsiArlyun>b`LsE5#WI3BZ+O#6+rvwpMPO_oEbr|I_ zr%uYn?m$Y+* zVF^7aiD^Br8lFbi&7tgvN?N)Z=fbA*X@S}kkGxQ)oWg34+*John+)xzr}t9rq?JJ$ z7Nr1k?oV6Gf6?5h0HNaQbhOMS@iLN>;oD#u1C3MU#1I23srBxUSF{D@RCDpK>=of& zEV{)hquTyF9G_Jo?9+`3r+aD1Yr|;5a*p?)wkEKAS%)s3z8qk`n)2Mx=u|5nuC&)W zRC|;J)cmh+fH|!f!NBz?T!}xI2y*mtvsy3hwApgoi-%oqZg@De*!92+Y%|e?Kf3NV zIDu@!htBRcI?+{DD9z^w#%US>0RB!3JDoP(D~I3e;O6*8sbrf%K8cPTq;1AF2V^UJ z8={*Pv(Ah#LTc{1ar#p^{u5<1SVO&7a~uSsE^@7xq0!eXt*JdL#4F+Z!z~|t8q~jA4*5pE15E7j%*gi=Dt27SJ;fFhxW_~%*6kXT zZEt1b)jczxv*9baj=7=*`|KkbTTn*P6tomS?1oQX zdO*x!*SwfK0DUH(Ezqw9OUIGvW-^cjPgPGsk4Ke9RV)XcZ7jRgzsvm{o(Q>gh0jsg?yThsyQ9k*)IcX$MQd~0r+s-o|*`tZ%cmszG%tqnp@n@>p@2}IBbo=xK z#VBc#wQO4YiX#$o7vix$b5t06>=_~dZAw5Bt^EjzF=GbV^s9D>Z@Oo3&k~i2 zGfTX^)B9+r?A;tHl3yZ1WNFYB`c4lz-`^hl9Jcglh`6Nx!-dE{xX?msFa7q_@@*y> zH3({SsBABM0r|GQYg_P1vTNIuhvK@-f^d|!r$@FlsWggof$i#1LBM-Z*E$FP$@~0q z-SGNdgu#13c3`5?fG)(uznB#9beH!YHVGk)eT5k}yNp>8+iQS4FR3AC8D^z2G7NtMuT&z^gb8R#{<;jW_~r3e%m1#lH5MvC*Q zV8dUI&Tm~l=W&Bjp||t!$^2mV3L|q*tZr6XN05-?u^=k!?XsTVsSV8qil+E6;XVhP z-}whak$yMp%3p3hf&rt^GMhjnm{vqiTcEBr3gH%ngCc0fMjt>KH0Yj58tVqc419&w zu%Ch=bIVILVb{4*8*yzSpeM3zI?n8#&udaY@Sw9HE~3g)0-xYyfHeQR_kMa3#gm9H zaFFi$W{&ydu}e>Pd%OEs>%sju{|$tKcD!0vH9Mu1*x=^NRn?7t)+333u+wf^irI~B z{xg!&>-e(M5u1s;QiJxAt-!P!tSMx3feM`VN27Q1)deM**abcs0V&4-~YNNVR&CInCz@lc5%F zkk3xje6gyR@_-l_7(X;ej&u^{+HIJO00Xa9GMm3d`E$O=8C%#n064BrGuV@|46v0a zmrb4R!+7wnWii=gjFbc1JA;Fe4T8c$W${rwDwi;u0M-RJN0$m$m`a@8BQ8x)2;?Uu ztxX_|NNvzTICf3YdP|amRl6zY)qg_!%U~uHHU$Bmq)Pmz#ArTsCZH)<)q%lykOt)- z6O*vl81r>>mn3?p|E=M%F=v9B>L6eq}~cY^T+2Nrwi~ z?B)+66FgMb5-m}Nyao}>&N#|K2e$x^JJ}uhn)acFqNfimLpz%r@XwlWfSZ-XlJXs-)jRT8~MLwvEF9+6!SMnszU5YNySOSeqXx7uOdAtgSZ8l zl$9gXuZ}AI36VG;9aPPIJgt0?wo+5 zNWNa%jk%&Gvh#&;=D2~2@BhVzu?N%P`77JLzX`%nEl&`XBbL_BPd76CuaD@^+^))= zj7-39)G#E6bh${+P==#|bRVCD0pu{XFM<)yhEJlvr`*H8V!nAuj@(Ib){)RPKYn8d zk)q!MLUUR6Lom=n@mTbS?<}nx+~p_hM}*CZzmc+@QF>^@1`D(yyB?*;pjR%rW9@V` z)L*HatWh?!CJBfz<5RbYjqQI`i~+;lfp>CD`CGlf7^2eESUOYPMh9!D@P$miDi_l&}0)`6m1%SsT`$`x+8GK>dN30g~%bjldPWaeSm> zurlfc}-z09cP$P?RR4SW4AB^H63;1T= z)zD0Geg};$a{H0#hn-RWwLMN6Zk9zOHN!JM-P1|J!L>fV8@>aNHU)v-OBTMVo_1EL zgf+VJK1mMz(Vo8n*i|vP{VsA4tGhnD-~#;bl=_>9NGDslLO@x&{(p7`>)561rH)AW z0^dKhkZ+#CM0UQF`9j}U3m>4ix9SOw^zXeK?i_-%ZrOC(aM4b{*vLFpnSyh6xJOyy z6AL=MuaOetOb84hZE__{E~8^gF7Y?6v0l{rq4 zdt6aSvRwG8V<|9bTK6<&H_DM7E_@p_*Qgnu zx<3xg)}|9>scxGZO)umr$)G*ChL@sHZ9W#Pb${;VD2c9fF%-++owV5=E*@TfN3kuy zPSTPNJfsiwuXPJOkfsJ|y-504*KyySvbzx%7^(*Ev$!>~4%TtQP7|m^88SYP^~cRi zJ}EZj#(zH;sy4QpJ`ykxFR0MGv2 zCRlEsqb)aZE{r|5o00h110U{{cD*Fx>k9cbc;#4V!j7*N;+1WttML!;$(~bjQU2C- z388yb4i;fTHEbTkw{6w}w&+yn<$}I^lWbA^J(WL&Mk}#R@ywO1n66TVF%g}*ZCALL zW`qttGD8&Q4$B$&V=Syit^ou!l*kWxqvRw zScVe#RCoDn$zV?2SG30ZV$$7Gd+FPNGDJ8_sWi5M-b;vkh4~ooU9ZezyoMNUR4xj6 z=to@3EZtB{7OX^{5E{jpF~mDjWm2a!h&=|zuAP9)!a^ZBpx`r=Y!AdU>qx7lCn zSZDM+l`K(Jd^yNOS^u!cxrj&Bw3bSNWcP$T1VS&4z)U1R(wec4c>WLWQz*~t_;d@R zL3WR+;sI|^@d3jsO>3tfoez?fJmpFIys8!NZkDgY0_q!KM8e)B+_aeOfHq-<=vMsh zD+o^e;QL?1pdH)i3Rwu!)@0K-*>#GwgzzqSaOdz?F$i9|Qu)adA~^1dh?G{-xsYK( zXGLv_jh-Q2v4;htmnIBh++BylwiM}&ki~tSKB6YM{nDA3eJX6mh$=VNbv%R3`!Kt9 z;C3J!p}q22VpX>Xv)23PAnr5G^(tvfZn=AI^s{SSsH z85h@t^lj#%5MF&wZ(Qlq2#>bR)3jFkP1A4v+mE{FF}3~Yn1`qOy7c)M6JPG!PMnh3 z$oVHr1o&zHz^PmP^;ze^!lk1ejOL(z@5T48tUpSXxvE zYt&A+(dlrdfL zkZ4!jdJgBv;$#6~zV~+v*&6nobylp5aVsV#2$YJ&VSk{;BwCG&$(ZxO0JLSo>U&>3 zd2lFIE5f=ekm!>3NKc27q0^JViw&;3{g=GnNu^IB5)&kfsQEmXE#8Fa0V9ba=$|8C zrDX3US*G03ijjh)B){h0J$=*#d8`Rn@MVcxBR;rx=SCZy9kxkAIgd5FzItjIp-6~U zzIoms>LshZ8((!RS8Q{iXT}&mClt+kjCqS0EmNGw_9Mckj)rP6>W5V*D5s8WIcz3% zVzpv2KXHd9{8?l6Q`kYUwWJ`A7ab&m?IoSD8?MyR?jjNq^%4Z0uQSLjoO}^&-7|53 zb{!5)p`!Gl&dR7sHVba95nuiVH$Dcu*5{9|OQT6%pc(jvE={4OgK~Xc7I*JPPEz0J z*ez?R3(P_FTqvPwoPmjJ$SlOy2Ds^G_@ z%L!v?ehLT|8zjXlvrt=H`~wi+G!K%c$dM-lF8{yI0pSZp%2t!X1M$(D+lyOMrAFV8bsI3glHdgJTr}0D)7nZ2YukrF7#8#b zO_45OV@uD!ef?P5;De$s!yz)i^=ziSY~p5RUhAGDf~_tlo(O}o3Uh+(-i_9GtH}tC zNY`T~m`}ItDDiR4l9wDIBMG=jdO!DO7B%4cY&U{5*IlRP3(}#r=%r>R)&%RGhC3)f}g_=jsEz z?K95Ta9a)Pk57FI8$x9;a!SX4oguUSRy;P#X(Rr2rI1qzf^L}h&%1-10a|3XvB2J> zmD=Wum5;hgqT!=q$1n02&lFJNCgofpMw8TPzL*6DooZCtO zwY@Lf=!g(t%Z0%_+AI^6C__1eq4~I7*gaRCLv@89rW^>zf^@o(f~ZeHYADCL9c?7O zgFo~o+Bf@}1a%k|fwGP{X=C0mst@7x=GqU$^JxK~Cl)n7?1yB}QJH|iOGp#X0Y(Gf zo=KrfmFo)ofn%@8;BZIpdTNl7Tj##tBC_tgm1|s2z4W{&6=fBCYIRNSmk|GOgLP))I->bhr5$KzawWr*p$Bo)1{`{hv(0n0L37Zp#U zNTddy+7WM&o(E9oqXgTBA@RbIr*42GFYyjuOt#Q_K@g9g-XvT)2+mme4PPH=tVS{<5g;2vO)(=GX>=DwXIRD8ZGN z$Ty`+L;}BZ!*Eeui%q#tmF|-W8JNyU9^=oWy@|niQ<`1LdIf-=Y6C&4!es#Xyk?mIb_)rvD);WY z4i(VKWIRiq5+TS-eJ_myTQM^h`|wh>TCJUWxlV~h6!}J2 zrVmne%o<~ewWImiYmN=>Ic251k>aB*kZe*V^4Pa3w{KY7(Rw?w7xj%Dpc`DJZOLee zleZwIUTH258nuCqE<9D`hlp;AB1z54q~wY8X-M6(>yM0wwOw`Z!~QbqD{V4Tsb|$1 zI8S2o=2~FDWnjnL45_669b{z$KR2uHM=zQ<6_!wPoQ!?h6!7FTbYC&vp`+EToZ8U- zbD=l1|7vKj{GThdp*?HjtY#t;xjdyso!YKaWL+bpsaoAiw{pG(ro_&U!OlioM_>5; zY|!g=$RZLDdP+)>jfxu?0EH{TehxS~Ive&boBXb1fv`hOFby=aFML^1fHVc~)7onz zvc-aRKvK~D=dw($3F>$OndX->VM1HX>1R*H-wdcnS4fA>mLueyYP7e=H>IDSr>c5i1Su@kL@6o00OQsjv*EO_50gS({HP2oM8UK?OF9=Cs`nm zX*M#0T^qvRDI*P5;vJy9&TAEs}PPY@iW1Qg(MU$hbCjf(GEpxqK<0<66>oEk&W@ za;1aztI4^xm4fyyl6vd^VHiK6spl?SP@)#c%(ZZuSg_nsLdf0`11`Z#DB zK3-;;(D4>eL#wA{?HE`Kh~}Jr^vr%lhaOGTvgM>3TJtdWEV~-`*PnKNSTA_J9+uwU zoy#8|VrEb86aZYm8PJbW&08t|a(#F1POfA{ce9Cwh-bAo4ZlabZfAz&@G7B@7za2i zNH*8WK)=R=-!_+BKod$cyYR$#zj|{xxuZ{Y>re;wwZ>jZ;UeN_u8;L&w}lg+~1G z^Q<{n&v=fcpkFFq54Xf5PGtMq2n7UGFXEfEq2Y0+uHm0U(k0hlZr_~)#2(N73gqPJ zY=xvH$j;bh*>BnoqI;ijb0mVTEp{~-9%-w6xnTKIgPr6?r|d8)kZG6>=>`*A72y|w zp`|t;+wD2y9e?O^LXwZ{BRs!8E11)ivhb|NO$P^+pA($Pt2y<2}nr??! zw6j>tPuV3$U3Fn8D;>rLPTGiZM%xMWh|ztG=h`MJ{_^v1qL0$nW?#=UBecy7rS*@E zWDx*}GK2li7G1dd7ujY)s-uBUqj)c<8Efu!&#}?GZHN8zs$gz74r6Ke&*HGj`Mp&} z>iR4Rrjm1&?NU#%L{*}uwU*L?zm(lb*zNS)%)aR%oBwQ@-gZ+5VI}9NvtRvNbol#! zbOs&b%I#)931lYo%owbV-Hod? zbQL$4(EK@mvdD9?6pbNtOGTn$;H^+AkS3PgHvk2sb;^3iWeUmQ@10w6d7X7-BV@9c znPZpkeHW*pVx{$YUV%e7DtGtWUuh!7p-JHzx*NKM7&Cu>`KS6C3~$Q7OyB#_HcL%s z!)*eBZ|wf+MdIq})?L3u;T8r??UgFc_du&at4G67q) z?JF*1g}I41yS*iYZg_BL zl7^u#-2`EevygEJIpCg3?JOx5x%t3pa`|}H&Lf!X%G*|-Kc5w&X?q8?yELbQs5%h$_`vrr%_P5#ZU0kIu<_fj_8Zzzry^t)3&e*VZ zIxOZZ$49gWZiy0}GV=r!OW6$W_+l>dVJ}BT^^=Q}}(&}a22jd-ZzegpZ zyVFaZ8aBnf%F)F6(>}*lO)G4BU(`u&?~_Z~e2>mu?DMj{`TQ zFf}##Xstzsvk1_)(m(FbSZ>rI#n*3gwS0JdSg@$2G7~p|J~mfgT4Ic-tl<cNt<|1}B=Le9mks z+=4wY<;Z<(i$|PKoHKewXg&w_ratr?JxCqWaRA9#f>Xx{xPKI_HLX9qhifT6Kz1w} zC?qpU|Hb|O4g6oK?H3+~IQu&GG|2s7g?=C-E6qVC}N z5x7$j7I_Sk@#s_gWjA-XJsqbt6nh~BNhi;yS6QRr#t!33e6ECtv}-+F1Ka_GL{3Z; z7e;-xiLRqD6KQ;XM$a1aaH3ZjwhN89CiwaE> zDAxeIbGhikHObYDkaZ2VxWc(z>g}P(|(nkI5RyUR;) zA~yyW`*i9wk`k3whqZ-ZD|0PvjAukfAT`^I*<~lx&kEj3+fMtz^6jhTvx-9FspMiZ zZBl+Li^F!u@n&AQ45@4&9g*--Ad_@@j4#WI&?s*sapLp{kIN%qW9rb=X*K6Uv^u<1 zU+)Xue|xF(BiFZ29r&2#cr=vs{PaA!1`}PMmga(f^SAeJ2{(zc$0UHw(CgN#7l6+m z_g`mEXH{+0gSVBn_TM@~Ep8?4IYZ(LRE@22nsaJi|9ej-i`%h+WcFb8rKB@dPDMOI zE(2aYpQ>xEPe;EkCH+gI%g8TOi{a^P9By^5=DW$0jJLkG(nyNA@{@;~(_!6McvE;c zP`6`;JV8#U8n4batEP%W_leLk*eTPgLfpa{Nc~HX4P5eAfDa%V6>|nY?>zg;wr63R zd1>xG|9E^dwY#m`2C>#nw&R`P@p1FIO~B`KJ=mt}*~dYkjhl&+>BchucT11tI_rn6 z=gnCDLH)te<`izceM}b?u0IRkgQw-i>*`74Tw)pNKf~=@PiE#X-;cP9>8?;8)q7Qs zUmlc(3e$AcG1GC=3{%rx8Cjlew-1*K6=kZ)@syYX41AuqyZg`a-yd%ycrP~JGvGj7 zFj~g0)^gXfo(bl=9gwIrVY##Gy{*VH>adtrZZ}(&x7q3!j)}TZC_P=YSN50E-QFFy zVndgvnldQY0vUY7vi^5OCOfD;X{PHu#}O@Qr#}=9`-97CvP$Rg(xwDLjKmf?i5&iJ zC9h+#LPPfD3+wkWS|>(ac6~+n7Qsv7(38+&FbP*zyIR^zRvR!REoZ#U8*wr(<6^5R zOd4!YwL-ME4}@P1WQN-LLS?v_>W1cVX@CCyDbBWx-k7ad7xvWLptkWZ?zh!d@>^dZ zC)z_$dARUi21r#%D$XL5RVgyoywqOCHz{`IeX?8pbg6&eGTYQbxNCdr-6O2ctL505 zuYP~Dd+q*SKyA}`3OAe_+U6E?JJ|W2(!Xr|cl>a@dFTLCxAuD5Sjy6oy1HkVZ_;nn zT`;Ta71SBc)j|)Es3c06OX8O`nGOgssE2R`{IPm}5vg|*Y*Wd%=V!oU#qnWx=R7p+ zi7JfFzOx)Ztn_+Jx%q5uk6XZ1Rt33CJMs!r#gsB5%#v3s*x;A8)HnU!o+4&)k=K*T z042ijK7Ntk76URc+vu#3&hvU{7r3V}$4q!BuCU!#bQ;WJwUvs#y4$H7Vp;hnqq$J^ zsWsSuuukmPP;)Q^j@0YS4{g| zGZr(gKld+VVr}KBGh2=QCxA!Z75(mTsi*u_giq1zlsCntUY&K{@9Mi5J****_5kJk zJ&E(y2iwKN&;cj=AWAeZhGbr1e|@MgJ=VHAB>MSgYpZ*~9Z{9s3m}c@>G0e4@7DJ6 zryY){T=phP{IVu`_!_^eqpIqPCcDmD-Y+5#oH#`_Z<>%UE`Nz$(iewpQ z+`&uNxI4!ew*;Sqem}dNJ^8giS;1}%s45D&YGSu{PY~4A!fvZtUyoMlu!kVs7MypF z;>4sFM-14j5q6LleLwMBaH4o)FDh>d$DA?*;oh0ojte$<>1?IkdsG;=-Iq!0wVj6< zYXvz9WUcVw2Tj)h@tS*a8FM!dhS|QQ&wHjh#6Pt#8=|lo0W0HdkqqvR;aMhEGicG0 zf8jZEYOHeB?$&#e|-%Ccj7T%N!7u79EiV)K?TED2}N3|24py}(!Six=;n zUPzUhh`%k%d3tw{JKr`26%e2te#dJ=4|je;LjLnnRAjZjEM+*i=y@&Gd2JCEUt$RE zo;4fr&{Dcw(c9YjwD(LW(oc^=2#u$Zge*{8gI~WBRFA*rv0nZCp~HZj{9ZeyFv+r0 zFIU2Vy->q0S>^t{xrEo1ci4NW(Kc79$TSWsQ!J?LoO+s`j*=2uH6JaoE7sc_p6-hJ zDzNDI37Ad&o$1hpza%qC6>YPlcSr6MGpR`}B&U#y*h4TAT=o+2)*++E| z*LLx$fUd`(`<1~|BS`3V_Ha3MrN4`4=b=Y!jgy{)E2WCHysD33{W${ zq3nPK?P53X$Xi-DM2_J_J{rX_!=NMsVYp0|?XjM#zP;dALhgx^!C`6r^mDLzWHhmS z)8asR4gRobA&sXaty;BP6W3r{UtkZ7&a{;k*yXjJf7fNJ<`$A;VJslFt`*s!c}zs7 zZS>t>`EZ@P+XjA7i$dOq!AG8>Cna&b;cFOZaW5P^IgT-iNZ}Y%bTY) z^0!UW$3Zo%#jG~M;9BtE#{<;bvb7uiU+dq~nBR`Wh;sn`cMiwz$b?c+(hwqi>_xdR zl!0iwXe-ze=Hzay?8g2zrY%P&5|2tqY_MZ0o=v1FR{!RS%^EYGvlps~JJe7W-(|#~yTgUP_5N``QqO~$>+Vv75tb-E zDW|AlwSnu9fky`&^hTZRN9#BQJstZ`UpL#@_GiBm#pQpQi)@1dP)>iTwAj1-a`HRA z`BE=03fWPoAKbk#I^HEdI~yYW*SJM6YbLYFHW|4>32S<}J0ji``FGD>uy3apCIXCK zsZt4&?v#tKeD_{s`29*23c9Qsyq4N32e3Fj1sM&_`RuTmlOaM{ZttGdOBX}mGWjSz ze3O%-ocTErX{5}6D7%(+Zp^fw@Q*Xvo&G?)E;{RF6--|X{?%zkfD1+pWqasfnXP~( zhp#_Fgt_4iYe6bJRNqGi|4{*J#c=vE6+o_!6}eHR&YP3D(BbMra+9Ny(GukH;<&Y{)R_Ip~Sh&<4x zqOtrb4~8S zh>2BTi~08%e*}=fanfHAwrOivvyjKyPbP@QH1!z zev2#o-fG&zpLogolQ0ZY?yQspE)>xJ%f_}^ZcpPUyTa+P8Phf#K_cyNRzOT_79*n{ z;|W|s4pp#`XOUAyFv5D@pp_SQUEm>kYK4POFQ`1!1{2Lstzwc}&YYM%6jZUK1Qj7} zmx?)JnZskI5eyui(f=<0BVS5R4 zwZzT4=2hU>7$K~cKzcSYl9OX+{+Ag_jR`w1ZHa(NZ)Vgn2+>7}l`OZ(#9yNjB|s-( zpBiWr!Nkd7DHOikK!nR7R?v^8J&Mcn(PFK63YZoz5TSw9ngCP*?-C0{xSKpMtL*ye znyzrZch6YnTsV1Mh__M?GD<^nY6m>850G(qMukqJ6v_E>)|rSHq71c7Dog>zg*fu|N2Mw?Lf zkXp@>%dx2@FjXW>Ii>k74UlA2TQvz&1j|kJ)r|%z%yXv+sA#dG2mbHNpbYp>B z5JIrb3|VJ;;=H>LyzDz=%3wQnH|GZ5L>#+u#8^)fJu8uys0^ZT{N zF7fVD57Aak)`Rn?8Fs{HYr-5IO=Rz0%YcTQAhmoiV>wGho9uP{HWyu*77T5(BnGgAHQAbfDH}@99lLxCRDF7l7Q!a5o01BLNS-!}4kg z^dSPi*YcK?(+{%Itz2gbeaT+B${=x3Ad;BD9RCp`$7M#&Q>-EkQ1Vd@*(^z6{X08 zoY^oXw&S1grAkbg9Tg%mD%Hu&DStV$33ZT#ij;vQBIrbg+f(5*;-RG^XdwyGl!GxW z@!&fQK(FW`4MrtZ4y~5}&49uwKVHQ(!mt>5 zfKhc&g4`-ZA7o(rrMX?w3vZ|>6dej%iL8g_pyZgC98rLZtPOsy`eLJupehxu214|h~cgm)zPBEpI7m1?W> zLA4JZnz#$MrU%#jH+YzVI!9Hw#!{dJ)T|o^D(w2aLnBNK{WQn$0uiu9443>b)PMO3V^N&lFJR za*uXowgQDIQT5!q=3-?C3B%Aw(0y9EA{t*-r)91#%1^JGapS z2d5%P3>Zxa>WUFjGQ{!e8z>gWZRqY03)>{eDfAJ(lX0n{**FQ}b^X-asNQ+$6z3V2 z-!D;lD*7IUP!rxuO&cV+U{`gdjjK+N)+jLoBPPE=O$IEo7$QpAimr8#M4X1r161@;20~pv-$qw_3MiZrRX8~)`#red6^Ch;g5pPerGQ7Mr@I=qNE)3)#-IJi)3JWqRW{rf0J$&* z92jNB0Ax~oPlq`ZLPzKUXADIzQzB3q$!BrvlybNoS>)%9uy!p|>fcO^gutKcsLyPc-!ov>%GGPvY7uR3Vla7;c zue4pHRZ*`xrMU{Ogg4?>2sT(uoK}WmuV^QC2>UQ9gf8Oo8&R-=kDK-Bunn@l7`;1R z--2oY?ECFH4LW2?ocZdAOl3AFub^6rKw}YHMf6vCjp9rRLqtp>05hb*G#Ln<5Pd)n z+6m!mY{@QQM@bNNlB&2UM(2+$SO&fAVzIB$7vpuG@7h853;@Zl?;h{KUX-@3_A6ZC zz4QEp^}aOGY(*IB?DYJBI4;@!t;sZ@y6c_X^Z;RziYo-* zWCqNG4n+`=DZfx>CFr0-;4UdPcL{4biu=SMz*&0=#tJpW`lOplt%3Ul|Wjq#6H6VGQACVbf3<$F# z6k-Ex%QF~FY8rkPG!jEwoVGxD$hqx8g>C15CY+Lt zF~t|jtpKCddFtW6lh^bWE=+Z`Rln7QK?NrQ)qb5VDVv~jdZ-!!=fh@E#AlBh2Ia$>?*S+%_% zyG6Y7UZZd6S5_;#VMM6aFD>-YNPq5>F{%?dNPPt_TH{ks+Z{Z@&sWr#>fXDwZtJ?> z$p;{V?^QyghOmJ`)npaZh@QRe3J2~Cp-9vXBS7pMbtC^e%d|?9bZsG4Z~xZ>da@b? zJZJmc?|k}Pt#fP0&E0mXC(P%%I!m1&2{^06kP){&wwqF+?;7LoLMzmU(4JQWn%ZG0 z!Nf8H>-xElR|346cCd(+5r-_*b}A49roo6(6%)@9IRor?jaAFJB%k)kFV%cMAjW*( zbypQh^`%3o?H#`LtTy-aHNIjA8G%kt8p3o?&dwu9=Ct_ZVROk#s@DMDkxTvT7O23- z<^9r$h`o;I#fpSJ44?R#w6pw=`Zc(A=G9gMo4dC0BGv71s9E4%P%c?>WJtw# z8I2^)0SnHM?MS0p)$PU?^WLRf;cMClT@#J-^cu>-UbionMz(QkYOg6ofYv z7zVeC1%wSWCIK|B$YT2*+vMZ9ZbY)+Nfwjxs?}oe7!O8S0`qh6DdtP%Ze-1!$I=ds zl&n4NLfWeao}M+DFy4|q881^Q?rmGO`m z=%?ug=&irF%HFQ;&oO?w<*G&L#GW%owNd+~(~{syLt@@zw-pu)Zn>n!;Zm)njR9zB z`naLqr^QP#DnI_wkbU?b5G#=Q0H76V9o@jnh%2(h8iplaGp|YP1#tE(BbibJwA_7x zCEbFoT$h-{Sqj~;KMp;X5Pde$!ye;x@)~;i*Bh5*nz6>*nC=gqXj`)fvo?tsuXkJM zt^X>J9ki9zrEqj!clu|MhaD@X*aCR+BuUbM;*P_Vxic?~Dy*>LNBU@M@+-Ay{;wr9 z&jdE}vu3#5nWc;dA!B(J&QffPQ3bvrD% z-ytJw5#a`Kx2q*lb5iFE;y$d@RCuV}qp`e4h4D&F~+07Wc+u00CF!{?Ai(14;nk4x2=nAiBgeP68jmq5umgQj~6K7>rpji@HdU>)7*=9|Ykh}zeJ388!B z?d)4L^J&MApp}}$aQpfP(}b9jT{aIJVJc^4UDCvczHuiE>w65F6&_De9GBn@(fMj;+3Ol#LOI=I!o-0;4#M9AGx@BWK z?-zRQ1E#AVL{%o{hq`p7+!p%K=wAdT&-Du=D%;l2=$9uXo~y+rnNaG{MXBS9+7H^o zcD4L$W8iptUzcC&UPnzu6g266A~qpcgi~3ULR6~JFb_QWHou{w)g1%?RKn31`!sZ#1TXK{fAzUaM z`^%VaWNuXy_T50^&%lWOAF@CrN>uR+9Gu|-yjufoZ0h*1mRMR0OsWAoW8Ui|0H_yL z78l<}#uY0Zm zyQckaDQsSUh0u_jygHlv{jKQ*r@HnZ>OV)2?>{Cp6&qTvI2p(1!F}T%^`A3ypfv!7 zGV+ZP?}Rf{7N{67h&w>#83o_ zaL17yER$bRTH~-$vm4%56LS`IE}y?;D1}#4=~Ni_y4^?=^(to4`9~Rl>G!3MZa$<` zb^s10-6(J^;J~ixfOwV|rk=`FzE>l#6Laus!mC=tXiuDg?&xC`yCqP>DSUIJXtRsi z`*)(uJw2-$`A1OI_kqhDS8l%;Y2Ddt}6GT>s!rDvVT_lo&B_fI!yHAd4=S@hbAR(i(QJ9a^NY2o>LA?uP) z>KRU0#IW)+NrK~so!hjlAJ180C4h(YhRL^$4l-qI5<HE+ubT(=gLDdp2Mt)khbq>%iBz9w(t*2SO^m%zN_8Wg}joji}b=W7*6 zLT19XFvy@DgP;Hq~7SVgv1B7p|IUcwTt z0rRGI4F^JVk2P(a;KBbqg)?Y*VeHC=iM+UMWSz@(pSU#qra*OrA z0+6*oDBw8*8)QYLu_rrz(66YdUU@x;%#a8u7t~W65u|Rt^w`Re(|RmUUdIG7Lww_l zqtSZ$8hPibjc8~<2}INRDRa)(wepkc@Z6zsuL({*(B?4%w)S~Nrm9xd1M6%j$ij`s zGq1(vYzij{;+V*~96^$~Ytx+oJ3hil%DMAvLX8BvwgJBJdb->50l@7@ieId$!D8zL zxI5+<6uJo%E?jo%OqB^%SwzFH|8hC<;z0RLMhkp{kYjVO040U( zY(ej(piUe@y35ez1(1nw08i!&Iu+u`pl;H!+m81JaT68KINCH2A3kX@?(W6n@6-ms zBt&hf;C5TU-FoEAQ$Z-2i}6(p`pQve+0OL0t3ES*5E^(n-sh+X%5eKR)8q@PA#Sg0 z)t|MoL*}$vIXBX8!&pihn~hMJ#Pm|ngtwlCQhk9`%sC@!Wc6y~u2kmS^!Xczyep+x5sq65DJJxb1%bhq&EO zl^rO(9&;!pcKa>Phw{~Pfn3FS?Kd5d9Jc0^uHi|m=@IntqPry{SnNA`I^X5o*|o@tGPlyK0X zg+M`b6vdEpP1IHiVk;RQ;07Nrje2xs$3)f+Pcqz<#?fMMb!a*x4IE`LGN&bf^$3vf zNaLtd*hbW7?`6KKFK8wNRa?O2(ifNM9BnpNzoqK^C`U(JroSBhxfG+l!j7ULzFNct zQ)0dc#(WJ#`1C6LJQA}~`m!$@rro0Qzk!(l?#AfM0mR>_;Kz-ljj;N98E(AQYLh2`A(bvtdLMgv*90NjRSeUKnmz&|$|KkQ7O|aq2X1 zhirIfdz_hlWe9`+^NM{+pMp&`%trX~mo8U_vS@uZ#>PH=)zDBjT9?fPqR3hbwQGSB{RoV>Z7@ zZ{CYkqbn^NGURR)&ud?u*ZPCnPX?4%j8uh%UbUPLqtU*fC~Pa7CelU7Cae>@iMo5X^j?pCd!XW>rMgmhMUF=ra&!8N`m8w#@C5^Hk6RWz}yX>_iBDz zcz)_KXw*DxbbQDTvA;sr=vS@@UmaUB8SMCa69ier!$ zwR)G8n3UD3mG|J$mObe@Mh2>i1>m7^)L{v-t`jhCVUtKKC+XHO1`?=29Ujlm=|#ni zZ|w}q?AQ-aWamXO1Tialwm5bUWvTbZ_rGK&BVi}0uq~C#WC}={`|>F-wOJpr^8v@L z0Q3R4YhQEl6wvsl^vi3HZ}!TRn+kO+uhYva6j&ekyvXXSd8UXKi8w6NbdbG%yg z46ngI&OR>;QiLkY%pFDD6#3jikWd3r!{PU2!Kr8<(>H&A0qPKS3&wIOjKuGldUGT! zHef&eP%p~qB{G;qRY?Msd=b54-?gStJ~DO)0Fsz6rxP59aJ~u?w(Z6Xhk~wE5|Qmg z%TxA6L}c?dn4rQqTWbZT$=Lf?mySMXnZw0M z;X#6f1z`&{e9;_d5fmYP_|4>3f36)-US!!s=ff{J3>dv-d57%GY}ds7RpIjMH2f5_@aQuAQXZ-`@oX zMfurGRH`t~rDnMh33;&*&%lJttFc*h)M5IYeNYmfjb1O_QdL<8?C#(Pm15{l-Mz8MS9RKsi3`BO@)S|W<^Z9!W1N9KCFW?6#r7)) zLycmt6)h>*}aA+y-50BoR4r#T8a6=PVZt<^BqGvoi?bljc(=N z+K5BhWyaR-URpqM=*7qze9gn}ew%jf1|Ce`L5&26n(Bfk4D6WG20w)8l3){p*~aml z|2_QY&ZA4wWkh>fyN0a1UkSwC&;wr z%x6TS)URl)J4bxmv|X~-z(XwFdmDh0tXF->99-kL$wkUOH*}o2H3CdVN~T;ngLXAk zL=D>=uR(*zA`TWSV#EGa-7|64`NCJ-Oufxi@%fL=Cs^2SaZemQTj^(Y91$O2)R}4m zPzG()3JNKmm454c%;Du;JrhM+(w%=K1`90!H=_(6cLz_s2Db9;HRE4ARVgBKVvsTB^%~Pns6Hq$+>pflmM%0dgn>2+M)`-(K7hVZPVKUpg$FB z^@@nr**N20>@Y)%Pc!SPUu{Z{lRq@PB*8}*1z68BA@AWo6(IzVaWRIXk*AC%_$SE6 z$-Gw}l1PnWbI?%{JGhvLItKI*c=m0xrJ(++f(Ctc; z&`2w-F$AwEWDemdQo0BJ@vbx6AC%B??oT_k2|#SiL`$5*HODc!%zjx9VFPsw?-}sg z%RyAJVzXK*3lxjpaC9r2$2b!ah_096^0|S)yt-93sLdt|$o;V@CgU*7u>&xB78z|t z1dM_?907d+VJ>4M{8%XBNOD-`h2tb95vCv&3vAkA@f#%wtNuZn#5%gOQmx1hm{)c) zuLayIRMz5S(GFq`zP8tMX;a3YC;l8f9EMTgyQ^OV=*}NF4&)LUeC^+f` z@>oJ1k)u_U1)om-j8Iq>mWN8My_!qFI%%iUo9X=zJ|D7A~q%frU%R^{P`Er z;zK-##6%rah3DT|yCOm&YUt4Y35XTgfYi?Rz<4rYI!p=NwwI&2g{-MWj{}P4+{noQ zUqLLX@?^SUwlBNS&bEX_g+mI~7p6=1W+L9a)el5=U`lWuNRM8gxCB|Kf(t>pMK-FI zPYifY$>5R0TK~YmA+<&Tg`>1Q{eMsJyyIk0d2F5)L@x)-xf}O9DAxJ8&*5kRx!fs< zt11xl4XNnzy!RKBk|aIaAI#S}wz@ISCWWm{yNmQ(^&P}!${6|H#~Qm&Qg8=GIRjs> zTt0$;NZGz&ug;Pc%X&u)|4_qqSR4S>%h&f~>gc4>QU3Cs>tmjHo}98h{HTdTtIJE$nufj?zb&&%`9`N@Y~;A{XI#L)XZ1t(qnxFK zhmY=_jBivcKKwovKl5Hh%n@1q8TU~wlfhM4?Er~6tQ|z=dPOZ<%~Dtk>VcP?D-4OB z6Bz89e&Z(8o?*SjJ((U+&}L!ph{*=4oFdn0jAu^6sAaBIN&J6#Ruqn7(4orGjMO&c z@DsOgZ8`n*7&(FR;=mrKWjBQ+24n`nbpB~UDTem(RiyyJL_DOC$b{TmAf@O()-}WC ziJsKBHUHASo%~-$dF}(4&i*7wX*&xJIyX#Z*$?G^GxxgLF1nZd=NlG+0O$V$P)i30 z)-HVvz%u{@6aWYS2mmBlia7uP0000000000000^Q003fjX>4RKVs&(M zZ*DJQb#!!ZZY^zTZZ2wb#XW0x+Dek&^DD4E5HwbZlRLXJgQDd41;%zHUVdO7pBw?Q z%>*M4h$LR%zi(B))ZJ=&7;|mXjFwxqo_0)52NWk8kH8)Q8X(hk5TEMdsI57 zk85upljOPf{{1NW5l!OfXjXkeu+?dlynk7Y-?Q%3Ly{<7ut*vHIWDy*Gb* z|E6-km<|(oR3YiPL0{CgJqKIcHy@>5u9n zbPm|ppX1R(lvD#4aT2~br|RRc(RAS)dCRqP=1muqiE~Wsh7YV>J98jVyPKUq4%J*Biyd#S<*KI-Ese5*<$>{8nk(?mC*x zqh)RjiwtbpZnsLt^Wg)TMZiYvR@rb~GFwFMdfl!52q%lk>$vM#lq_b`QrBGzM4SL3 zE+`UwFQ`s|FMNPoP2!7ZAo*c9k1Dp)^^(W&-03+jK$PfvS-B!u*{NKW#?#UT;HU>M zfDZc!plz^7A|K#EE1X-eT&`GTDi*fxLF3MKwvV&up7jc6ux9u?08)K-Nsp%Ay69OoScprf#+e|U z8K+agKe=lOz`;eY7x)xH3)(z~GoU}>Q~HRo8`Z~femDu|^GeG>GF1<|-EW8I`|#J_ z|9ZS@z2jpm!&3Ix4uHU`ic$(9sLrCN_(vp&o}x6U&Lw7G1a$-v8Ny5u#v{@_^PG{5 z;xq{dV-Q`xB&703fHC;k#E+agCgC8Oh^B4N2X>-l`VvqctOeEabQ;Z0dSB0Rh<3T$ zu1=!qL-P1}51|tfUR&YS{R$Hzf!C^re5P{;x6^z!jOfO7I-Z}myV_)T;eZ{Fe60Gx z(J{fjy=+w(1la1W>UacT#v`|ZyNt<%`N2ynY`gZ7@oqO~IL6YPzc_!(TzgU-hLcI9 z?R1?$5NYjLf3qB)ODHxMwDII7^#LGdsY?A%<(yS9Gy-&4H zs2S{~L0!0OBwpJy%%wVC0NRGQHLAmSItP9qCh-iUppVpoZBIn>obia~eJGcAB(2c_ zC9=~IbfBy00R8MG{`HWGz-}Pkn$Zd_@|OvJIvcJ6Iz$rLw$tIXXn9Mi`@0WPE@}wv$h1C$lh_sP+KWi1H|9abVDWX#p*|O9lVRtem?x z1vFWviWLFEky}C|iU{078oDzJB5jN-!;Qrds=d+)m5YMT|0fF8YnPc!zmjM=su(!h zk!>ypX8DcEW6C?<;MszGd>oHP(X>8}CZjof6i_k9-<`I5*@`Ywch`y<4?dltR4 zz}N)avUVQ=LgjaKBHC-vK+uO+fhXZ~Gy!u`di6D4%p>E=Y4D6NJJAFDy{_#!LUPuu zZfoDSoWqmj!?SPuhrQ0f=X%XXK93@q9?8&xQba-PU=tXPiwXZ#v`YdlhS=WdxA#az;f!r?ym`bNF_8{E%WEe80^g@ksw;FivRvlg;A+xoQ}1Gjne~a3#J@y)^R|_{ zAd86Rd3#UpKzV`p$lV}H7s6<1ABi1>X{KTr5sK)g_&s9wzs{P4sFj)!6~l>0_5|(_ z)T_J&$ox9+*&MA^@?bDo%&>tnE!DRWK8llmv|Y|t-2|8oxRS6}G_PdZQ0~k$dxVFx z4Q+^Si#9a6$Msm;VpG?_NYH|!m*N+-QHtC?MQ%qz?j-!5mq{Fs zh_tbt3+a^*=HRM@9yPNDPMgGj0_WQ4rtzPfioF~FCNO$fxsbvV3frEK=Ls6muus4V zosN33<=og(2^0rOet40Ii@T#>HC>;W}Iy7-UCao)s@#Ntvr zjFaeTADo?0(NIm^NbcM72Iv4XXNmU8^Ly8Zu)>Eed!lbDl27(m_nH7gt&8>HAd~l zQWA;gAb!4rLWxj@Gcy@;sYZqdn}P&>sKxA32ZH2wkrtuEWNORI0IhUQ0j>$`L_W&A z7uVyN#8q@TJwY#gOY*9wtV2A-*F1*mbifjCqxDUU3tTAx>^T-@^OJOEVxJB^lFdBc zmbv^&<1Tq7xArA|N`uPZEy#h-SfIRJQffhBT}Z5;wU9ym&#Ds{a|sc4idF($ z(J!F%t;wZp-|pSPpAUC;KCu=*#UE>Nv3d5V@;`)ulTy*8GxK8&0O}sC++R^D+u%ifQPeqGI@-!D96%# zPyMxRMEq0uE2q17VHeWicW0r4*=`;_af2(iz+C{J2$%(>8U*Qqoa-v z?07UUV;4@xKa4T3&8PIHlZcu3`r6cO4wosWaY5jTo9y9BPYz= zj>Kv+2;IQla&C{i8OW5|PwX#Rq(Tb1V`Kp)*3}z7MKh0Q;y?bEoQsdA&aK2TcgWbX zyUUnV69Rd=*fR{wIhmVCL$ul^%#&)XQH-{f^GihPi>KS19m$GIt6fFHxR`7>+HZ*X zwj^!0;dIWm;cv>t9&FrFxk z!sZ2`*bd}tF~t=DT)v_Sq*(nn2nlREuNFd)u|fd^iY;r#BH`aHHY^eCB-)kl?WdV94(Oe+8@sN_&)E*;hIX(<0Ms94E|^om-Plv+~3iJ__tHDi@(IF?(Y6yo$I z&1n2v=}*JiwT>1ecWF&Rr%K*yeUxfBYV+ss3%c&&l2pBkiUSi0vZZ*c;oHtL2U-TB zQL;CKf>=CwGJzg$H(_`ED$H!Ga?P~b7CYSFX)&ENm}r|U75B^@ED-c+6vvEPpW~Jd z?9+kwSz=oebf!8~LoUbW#v04AY*oCbsjq@MHYT9}FxfP6CE22#*Akn;b5Aoq zSrdpJLpYJD{VSUJVDLxVoMy5I-d3|1X;{C&FK_97dCS54?*@-u-Yc8@ZPftHtcjzD zGLg|p5>*1E@{6z{FZI&m0ePOIG3H@(82y|s%(ru-$}xorP0^zbE0^s_LQEQJ&fR^& z7uX~#+?J;XN`xlbEQHg(R(_P1d)2x^;@H6|IYT-*WkO793O|2(AAYuKZ$I&~ zTI8%aJ0Auw>8Ho2-P$qAvEN&WBp0`sW2SY{EVI^*oWPYpX$BF_{Zg;s zxq&^{b*`Ph({nC}OL&EsB&1I1CD<_OdgX)k20V1V0)H8yRk|$Fp*f4IRppqT9S6WS zUL6{K32GKSzzLEw?L+I@r3dV+zGDK5L*5Xs0`K<5T(G>pRHQ4Z_Py2&Uoc;J?58;E@Zg@09W8%e4$Jz-2~f z5nwm4n_gTr;a>>H(wFS||jQi!$z1PPi**(*bt zIUY~%WyMh&eR*PhNLyp=A}=+i4^(#tP;;R8woz$liEk;;P|*!|ae?f4Zs%m}+i zF_d@Pj<~6$zu_j6Yn59;Kn@wZ_MPkWgavKy_0v>_91HX+H}tG!xy(MKw~x3R?x#T1 zO1A_cZe6wJlwPU=Ms!b{Q?lGXxl)9*yl}3_|HHJjZDcPg^(v$4WAZcs4hPYRCsAA) z6qWYEm5L$47hf#a3&?p7e{E57dnxNN{kZ6br{8ZfblCMR!d9Sr{sQ>zLb{^m%DX_a zuGdGmy*s*5HkvxN)@0M+E{i3sWQsaG*TgMrlGMxOuF|R}EH2T?p5T$*Om*L-fQ8yj z&aa3%0?|aP;3pQn^m;UyXf1erj^O%AD(p%RhIHjRuJkd7zyocR1qbHyWI2(d&{I@F z%XT{K=pJR8OYrWn2KZ9D2Z;rVQ$2CX^n_$t4s04GImF`8Y0`HgISKm@Wun|0tob%H98)sDxN%bt))C(1Un|$7r0#_8`d(9>FHW>{-mP{o)#Y8 z(V>PqywC(`t!Bgwo3vbJ3-Y|Q^d}QErInKU94IE)`1A`K8(ZS=L{aRgx7ZlY^5eBO z+sMQeihK)E8d?$WsjJK-`;uM=RiS0=s};Rx%y!`McoZh_td_Es^K&*%q5#a=8qt_f zQSum%YAmcruW?uxj7TLLAJV6{Oqoa0L6e&uieOXgK7~#GFX}+7+_XJ@HBO}nhPan2 zg~K0du>8f-Aev<{#;$bWgA57a#Y{dV&mv;!2>5+FtPy2fw1D(3fs_yUv(<{Gv$UZO z;&>8;)67`>vV@}H$W?ObO7QD;3&G?5#e|?o?`$n*1NPk#d*+g_D})QXd7u}ic_dne6*_C=Lef+Ps&+F0Ff8fQASiF zL(V9gC$soPA2}~0EGKD{TsgJ)Y5Mi7Ts{NiaXKPl;WK98ljsBJWIAAl9?x8WzLH}3 z+7o&8n^VSxCECAT?e?b=)uwEsR<&?}Wmjr;@)1&ybb95U;2qWlJL( znycM-Azlqib0L@B(d`YP`z2m?%?p-xF0v=ME-AE_36)t|5`r%zkFi?e$7f)ppYd$OzDmg@UnH04=ld~MgW0s&o+nf2 zr4@28?tdfJaa+UmK3)cWn2K2wh+6=Ps2vHnlxC%&Tp}*jI8Gn}@a1 zC^i|GTx^IJ8shlUfUNlyA22gHHU53YFXb@qqi{5mH7E^-czP zJG#ZZl)JV8g#M!dhx(5K9AtkK;7I;afPK@23C^)+js-Pl@!~n1)2VYphi#gmkj8m8 zKA$-ar;g|`-}!u$h8R!r&gWC@65>;G`Agk9RPPbS$6noCH#7G>f1?y2bK(Y!Z9AvZ z22;j_O-g_#@ENDsU^%tCRH>?0F_xLmpaE!d`NcVB-f0dHmlD^U^A~xAy@dT8;tLx&d3y%MWQQ=M^1wH}9g%1_gK`Ot`~% zfuyC(b%J}f?w!zEFJyytep|nz^)+c|sv$C&b(+aEo}@VAKfiGxDeg1dY0?Kmal@k% zkVeLz82~Ce0G2>$zo*{u?a7@}_h52pgL&Q`|5&Z?zklMKD?n;;2`gG*Ule1TZ>6(dpQW3n0LZ@xtiSJRu<`)eU-ks7-486#U;hkmSVb!;xk{aRqe4Ex6Ybzbwj@}{ z2xVxefyd;iY^}Q}PwOC0>z^8K9pz~g>BB?m#;bAJcyt~t-UY~?K1hxs$QV92Y~AQ5 zsp)l21uOp3=nA@`!E zwP4L`dDuDAU3FK10Q$i@caLw+rC^9heq;uOcM}#zr6=XTrgUgD<5iyPb^w#H%(qd6 za<0HXhaP8qHK}vjFoo)fr6-vKJ6?m_qbt>?odLLWT5TY!HtBe9R_{6ITplp9>0IWT z?B)k{0eg`cN=G6Bgt7?j7Dk{`R3qGyO11O})6$+QMk@^<3ss`PG`C#d-g!-8ld@@@ zib^+~pH)*KwK7g@?k+SnEmy_r_+eBzalmL{L9*l9rW_$_X0Kq}8l`xvei{>Pn3)(w zIyE%S#+A|bwvoFr1LW2LSIiBl-9)IL9`%-YkI5Cl&>t47T^Tp1=^alDw5Ge`rB zEzM|WMquLb-ETemJw2ll1}A6l>X#U4rn|bjy1Kf$s=9jhtEGq8^de7APD{}p_Qc(_ zweS1lZFHJtx5REb9Ek1lSkU`I?TDxR zcw_0bET4^|xOT68F^5Vq+fA*K)ftZ!a*m{9K`Ng9%{1;x}qrs!I zI4w7qmR7&|YDs)0_5tCYsEqcqSw4)ZNK#&iX`Y=Wqqq=}7-o|RU@*+m#RyvHi{m_-h<`+9(cUmmrlpAT zJi5SYB1^|f8dI^OsE7rTI4=eO4?+HYl8t6#eqRux^fZtEHA`ST1ktoFV(c2d$)-rP zXe{0rS=twXT^~D;#!O8rQzqru>HBN$JG@*a@?76%^$!kCF~b9-{cs$?@Zq>3GrxVk z8{iK;FljW2izzaK;W~Q3P|U-D0fMb?nJg{Jd^RkzoPJNEJer8?X>t~0Y4PdF{IzX|s#%8FxP_>roIA32}1 zlWyl>HXDybnw2ooiZV*eBq|+N9nE4SLy`j8$;glcCr_uZL8?zD&hsqq^kGDkVo+v# zWuBxb-Cl1~7tP~xmZ$vtlK!QCsKQv|Zu+rlUjLH)-&s6E5`Cfp0-QFm-#q2ySDdSH zQ5G8qhnH4en7vcrf_QIu8c(o+PnVn6HkDXi6?-v=iS$AamY{(y;7@@fH%Uo$fTYMl zRtcbKG#i(N9tp({fBB2hKL!@l!B|MX=-C4StlvdRTW}R@#vf<(fmUQG|BdS5fqZ|6 z#FJ3;vrVVU<&yi&8U~=mPdL)Z22qMVPk<-J$*-}P&W>Oakp$wtBl45zeu*@5EWhzXGIBX6RnMf`|dg$WsoRq@$;2<46D~joS()iESGYI zh@=2Yj%a?P03K&UAkq*CJCOBM^}o}C$M0To?MJ)>%J)((Zs#XB(-{1x7g9Ll%C8=> zz#IfCLi6Jz7$Uc(embuz2y9)kJBp`yJOnNV$@jW2PzJ>ilp_UX)$qbFkD)a6s@th_ zwA0&cqA5y5Bqzu=U`Wu}SOZyzsw|#vfUHXL`8DO!|5YPm5oyklIBZ@ZofVs_B}}k_ zS2HU4ACb+=-I4gjk`rp>QCdW-XYTF{gqGnqJQR8RdEwI<2Vzuc-m4}3m!1pJ`Hjzq zKgiIvpFo-*393PPfg91r;d+UMzSx*CO8?u$Sd~@_i~`BPd85FJ(SJsv%_taJb>s%6 zW-Unt?Q3ul;&hnJP;11ONqM@+nt~-BA)r6js&Yl@x2Vg^Y{SlXsTtQL+J{B66SR5o z$ai=4`e^*S-mM7zCp;sE*-Mhuq2N;2*{n7@UQCHQX6c7CJ5RMeX_}*vw7d}eZ(lz8 z<@NLbdj8_gb2isu4PL3~_i>U&Y-*DGezCGn)*HK~*np?~N~@7=h1^CfWDNrU*xP>f zYWrO=;!^G?fuoXhqa)=zXlj96=*UQ``ZtmJ`yoo zP6ss0jlL+dS&8<~{a30)!TVxZPQ?C$7dvnD^BT0V4Qiq#?%x{RbyeuVx9vGnj4sk> z0-~wlNt0%yxCXhshp%>D?mvIA(-yn$40fh2p!Z!BJzCmo+I{-s;dWc*`Q9{1)u6TS zO>2+r<(Ule%Fc^xvC@(PgY)Rss~4|++1cLT-hKYl_S4-RgAOl3HRyD9E%+V6tpW;A zbc;3NOIB}Eyjo%V{PokPZBc!$K>K(i5Jb`x=zp0tGf&RYEDI}U2@EQ`m&7-?c#?S( zy<6;LK|dRL<;Wud%8Hl(sgkMd-BNl^U?kigDU~P4%d)rhoqJ5fAgj2`T?3l%J2^>V z^-unVo(yN--3CExr@lK{3{j`5Lik#TsY$hxTr!Ev(`G7bx=0scGPmE$HHAzx{393F6AV*xx?NEhc#-88PC>`O>1zI?c zk}y{}9G5URxtHhkQ$<;yesCZ!+!ruIRly@4_)Se2!h=o4vnm+B`JJ&Kj< zNLn2=97e~2!F!}n53+0=N9m>Rv)*)O!{ICkqFQxmA7(aeL=$>M%j@}RGCcKZHnh5K zZScg3m=);isT-r7#n{qL1>EgW6L{N%52$*5CPtt7&?oGS?^1N77f8`uS9AP4nv0_8 zbbQezAbm+?xnaKq6#}gz2Bh4}1OYOUw!953`keHaa}aFVx$&3bE=mbOC3@J zg3e=!&=3W16&>IA`4i$Tf!M=pAzbl~udd2rL2?w5!jeDvC;EMfUUx*Nqg|QWovV7)m6Gb%+$^gw5}&~;(7y*D1)=r`Bh98j)gunWl8DS9 ztknmUL6Vtjzir}?kW?_;f>3srAu@m;9f0Dadbry<4mE=d^{CJ2KA5QJcc13X^Oy- zkyET0st^M;QHevb4V+WD=%8*JJ0MSEZg#G$S^4t`@aBRT7)KqFI)#8CQk~*1GZo}g zV!!6;&98}zh4Y$Z#3hsAWuBE8p<}EVq%x`PDpt~Ew!V~8LK;}Ugk^>NLp;5GyGhk5 z!S1A>;mTMaR+psLX@jPs5$#VcH<^r(Mr#=wx!gTp!A2e2zMtk0jgTpFPT(SnMe^ERqV5MA~#urfZMVz7;XN2ky7fj=Lr1sa7D2-0Y-RI-RQKCVX zcQBLDq&{Z62LYU>*?5d|KnD=+?m*+GQ3(R(EG7w~Q0x2#%co9{h&EPp}9cUHCmczF+Dz}m$)Al;vs(% z2~l!Z#K*HS7R}?)Y{puDdurO z%j45HEzt4LlZhkQflnzU6%Q+*pBkpLJWe3-!-W{O4`e{8vV|Af8Z9}lvuDm&gRm%&3K<`RC9&O-z{Qur)e4lM`@VPfC@7sRU zd#muke@Cv0;G3VHyb3-y{*>Tr| zQC3Bbih@J`Jws<1eNd;5j*^tmXh<=13=2SZj2b zeQWAPYDIy`HyiWDB!ZG755n_o6bAvI7gD5BWyrI0o@ib42h%qcT0IZoFv~|f@i>_n zh_C1&sFd&&doQ}^GOh!0oWLyhAUwur3jruhWxcS{3+hiHy3vP7e26cK9+^KhsXWz$ zB=Kx`DxzXTe1h^D9fE>DI(QhMEW~&M@Aa+ zNU_%dfdLnd$Gosq8gfThDS)&*;qdaYK5e@%K#72F$K>#&P3bX72xLz{0Eb>j-MQ?v z%A6UVfPDNVDCE5pGQWeWapTUam)s5?9L#d%oRQwa)Ebf|yU#RG}*R4UW zE-66vZdh%EC0r}2%rV=%;3G-o?UZPd->J|FH7cZ}faCT`*&;cT)Cw*=#C>cC{4T*1%(C%0#nzYcWB?MD!7AHjNm_x@cVtC?_!}OKzaH z)R`svY3%#E$0h_)?nVZKfifqB&SHuCVhtKl_8V=;agR+|I=JPN>fYk^eQ%VFn>bQqf?lP^>f_6UoX-h!C0>%wo`hrtd*=*np?Rbq6h9Mn(v-I*`_+ zmW8Y$s%fKjzVqk(EX`)Yh>% z$ib1HRvAitY8cBt-Vx#~y|>T}FUD;Cr->M^cqJivOtT`fHETWGwE$o=6LHUD#-=gT ztxkYn6r*!ML{j30JUPK2FA^GvN+TdCABriaP3R{5^#&TqhPOu}TpW2}Y%EM;7mY^y zJmU63phjg*bCx)jRHm4lVSv(leL_w0T?ftnW^KJAI`F8C{PjPVS7HgGkwo-(9G%Rc z7XvwyVD-yq4fEkBkE0La*Hu)jPdtBvuOAuOSuPVv#GZ6Agg!uBT$U>pToqqvuJ1mc-r3l;uL47os>t&lrNz z2m7&8LaX;;NQbpi8PYOqg%CyUI2xaTOes$%zE*42pR230tTTEw9y&w_DyKS%Y+q8v zrKh5@OU{0UQcE1;rTS5;wOVL;8x~!T(olFs9i{-8fFp+5M^I~e67Hg=frNVsG zA76)6aW}b!wM8(Ct|sIp`T)yA2J7Py+6Q3SM5-y8ss*%5KB29(9sxT)O~!H8(VkH| z4DB*(wA6BXnjDwio{t``3VNF=H=A;QsaCVTh)Q}M!!A~?Y!Q1)L_qy)qxi_=AW~Cx zx^(DhW7fGYOW_KfA#A5`DRs)1vZL!*uB~}Rr`Ob6_xYdB$|?R|T{1sIHVCCy|1x(S zvA2Ce4b?qT7g%r@>yhEt7E6xR={?L2HJjqzK|1dy@$fWClVZX~wNy*J0$HkvOXH;@ z6A92AV;0yHB99c<>yV74^ymq2l#|X966v!d9-25WxuFF1)gDFQ_DKSWLb)s*6@$+= zfT)PtOYuZTN9)*J@`(*&bkx|awwP^1H>D4Q1|r&ajmMOwpG6;=!-znA(Z&)|4M)Se zJxaO5bjDq(v#Yb%>Jb`7$dE7D!gh#RbIqM<$RT>D@U_HuzSc$(X)hihOWEzd!SeuH zHqUe`b54B-$N)w4L+!F`wj5bDlRhKd+w|wFb|?>~Fx|RWgyMemVQrqtiOZt)WF`lGXgb>|94ajC)N+`7cVvYM%l#?mhv9@o z+GMI1GxcJtGGG{@uB5Cs+HA@4a`_^o&3*dUHQAsb=aL7>A!iNS9aSuO5?1Zr*XgLo zJAr6&JvtZ>L1%C)ffYq?1h&UxJ4QlM*nS#XtZtBeZpRHJoxP7~8{4th<0LQ8x|Mz4 zNC9t;Nk?H)oghW;f1Ct#?vj%#h5Gu;=G&EXAbQ%=IYWsw${Whx%lr3+*(km*&qv%_ zrC+uSnOtDF)3z5UTwKlRev?xv8eI&ud&_M>o}XB#h1oRY^gv3}l1GPd1tw*)t}$Bh znwm0-KZThnUx_@LBl8@p!%L)WxTltix|Y?+jk?CS^P>b9FTarCyBMlMM-bGnVzo;t(WUrZm8mzZ}7+LmMk{uNfPMgJ-QUW@) zY%#L4H*k(mbq$;Y&tR?VANFaB-mfn5f#_Skv3gE<9l4`@j53wVZBV}Wo04bI2b}Cy zGSgP;`CNV7_Gm7q*VOnuRp^LzDyA`p)}m1%c zvV&S?xy227DOUos7JF-gOV1ngrmDr^26hf!W~?O+akG1M6&Gqr3O6NLaZcr`WGmIp zz3ZWa`Wx`SPA&N$# z0Rp37*%1kPGbOL$FKlayHT z@I?>`gLV=k zvelxyU9YZCBJALIyvii@Mvh`su}m+h`Jr6@c#2zNwkPYb=&dasz5DZ%S3U6qJM}i$ zFJ&tG^2K&s(tAgyZaKr?o^;*MNv$i=sUQ_~`tRO0#Lm9MbCnV@n1YpobaDXHVZlH@yS9+;97hIEU4?0R?BT4pD)xtDmTr(dX2>=e>lv=8?a-fb<5$Pp2W#G!rBvs z6vHOEgg8Xes*#N`n320l}F(h&wpp~Hc+>O<-7_SuUjxD{V7YMR2pfWUq%a&l}W|xoHqd+y4A%Y zVvDCSD5t0+;e|HT=xe&FCh$?MV5z3iMxREy5|4AYX;8xivk<0WYQ&dt<&!jpn9=?d zwjkRtcSVs*51GH9CR4PMMtm(M0e57 zJ(qkvPL8C#ypYL~WPntVyLD%pBcStSB4Be#!BlkhQkX3Gp|~L7QD&?I=z$ArtE!Jz zd3YM-+hupHCvL$i{HfFXY#0Zf#+YyXG!IiTJ7R)%*F8ZhyE->sw)S;}tHzCo59|-7 zp8~9=0%Rm?SL19}z_`y~Ut>b18UfJG>FE8V6m6u>qVg0YxqNh@qTE%w@nNUeZ+Ly# zX$l-(gv@Jw#_Nu9LC+(^K6@4v&)v@c+$^{W_EuKG2pXXk-JjQs>AzBC?_bku1Po1Ds~$M<;y4}zXwH$47fkJ zCbGhoYaxO{`76_N&i3y2ASa-7O@zdKPaP%ew^=Tu{#$V>;&gS|N`LRh@7|58b;0t_ zKcq~8vnj^|LA9hnW1hg2#Zftvt4$RJ|H*H^;cbS>M0v}13rXjO%|bOrtPtMIT5#y< zXo5wqkS&doiSyp$uoDH??*+_;N?Vm=s;JOMm?!8I&rg$UKEt#CW#t+t_ON;v)YKvE zbBu}2sAU)zK$wH-O#9aLKcS%U%1k$Ae!tcB)_uiuE7?9*_RqNE{V` zLk{!AK5Hd|SS0%TEG8aAvG`D*;L-7ablbDMeJpf(i?X)>Ir5l1HWcAbe*B1{UuG%R zCEPIKpE}>9uQ^an`>~akh2yHBG|sBzctV}7U(FR7y5LD>GxC!aJa$_HV#p8!+zF9e zv(n`n&t~1S=^p=biro;uU{HgKUGVQA>&gewNrbsJthjGZ0@U+44FTZ^!qLdi*^Z*J zi^(zACj~fjD1{2uE%mI_ayFeZWVX_yuk+IeDPcnOatwSOlDe*}X zV8dlv?BT|z%gf+lJUKRs;Z#I^Cvf83I^OQ-ifxWd)y)e_&9u<^(Z*+}PahpAF|y$w zxOYh9>3MTBvbv+}_0yEOk7?C@PHJD>zvIO0QtQ11CMM6XuAE;@lgdmeO~Nb9Dj8nU zIIHYkvb#x3`r^I&B*#N+l%lRr{WQ#O?~aJbq>pj3JpIl`%<+YDhPDA$shEZkQ+}m( zwZVF>fdWzJV)h??sr(Ns!b$+NvXX?%PpU2yG>9k6 zvWEkwpIvTND*2Y~O1G7F53LVmwV1atZ)jRt&c+erRwJRO)Ut6xKPp z5BzF(mX{BEX!S8KWDK&pg~9&d_)P1@KvK+V0>%LcWO@biM|mzoKI$jc!P;T3GA`X@ zE9CyFJ&9*GiU;fQ_=mAL*&mpOzJtlhN@WvC4lq?|!@hv``z?o=5Y_jD@ca5?SyY!Y zU@BHTcptz>eMm@dY1;mP_(27jEBJ)~(3ov5)q)@num_qd%yTTthN~6n!eEj}{gJu- zAoRJc#|dp5(Q%A9kK?GAHF(zeQiO=cL|>`X68Ugewif6~uCjU!&|Eq0LYn`?zo<%T z8Ze5re(5jEVt~nim?(h!7h@v-K?|mmDhV&5vc0BALnn_Sr%)1cS|+)=zdSZEeSr`W zqXBsqo+|t~+YtG;apMtLs`T%_?XVR4KisCnTmZcA&OZ=$TGyb`w2=u^UND-9 zl8}yLX>i3@CScDrw$hwelTYz1qvIm+$D}B$p>dSxB|g_FXM+l^B2O?AZLljG9o5y4 zDN0>|saw$61YC93`Uc;?a$H?|t`M|FcO{O2Xwf)>iJSWg>E$^`m|Hp#Jcn|HLk}f~ z0gQsnSGtCcbv1dy>n?glFNSzuu$?iN;nu2UDqAj44Z6+Rlg2|*0^N_p-O)$E`E$iR zEV?P~+zDNj1D)7v%t3LaRCQaQ=qT{>29QdZ8z8mYfeaS*8Ps5U1Hl$$GIGmyVL3l%r>9J*;3QfF+GRP&b>yv zbNJ(cYqCU#Kc0QsvP~~W7~n~+`We!L0a!LAF~_JB`Ybj=?QKt?&z0;^p-(FtRp_%= zZlc>4lxacvx+l)|6X!HSZN-yL zRIR0!^)GBJ#n0y%Oz~4^GU>kGzElslb$DGfGeF&0vXDs? zKrn+?c2WuD6TG{mHeB#w6KFLeDS+9)SRi%7wh59;+3C>i9k8)2$mw#Ie1_gNyy> z1UnJH-}Hg1!`4K89pDuXxM8k7s*~uZw{~efJy4VnPZJnd?9oqEBG?_F`zR_vYK@4G zfmpkbWFp_47tiX>nM&NcbTLIq#}I!I`UfzZc_Y*NI0fXhO0J*k;1MFn`g{X0kr?Xq z1QQsUWD4SMh~%IF4jWl<`6O+6j?EIwOcOjU8@K?@{uo;m8&9{WYlH^USxxs%@%|p! zOW)tQGjHL>+oD_`u!}cC+-BW3=pUG`)`bvF@UK@9kR7UE(dIO`WlfQF-)BkM?Q|L) z?CqX5sUv1Ll*XkmmGn*r8MdYe67f!Fj!bG{1i7M-V^Jf<4H+pu%Lw6;>pF}GbBqLS zjR1|C{6#kLb!->fgty*g*DmAUS=pvdu&wt7HiY(N6twl@lo|3Ej=Ikm&$W^+jK?VH zu$g-@%(?}P_8+9uE}+vc5EmfNKi^PTfOCKGO-BX%oq4BXWwLM8k0nn8C-X6NTkZ#%-!P@oWJbft_ zwXR*SFFw?2-!RIu&#LsnhZ=>@&d?OtW~k4ZMZ+-7piLxKO#~zM=&VtLg$B+R*dJWB z$e?68W^MW!G0iUmK-#15-?7!M)HiJ$$52o7D7kiM%VjYwWS%h}TPZ zWU6LgYs9ryRA-T_Fj>8Ya*k0l)RAhEgLyY?N!`b2bJrad>s;S@wNt8;j&4z1Qze7C zA!U^ z7O|~A-`$krXL<1VV@t{l)YZvk0{X6m-m zm%{B|dZL?Hmj#(Fvbj_%)JSGUJk}9i23)F~p;OTRFug`L9y#(1t5n1p0_e-cG$EmO zw#D!I$<`W*UYk+eE)pYcCg|$G_491ACOn+BZ3l9YywV5$cZ{u9!Xs!vPMK2Mu5v%I#mSO+JB%0E!Cy|8n*wtRt zN6L2TopfRlK*Y0CGO2e;df~)%2Qe_PKnU$=!k_9$f4G8i<$Pv9Xv@IQdf$#oJ}@uJ zm!`FFCbn_>*BX=N$Aj9c^@07v^4OxvvtiWT4gOPe=A$7&cb%{al`*c`;B`5HE&u}_ zn6F{<%hL_~r{TEDTyrFT?7hT+{iCtfgEjwPpVM%dn)A>J=m|IhiVM&NKeDQTNJy_| zyU6R1>JkzTFZ0agUt?)$&4ZSVpxNls2nKQ?M^ASq_Oa2WZ$%30D_O?|p~r8Y7-XRNVS{C45=b-*^@ zP17-whNJMQ8lvKxDqVs;j6mUy$s56 z>0^9ctG+dP7`axT!!R57>PD$B^(Z={W`x_Uh&MS1y3qo9PkwG;t|hN` ztB4)x6p}s$+;71qVgHqaB9GMK*^T`NFLvJQ=L7#Daf0AnC~-rs8R}}almE`n8i%Z( z6&JLrpT}c@7|zSH&>`_QNj|6`T6FPPLh0pAAkLx^I!(eBW2}8BRd&u;=(-iXt~sZGzdjN+AF8M9 zKM)=t>hs)rR)tVJ&9xmwwvILs2?oP>JjON$Nt(tva&REdru`A+&p3vBm7~Ttc%1mN zj|^88fa^N?+rrAT$PwPT$8;AxiW|~W=N+kC=-6!I(b#J1bC0-s!N4_fDeoKOQkG;d z8Us_T_5Tm1-r&D;<5PU}zjT<&(h{ywnAHhd-^*tCFn)kRrZZHp=&lghZk#2fIA0jxM&at7S7>@B2@G%_>Tbaa@ESE{~ z3Sg9BiC)>^ct)P!e?(`|-Y`$5CEIl{NaHK}se6_Z6fn9+v(FJu*>Fb6X`f8?#8hXLQjjykH#7!-3ZcDinV#<8 zn8|R|OCernNh-4(Y2DSmvLH*3laoSx%B22k<&LkO_Z(8`S)x;)bs}f>+)J%}-xE+z2pnsNp6W-?=EtE5vyv^y>z_# zG<4&5>)XaJ=d^3C6t6tK!hPabxJ%sd;+EC<;W$fUj3w@(0Jr44n-H||)^C4AD_4HE zzwWzA#o$Hfev6e`&fDK`ep$a}*%Y(grmgwY@)l7YOGpfg8R(THft<&dLKK>sn?kKx z{+w2F$`ww$bn&}xNEY+~^BzNdm`yK0JcA4wf@U>2LI(!Or=VnamP9!!P2la%AA3Q& zq4iNkmjstcYpqj)`6|m-wT+f5*#CkhEI_}{TgCpd_xSbmhx@xq76ip3Ipb6#J-utc znHe4EV%tewt%?(`4{&!nZ`4M}0yXx3&0^ys*CGQVZvbr5UqVh@y7~=f9~vUeZCs#eeH zy;Kj~JE`paAxM zD}Ibi@wy~efblf8*M39o|NH2_LF#^<2E6z1)$Ysv=P!01&C!5Www0SvdxJe|tN4a0 z->B*v#8xW5#&LXe`tSBQiAZ#LGp0|fFS@YZD{|rK4DXCpx4`m1soAByTPJZT0nu|( zPMAmOw~F1jrqGX=zz4X~)C7G|y)h9CJEYDON)ubvO86v7qZ4-MC#mOwhj%Gxc3A)3 zXsjLS_inAM+#8km0n#j%t3z>b6`tr4qtX4{V~Tr_iXUd8%;RW8!A8*C6F>l1@;m~) zYnB4K&bC1B7396Y1u&Y5^-TGS5`sH`R!3H=<^3Vv+B@DWqw!~A#(+>QY=y(hii1XS zl0qGc2KTFq2i+PT(Y?HkDJT8n^;cx+_` zjsaI9?zG$&$aSnBi7*fkE`)58{1>KsxvqxK|MGvnUE6&9Y8U?A-TZ-mF$C4}OKg$e zZmCU=(mE<62-IvQhJwh%2vkS1=t7hU^IFB&d?9+{7KDc|=}L^C(o<1i1YMp+C0`~V zO{c)8#w@^;5-@J=1@j0HW~`L1$*(c3kBWJq@&vOfeDMwfw=MgEYHTWCcxd4JHrtuI@)D-dxbMIPmAw_!-727V5Xt%n= zt@9TQ$|ofu#9enpXKRkmHc;3U2c0{~=uYRbBSJxO4JIH*leBF>OZEln(hT$;8_>U% z4M;1h`YbWXUzEXVCQioL5op^}xuTloFQN6gh>pqVGo9rpu_`(QPjtA4_Z7JZy{rNk)gxCdoEoxHhvc zH83#h0Uq?|gw&}{@3-G7Q7T;|;#LzGHB#on5@|$vHbZrgTEb3`jpkK7bLc#{vR%>Y zH+Opx1EW>>%7#Yu3AJ8taa5nc!3WO*sXigw-xV#7tx$GMkoD-+qIK;i$W~a_1Pl=F z_)jhVSGG;ILd!K$&Zp*;jh3yjajlnOY`k+W4DVXZnr>UoCp;{jnx)Ff6DzzFz+yqF z8vF&Vtc%~Z;sOtP9TQ*29SMd5dIw@hd_!VO*(_HociniSmg{pdL{%Nv&B$4_TCB8c zF{0!_uk*zB)3}|bS2fx$s<;fRhQw0uL^NN&dP+3K7UxAL$~KkpL~6@js_KmFr)XAY zq>^kumg~@>py;`pP#(CqJzoW);=TaGjW8mdoSp4 zauE6V@ie*g{X7>Fz_M05XgGa#lB=~?{rv4WUV7y4{I1R@xASeiP)@BIbw9cIeF?vl z2sxgrGwCz^Pm&kfI-g|wEGD_?hD=bd5x!Q>(--kNDR^z2Prr}ZTl0^*$+N#-C5~MZHp1HP0=jxLF+;R!5~^UL8rl5-xEsU+nEWE+{T|o&f%KxgQ_x z*GxXLX}`>h(%>!6D?5nOiDEPFbgd1QPSjw0N@*LFoG6n?j7QB!a$25(q?lk@d@%te zlOl$)BX&oCkh5!IClDab9!>zyo)kSY1F;Q&(kxy1HO?~`y+?hIQ#$aBP^&U)nbfdt z*j}w{A7wcJhwbJpkHZw&=MDswN=2PDO&M8QDwEeLk{ecnKS20xmCXNf!F(|nOkIqs zIo$gDJ7|=hXD^1eaO&FpCAqEO+-Y4XFWOp|>1soHW%ujCcq<+SdipS^q*?|3FX{p6 z^)LKW^$I5mew6kRm<>YOYaD!puBSNrmyf6U9+%XwG;8~LGM?=3zocyYHjA5TYR5~z zS9MRUCR`^;z(c~$G)>ao9Wlyc_Aao88`L`dIx+*byVJL;7s;68M$p(qORSdXmV)Eu z86_LJ6|>9X(8ftq@1udzRVR&xHNYuwYfBC$4KhBeBoeao&jn4Xtq<`B?;E|e3B)-& zFk@U+C4{nZ-wKXSXwu^PPayTQtxVUT5j-%5g*%DE_2i`&8z5F5y?XWH)h|2S``gc7 zKYe=XQNqx)QnYxiyn`o6XAIy0FR_7X0bN;nyw!h ziTjBFY@iAD^03dQSS@=!^yZKDVIA(*X1U{?Wemt_Cipz z2*{G?e+;KCG4cfs<+B3s3vah-%uhRHt}T)E9giVhTjD#HGzPP&e9Dv+M_$ zTo_y86;UxE6;P@XGfx$SwO+3(%z{qJLf)p08*9)m##xGtjef-mdK)N2r=ex~sK>Dut^;L@(71KP%8HndW3++u<-!z-Xe;)p(8GRk znB}mGDqAU5m(K8#LZD{rXQ%|3wQ(}v>Ef2nYN47uhOKl84dk$2t4>r@iG_rhx3ltv zm+_f_Y%!sx>h1N(FD=0I&U(v|R?3BK?MRGhkt4cci9h?MOX$D`v4~5YRk2O{9H2?5 z3^~G{^SmMN>P??C;5b_Xy8{Dd(6Tm)vW}DGk#095ld9S|u$56YuPaOYAMI%Z*4$1Y zaX#G~2peKDP19B?(1!ZpUdn8DY9hMS_ID7WL98|g$|>c54X^iBiN>V2mh@txSsO0u z(q|@3Yj-8dL!C$qrqw9KLfr43UW7ZJeN~C!77SiyyF9Asj|lFK z^}6KdODrs(nzQ_DI>nL#4Z4m2M4Nftk_ErOeF0a(EkFlt(H%TT@Z+O>>z;1t+E19l z9YY-KXdVrW!*nDh`;tUXPpDU0Y{YbB!+gJ^ig;KmIpv_KErc6^J6rdBvgee9JUWjY zb)hnMZ^7Jk{6v*m>&}GWuyrL_`!bHmmO6din_yrVpw8wgHms!;{+YAMe4NeD8KS!# z@DMF1Q*Zzx%rPf@E86CwWK?x}pzI!vG!8Heh@_Qr7TCdbR-AULI<3)RZ6aR!+jZIM zF1jqwqA}&{*DjVa%F93ke=^2!R}xvTR$RKpFj;Zr@ev#U37R5SgF+`VIg-66g zQ8QRlVDEP^g*H`k#%+Fvc+^3{A{#&TnaEpQH=(AR?c!{#0Nt{OUSFlLHm@79wOT1u z_n9Y|ENl+e4i#rN$fg` z$7X=yG&zRFxVfkGEGlt%o{348*XU0Erv+Q%2QRV9^+fljMeCul1jqH?7jW4Ze_dPf zJ~bj2-@D!*ifV{-6Dy#LVna%|#k4#drA3uJE!JjM2*DM0qpdcQu5Ft3l4dK(#GpTm z#p?zl?P}v^D(}lF%9T3lq$?T#!4UFJ|djU0S5$@i^cQr)vBW4bTa?;mB`~_vsA86_RaufscRa zfX0QR8Flkp=Bs7?Q5!Yt1@-|0fHS_fR1IQ`cSR*RENVv=W+0MdaRRNTeOAul6}fYe z9Sp6=D6fsaR#2tFMF(1Ls-2*E;GJnRb-m=RzM@n&sqGmZ%I;X>I>I=x6EBC~aS9AK|l)d&|m^3U`?o8-7!JIyYs$6^5Ope7XcdeRmX->zg6&CK6 zb*8Cp%3D70U#RdqlnS7;Xtfs&7;P!&`kEA_9ehAuVG6oJvHCo+`?>W-tNn2w_h8B?DRd~c3)MRR4( zi<7b*ros+26`VqRy^i^cWYEs7&#l^q;D&NppnyoMh!~1Lg2t&`!W^6bMiJ|1TsGWjkxjSDb=nSZX4N8UJ z7_`!5e9%tVpH)Svv#dcCu%*J56=ap#)560&+4Tk;8rIeSMSz;v2s zfAx_HL1TxTW^N=djo8x_Rkk)TYUZS5jQ!eKOJT35?Y5`b2!43nVBHybMIGAK82y5D zp_YycWg%$^bs`1Jyj>-wpL0aNPDhJnsAyb^cJ z4ArH|WV9M0Gb{)_!EeBFnP+Z_G&j}Zxt1SyL)aF>Mi+d8QV546?!-Cxvuo9+MQi_I zk+cV8@PwSM_Qzy@K*Ja(&rZ;q_E}WY2&OZ=0TlCF&?XT@+I-siG zKZX3_Z6hNZuQACQT^ctE7#UeuS|hp>g^un5DGSny>Wz)UV@MU~6PBT((U7vhK---q zRua^n{t{p0l3LaMH*UusVSBcDv>Ox0`ULYC-5S90(jzzc*MvpmEm-|ImCT7B_#1$sASt_A5V;^=E;W`FNP>lueg_FUJ9y|PJV@L%rd&an%DAxLQkF+TN3mkE=l2k zyRB{6Xb_*@|J~q%k{rFPu!(d-v0T1=#aa7ct7|juR>rVObCly%5oQ=_K&FB?&*C~7 z1pp}jz-aW!;3q&x>}4r{vyXRu28;NQURnyHfdLVTDb}je!ye*~I!)+EaCc_ac#PW(5zEwSRD2AtPi!=P;)HNN1 zcA2wiRf>zm2WTmXuX*+NZxfq!(`@w~EOk5I5=|Rgp3}F2#f%LdH{e%yWuGFd{%6hy^fYj>{FKi^*1J ztYS}Oo2_C3@+Q`VvuZ2Zo`1n*zj3`p-TM`$=kCr@#|}cw7UW{%84SX^e{tN*@Sh>R z*Mp16?Yom`I$sAd*LiYyO(50PgEZl1_4w)W*74{CQ9llz+POb3ErajBvwX`8XNk5) zCljLlbQ{2wm;i11=mRV2APt8Oy_aLrH+K2Kk|QR4c9?TRr@y+x10Zy!k=+}yVb3aBj;PF{wVbMpIAeWPPo+C+dOq(-m+q4A)l=L#%@*aZrU3YY*Sqz z+$$3NP8t%WN7^-hnCR%zbucG(pMLQTRS79TNiR(-+|hIor!aS}@TDp(Itw2gHs#=h zv#RNU_>z#F)sddL7NRI5LE2rf2lUy=nU{w^TAW60zk^=v{g@2gyCUI1H3XJG(a zaatr|^bVx!s{62N{gz?C(F)liH{GvbE@SsAJgJBDBP+VmHQ=I|- z>Uuifo0#7BvtNr<{cyC8NT&T*a(N{xMD48lRIsN;uTpD-t1COQG?Y;DAS0((r*|J< z`zTL_>fK(CBOq#SR4OSOu1~>8)N*r00wUg|$}s*cmv$K)(J0C%)r-GbP$?LjyY&rS ztWZbkVB?|L(PN`W@cHdmuge;LoR*#%=dL_P4&zmRODnTAS^H?H3dHAUZ0UUHxf!_` zyiGISA0fZ~sMCo2sGmLMd<%1Eco#*d-YQRDDvy-8^nTdAqW`pU+g(TK~LV*DHVdLRDt>LNB8KJd!nneVX^5_vjIS z3!|%fzEIt5<$OCr{#3Ni>+Jb0r5$ZdIKcqbuqNdd&m0$=9ukXf=w4nXh4kX193pCT z)&axY$g0@HsMu^Y+%WKZci4N>+j|)D@D7cLEeD|Bc1l%&yOqYNs$Go@Uzsd7AXy|Y z2Y4x)9z171y&6F5&K&0%K>|1PqsO&+5nGS!KXm*8$HXTDsLr%>+b+^%zo^)#ulaGx7~Tq$Tn@vt}8)2A1@xT2bnfMiKHB z%ql>tZY9N|IU~1@_N4kZ+r^tSl;wIT6W1=(XIfWQXXoU=Gm;B{f~kAgrxzKN@@C};7NQlO0X2S&nX#w67Hq80dRp1e8vYp8W%DP!se#x z|Hz-`;DjIq;Me@YK2j)1#9|i)?jTL9a=Ir+5uXmo3*wuKWS6W{`WjxXq9q3TPc+PC zMc!Z}**owNSQ+W_&FwX0tt57RWvg=27ILEfoM^{r zk|PQYlxH^%F(VHFbltCr5oik3(fq*cu*VC?1~7@6T`3cX5Xq%SJ&#dHw+`MNAPo81 zTkGt~8Y}j~MF>BPZ23lozuRRb!*p&?BfhQss~PBQVCjRZqvOmLW#{1desPXnk`G4M zg)X^cY(o|dRd`snIG%7`8DS0QF)(Hfgx-up3s~p@#v);kN@hGkPM6KZVk= zsv@XZj$Gz8nDmZsV|BU81<-aTrv;H5t9m`55QX80T<@ z@@ViL+EgBS1#(#^SOOsAEQPlO6Gfq23ZJN_%}qTcgsvBT4K=+>k6twd0Ke6I%|Cn| zr_6lGWGGL90BzjA4SQxf#Qd1vt=}y-%PPyudwi)RSdTfbT|cuS9U+1NxlI^LNL&aw zOEIUsw1V;Hs|(#LG`SHvMqtW|<+%G30Z-p9Azsc~RT)KyBNMxeCdr$e%gc;-Z8?RFsuN?w?>pT;-;$@n2#qDTIz3?d zb4Mm1URuZhnrshHxJz&Q@ua5|!)jCk}6 zT^egjJy8yFE8m`WG$+^%vgCZ);2qwT`KIwI&b6qjrsvS9m$ZPt*8n%QwHyIrq}_30 zUx5Hts$0tK3za9Yv03h{klAD94$@>OwF}U{#tG@B83a&YP_DSNUB3SPC^06F#~Vju z6eO+VmD*vofWEWu{d9J8X(rj&$7paH{X35}wup&n_!s~0xRXyzqjA&0K*!FU-~_)X z^-PM&UeAJ?yN2-}8i{b*8)i9)HGU~iLQD2UoOLb%-V_oyQ39(~?E!Obi8si)s6r+f z;rM~$(UW%W@CDDD+Sv%WpCtT!VIbxdON&kj>lah55VMT#1|ih}sAnrBj9c9uKU+}Q z0QQW*-yX;@thOytA%E@}2{GoFF63HhwcI|r+sA5CusVUO;jXo3j3c`;gOsyel@la2nT&P zz4@fZYbCEob9=)A8W-0qY|deWwSsIi4Wa2v80-}D z4v3ZT?Dlk!ajlI%sf4AF!zid>DN=?_2w#8KRQw(eiFC^&8}=akQ}B)YBVdej0xt0Q zxVrSjm|Z;Sv^m*=b8q5anY0GT1+#G`oMyFh6segjt};5h(8y8XO7jCMbGA**=ff== z#~7MG^Y$2jbp(rjjuFjg*zS3OOj^QooFr zAX%=J-hC-ZpZpy#_P%ET zVJD_g1?-z>Yzql_dZ9K_+vI6q_o`NstXD2!unWQ!%7S()9%(qP(>k6P07HB+gmf8x zLk0%YxL%u!OtWqP5I#PEdIg2NyCLxs0N=Epg7b-}eV2SlP|_z?__cwe9Hw$)51Rqb zhIgzllQsAAZEI-*d?0J2#O%9#^XK(p&s^lwlz_UzOx~{JV(~JMY$iLs=}jTWjiH( z!DJz2X#4U>_QZyE`}=)n!&-+p+}c`63`qH;E83u%R0%ZGagw2&^&F%I4(QrBl6mk! zwcD21uI_A*SOY3Y`p7>chrsj|5x-B&BZeHbx~(btrkQ{t1x4~ek#ek3mu1ny9p8Cu zFsi1G)ksl-A&O3;o*3;O)yQ%$rEd;5LP^(D-lrpP;E{HI z>;tntHY20^;!2N$!*2uWVvq)c?^Kkcwe(tNkxsY-h?~!7fhxk~ykhdB?Ji}2T!K9u zN=F=GOMxWdVl152Sv>czLxR37^YK6`Ip#5|G!|3CdZXTC zTIh|%gj6? z+)9jWNtM!?X3tW!U50JLHwM8N{H?QMuK@R$K+6wwc)gr(gYN)zp2&IAKrTk_hCjMkc&0iR9%ja=W#Xh`?Bh-Gss@BJ z7tnp@BkFG&s6S z8gtnf56e?dVcuB#Xj(E>a&Kzu^4>n)nGA_>sg-E;Boz+c*r;8Ej`K=tbT-FETH7;l zsLqFzL@iN;_cR<_ak;E4ck5_<7(ZQaMVoil@77ED?JeZIUId?RZeJq@aQ7yPweUI9 ze&jo3N}+>!DWs^KmEsFEw9s8|qYfTIoc`)Ptg`_Rj)690MSrfViXjcx_@89Ba|@XQ z`BPc!RBm=%2)6ALP#SgIGnT2@drt81In{QK{g`Uj_oy19flGCr^cIHP`wDQ_(N0FoSVr-5C}3TJR@tFI-X zNhT)}hUm5H`)TV5j_~sb;J>VgQ6bY#g>nD@${~Qi*T5hs01&@Bv06CCZ=%Ehe}nuz zleRID_)q1}_DbE#2CEJ6yAt39k5r?uK0>@ArS+tt(Ie`R`6K`bt9d>@2gW=l9=#^n zgP25w=6;7u=(<{^xsX#p4y6?;c521V&6piK`kf97_O-OlUy7qkT#pbn)8P*pqq}cM zXo)l=WR&RZK*V=N5C3p6Hd3+-+A2h+tmPPYsG+&5x#$H<2+WV=XIdH=PpGl9nYDjJ z$Hnm3*_dopvk7FU6cI**Bc^Lon(E-*(c6>lV@!q%KgjO!!S202g!aJ8&o<8c_uDD9 zH-?s0e}-`dEYXkxO=K*El;_VDIDBUs!&=%+jY`FF`9`Aod5m=xwaurnE@@k&VS0D zPB!WBo3K7xg4Dp?90M%nS4md&kn)V+JRw3()q-5)gu1pw2QL9pWPvI&vh4<^_7$lE zIATDd)#7`l?<8!8gx&cNTbF+>w!FrZr*1?dWO z83O>N6uCD}X;dHwhEID8{_sdAX%^lQfs9ahv8|fP41tI!GN_Ic>`TPgt!AsOEMP=v z&fHnG{Hw7CD@1i8WknT+T;N34zyQ0sg6fss+08?KpfE+{Ny_!exlc;+B_U49~u6D?~+X8wXPuus4T{BD8<4<6OV_?V+uaw&0NgMOf z`j+oZW$eqF`n6JRHxu^)IskeYSOiSWkA*J8VCDi~j=y*m2pEG3RqC>4r&{v&Dg#D`qB@WoLO~=91IdbO2j> z_nkAj_IeZoK3;=7@8}+Pz_kR`$0l&wp?Uo162=xn7x!~^ALP{ESt6`|p9whv9Ra{9 zB2o$d3UORvZlp~8eN-XC6@<2n=H2iAxFjx9=vxKT%Q5n=bCi{3V+M0zN#Bg7bh=s4Y&mLBulh z42TyCbQP#pIz;}u>_$@thKGSDrkuMHglrRxSX7A2;PQRE#p9)|6JX76PczYJlx6ihwWJlNHI9qQEZ2=w}$%H zz{j03n(LA0@4>X(qBum^`$et(C5!)vI4%PT#wteVH6q8ay~0<-6s47BQgltjb@M{; zf}7mOS`1;r<%#V@5jl6gN>7Un$hhc0EEH!>4a71~4ui2C_!hn;7FDBQDMQP0=IIeR zPjiG{Vq#rp6j=1Q-sik%{MWS~ZI+{tte&<+F_E?VfrFHZw2O<0g6K=NH6n;yR#1jl!$MA^`GhF9pfZj%)BTP zZOx93r!6FOl|I(Z>4)&EuUtT^G{5fvhG)FyOpx+PZ}5G2Kh8Bh3fH~XA?2;G2kJVu zxWao17+Dql2`pZyo6qh%+KY-rgUI)K#ezf4HFv&DHSInp2^#bzr`^Sy=(ua<=*)pu zd0mQAat-;aNd>G;$*baajQYvzN!p5c%nMd5-^q@w8TWhUS?Ik}ULPH%Z|&`}6JT z<_)8`T9ls-YOpiXMl|@X(&0#*X^!*`dQLXM;!nV$4}lYHm^ z+ZQ3^M;OGO>e$^A)!EfJ(vW&57+6qbW;x9R!!ZC=9C6}`9HrzMmGQ)8mvfOPfPoL* zEbCKNm|H_|o{`*+-q)y7{Q_po(1hy##M! z3VZ24`Lf(a)(tCxNJ89oU3I0w((*VoURxz;E8gRvpEg=G3WcnL1-xpta5uiCj$J5V zhKTU+-D$x^vyRGnUB_uEnkE{%(&UiNHp+AQjfFySV3F-f>%Rt}HpHG|$f}(M>MHVy z=g-*{qpIN`1lgbkhMl%IG|bezO`053{|0DA$i_kPjN#PT#hYG}E_shR?H4ETrcFb= z#|TKHvEvA7SgX1ML!gU_+J%rKgj1Vr8@I@pd^hQ_VQ->)f|{weU?ax01iq)2o`bo} zJ;Vm~7*IVJt0&zvjFt$~3q%f1FoVJ)QW)K9!R#0>E7;&dqRr$7iR;@IR70Na+V{iF zn@O-X=*WeJct0dQ0pTYrvD#1M?`ZYsgkG;51{?OTa62vwJ4c+aUt`e@@%!lmPm?Ru z)#Qz(8cxdIMy)cdWeuJU_}mR=Owue|TVmYJ`t#*F16EenEct4}aqyVjvz5h|NYED6 zrurLS?nYB)X+lm21_r9G9G1`Imx|8gmbO(oOxt&8PhX<1Y`0z>@ON7HHiLh_{=<2N zK(o|!zc8)@?|;i~{hz+GnU$W2kprEnk)ENEy^f2KrGbr=5hJaMnK7Ulbn>H^geW_Q zo&W$RzzYDt&(BXq<;np@~`UWYEPIb0+75;&JA));pT|aK_c_E<{aq&&cs(w~BDTcD5iG!y{u0nYnfCJ)`HhZ<;YP8qw2Qu`@dHv)XYpdI__JNpnWYbH>SY zCMomgX$xkl^Hv#))|m@7nTrlNOTV+Wt_3TeMXUa0>p_(pK@}U})tgauTZv6O$t}An zt-I;%dzl^k`8@}PeTO9jM-@ZIRU;=gqbH3M#{o@be_sa(li+gt)#}E4# z&!;!9H;?ZRFQ26Y`&A)M z=hu$cR*zO!4p){BmKXOHCs!xekJq=)wl_~U*N@isF85aURz~MWhi8UcdRz7`_IA#8 zHjg%YM|+#Pn(|8XPHs<*u8$6{4i7F5_AmBlR%Rv_C%cEby9T>D2Rb|YJKFo&&+pH7 zPIgwdR~9!G=T_&6DvHkU&d+YoPH#?6u1}7yjt?&m_s{lsPj)vCHV4NCuOF|k9eB8O&Rwsi&&Kj^Bs89?yQ{c9&ggD-4oW$Z5-JW?+ROU;m zJ)EmPP!fg7q}R+|b|zAy6m3&Vf8-A~o5dXlgGs1V8k0&+R@TX3L64YI$C?!yW?*VU z$Yp69@7Pa9s{;_S&RzE=9GN*1_^L_qRyak_9r-Fj*ch252ev$cRZ6K`wRE+~d?bN#8Go*CxK9b zGdUtjiW0{a$&lPfF-dCSbn$)i`cZ#F(nEwrF=U{`J#;aDfTR?A;4-2}%A(HsEGnFP zvGLTp+*6tO`_Y1l^o~&^X%1ip#$W&$hWGW6wz^)lYN!Ebw%g`G^}w2`!&Fbv_#KlR1j zy_rl1SU{R~;9@@Xc1Xxpn&Y9&Wu^Y(WQFZOP(CHYj1#mLxN(7qqQrVvMB&YCQoPha zxx%Q@pLKHt`m>IpRv=*uP%*1{3gsbRh@s@f0)?@Ih*YJvfrtVqci}XRr;L;AM}WD( z0Q!Tf2)N-%h7BM2if48rju>_XGd*dk5RZ{`B8p#jb2 z$>T9A&z13?UFu6xmWC=k=kjtzoYMD!7zo3F3D*JuL7>q4f-q{%L-Q(t|0q`Qx8CQ; zXOjiV$Ff(SYC7izc$4pvXWRM@9ty7R@`K?x+V%lM@7nefkD?5OkuHG<(E~ULmm#7v zbBH6*8?=0oq5kL-sQLUy4TpVU;+MLBv`W6fh8$87%SbV!zF@43b&zJ_0}-L8 z{pii2$bE=~`k!upkVAYy@Ii7xuT264v^`=fF*#y=JwvMjKLdFmIWY(MG|WFtUC(OW9c0rpZV>}4@K!{bEWg2Uqj z%!U4Yh^H?tWqliiu?6UbSHeH!A9af7L=;9N{+rJo=<8otv;dGGnr5sG zp?4Q;#C4b@wJ*}Tlql1vHBq445s9AM5*rT_5rH)}0O@D-xw&0`jrdo!mbVh$zrP&;@b%%H+ z=`gH1R}ltVzevs3{eJZ6pkS8HNH{7Xj4^;ahGsn&6T<>b9$_(@+}z+S`Vdkt^ijTI z0w~2^LfqETI~r$CXldPkbbdH{hG0z?Q|<$-m)>BO(mFyC%RFcy%P<=m{h(1Gew;6e zL~_eLDA(Qs+^1Y{8q+>#?ahP9DRCyUS^=15yZWD)^WFii+DD{S%kl!<1X1c!h6p!e zGc;fAgoq0CKTQk6t-ChopWF~}%z&|FZef&i>~(~&$wKvR}BbG#r{=KK-? zSno)pX#-tBi&vyH30Z<+U3nKB8zfpHds;6mu{sbFmVa}a!LevlrfAa($;f6^`c;4kFG*gNwe)!g!x z2UbIN-Z7%>A@Vg9VlP_dS27b^0pWCnMmPrNV9jn3+!kMp*~bClI8y}B1o?(3p z4~L1RRs}H+=|%lB4-W8Zgz&n3`6x~W5K&~GT{Nj2s>494ySNe~)@rbPl$b zW{x!fUn`BCy}gYKjj@e^lLM`-waEp{t;5Mt{Jy@f?(Wm0EhNx95WnSM9}IBMN$x%qLptr zJFw^PzceP70F1x!L5|1t6JzX{jP~$wci#&wgDQdAvQV|dMd`B`ugmyt;Qnc(xASDr5U3vMM32M;jNuqSj6jp z-@EO%{J(n!?zdIO$VJrB%*52u;Xm@aO6|vHe-!nHgX-$%cG)Ugm^N_~_FN(OVr+POU#gtJhttQT(esFZN$c|h@a@gi$Nm@93S|qYbp`k17(R9N?ib`D z#_e$FLqxoP4Lg}4UDb%BdtDl75Mz5;v-E%Vc-UrD&vAz?->(6(@zR|7`?x7FjWH0p zbzgt5zVT+wnfCMMBZWI+CGVv+Un5(-BC8MVuuby*l&#ShX%PF{(F(Q0OC^V%p1wX& z71Hh(hzGp^S#5=D)P??Q&3M4S?KIfGB4%gTg!gU`>xmLixOtQGZx*neu7M zu=#mN;roz_p-kI*w?{?1OE-rXUzAf=_6)T4wQz^E-=Vz z55go|))H>q2{@L}l~0@EAlxSG;0A-nh5S=X?ALZ|XFCv>IS4fKej|oFmRw~c5|O{V zfnd4W7CTnwIGg&;@5lh3X^hgm$1-lRs)gUo0u)Ni2pH&U{qF4P}YR41PBe#po!ixyv$_0|07MMEs|B5-N;_wc0N4} zU1R}qWt8AhBEEi82JoGQOPAUYe*I!Sa`tSQICtPbXL7yQ&Iz-2w zH%q*`K2u%aU+)KGyLlS7h#ZBNi_Z1icKupUAxd)GRcg{O_iT|#lXT@P1KzxtQk2~% zSRyOL#*w4;Ups-iqs;-Q(%*N!uEqXDhV~$CaF!=Xex4SU^xhAJ$e{652r@WN;&79{ zdwDe6{1XN=?5%Yswjla`O(HdBYT}noUGqxYV`ZwNr%vAN4^YQNbKTY~8?2gR5K5Ma zTvZ5Cdj4T_NK*bis>Jvj?pH-Q3~b3{9TZ+DxUMMm)~oi~>3>e1Wk^t=&f_`K7W!5i z+I1!vz}`TxGGghV5H0I>%n#a7EffMTB&Irv1{PopGUK>oOVIaxK!eNa*oSUm0-2#A zqyu3W63b;;;TUf4o2ruexN4|>*qA$;-q4`b5@KIn@vofZ-PEn)a&c(WLe?bbH&Nyi#zzy;I4Vvucbth^ ziAvH2XoymtZ55cYv-iG8p|;8;n$i^M+qyD^QThyMRc(@#4SnQ$YOmXs2wX~?-6AK; z63r7KQm$s`(p``yY1>Pgc0?n)dNwLEIKduKBi|$x;ft=Ft`I(pNHe~WGQC6~*kht) zAb9amZEh=DciO0O`Qp{j<$N#$M?7(Bfz-J^&koAZ&rRr4&uCSiLU#OsGp?o`Wu}uf z4=^_$z(9aSX31q26L+-l)vm0CEpg@!h!KZ+J{UoI-!?SU;KG9QV8FdkG`oCYzZ_%P zFEg_=YQr0F`3D`D%A@QU!uEDGVUgNlGS*#=I---m?GaquXmzTpmYkc{gvPW9pW}K@ zlF3Wi8l@K)b7;vI9PhqRrCaCoagS4`8RBuCy4FBv%yF28IIm|iQ#$$`o6lSHpsk+c zY_gqoR!J+KEQv9(Z*2!fo0YJ$VL94#A@zQql2T;6dWHI^HlNj znp}zcp#N`axE!uyT{B6aaxyy9DyH;LE=EcX;jPhNbFsjqXZW#OGDuK{%A~xY;)Z!3v&0N z#GLy+Z3Tto4eLzTD7SeLZmFCHPiwMh1-VO4jP6Ph-8TJ7`h+cPjw_*SWU}#f8tjY$ zPLL)e%_7JgCg=GP(kxQf5zRgg2jP)-4!IZ?B)okV1&<*7|D`P{Ss{lQv0+6=e&DSZ zmxwO_yLp2cUY%)1V`jCC;g$d+_x3^TF|mcpmB*XZZ4BBr#Dy+d_)2fL)3@yMi$GF* zX_7)y2MrI|;jz!o(NI-gD$fHb}y)*39i!-NrC0GsgMdwM+Q)9w%k% zVuU{1qp4E&k@vb?o)GL$9O9>0?3At7-GL)~LCFF!9k^o37b;sOU_K~1{0K_!T7U` z3IOKfiOY*%dn%2&IP2p5rC{Yu9@u!oa*l7Sb$EI&WoLST|HDS-*acm~-~a&jX#X1m zfcZrLN^%PSLuURr{zu8n+brCM*JpLUoh~1 zHLCK8NvyiQ*{`TzvpM(`MeIeCOKx^7u2UxcMvqw{m(-!YzTe+)hXe#&);Vsez!s)H zT8Ypc7pe1w9~#kUl`du??`-xGifU+2vVW8CEe&gTQMi8jF!YII*BRS?;6GJpo_>?;&CEz18gYX%7HQ2ahjKgyr5?GZu>Olb`HZK)vs^@X{-vc&(OdTKaWjlPB zi(-<^Y{QJn_qe}=aAi(2fm>BnAgF3unS}jH+YNJd;tAhOj*oUZlP)Y|i|nz1Sz0q> z&59!J7X8m#8dS3c7ekoRb*I=7bE#a+do@*m{Tu$zv_ zr?EtE-{$$ptxCq|DcXmh%+dR*+rZ744JTXb{Xd>A&}SyA1q1+C0{Y)Pjr^adP3>)* zOibmR9EB7a=w1GEc$fNx!v-tT&*kKy5C5tJ^^SKC1wFE9ZYp=12QL^~5*ZZSyPT3b)= zKV3bfqrRIzB_D6aVx9I)?-~uNRoYKAqjX;zGl#7T6$#z>@`R1Ch_Dq)7dkxqQBBcw z;0-AU=Hy2GRDN*Wi2)ABbR_~MRY7oWC$vx^gJWcQ;ySe^)e@@X zCacCB=8(SM@^pf7he+g7NQSQbdoS>>JiTl7y=h7)EzXEzp*sB$Hnr{PyY~1aK39Ph zh!>fRKd|GT%n76R>{00U__uPL?jOhSn#93H{PkxbjanFXUO4uim$cUY@gtoDjpZyG^jQYh<4Dls2-ahj;QKPz zmjuDr7}%E?!PgnsmpZ}M8rYW`!Pgs@SC@*XZqp_dXo}ufAl~KXIV4)TEZ^dBt(|M?Z6~4*6=*RPArjS?YkV(~ zLD|l2cq)9W`7xo>Wv`~gL#Rxh$ySn+xh=~Eay5m(j{I?t?9ikOh>@ddnZrZND@&aC zNf&2fXv`g^MyuaLEp*=<_dpi3*8zS!1NezSrnICeDL2AmiJo|G82pz8WqwH>!1}pt zj4Wc7ayJ^Cqu5ReMwYp4n^N7~%ic;sdC4iZH2zTtHaMeNtluK0KB_Vi;u{Onecm+K zzu~n8h))jqv`kz5lVQ!sVa)B-Jxvhz%auv(IF5f(I>UuhbE0#)Fi=roGGK{3G5GeP zed$o(%N*9?pq_iED958Z}GXT!5ia`|*U-g%bPlk)PKy z*EE6D3>b03b$`dENEO)?3K-b z|FbYHJLH54#m0=lG5m8;AH_d8`^j_SEB(jt&zC-T=fti4r!86SrlEG-8M`t~9FiP>{}`MG{Vi9oRmHJ}N!qb2|DEUw7C@w=?FT=C%Q^tBq|Tn` zg?34gbpDB83`2wrzPP|2R)oA+=uq)mh}97(#Ah`I{-SfKnMLfi=YdrxT7+>XXdos! z&ZM*^`x+mY8!LfRh=WVdS?9=s=d5K~@do9H9&IF!19SB8H&D(GsS^=8ap)b`zWMR6 zSG*qlCopMt=U|e1*$PO8u%h|qHS|a=(3I;eC{H6Dq8`}s_>ka- zrhAgGzrlOUO88FMil~X3>oKu(BaD)*1%B9pt3O;X&@c4m9%47FFCJ{K{b{82*J#y_ z9e&tE`^|Fnbm!h?98Msbw2<-Y`cm?G#nn_r)bncy{Z6cD<1)>o-=@!=WJ?jpG*c&J z(M3(ksqs&lGw<6C^}4K0TYAuFa4DRu-_p$u1j! z7I_k%?|9R~we#o}fc1T32~EUeg`jQ&X!uDk4!$ym08jx;-fLjx^qFWLL06J&KfQ{5m4Wf%d+JyxqI z3~CVe%HU$-sSw`t0XDXk7mJLcUo9jcvA@xG9u*G!PWM>J5W1a8y>TYJ|2)hj2tC!t zuiPU&bF(h_Zw?A%frBIjW}V2~HZuQXDgt(I2LA&dMC=|U|K$k8#%JMKcM=dXI#Jtt zGXDfsLECqIkP;6$Tt#hYwQ($Tl5v$4O8pq98}46FUetN=DNV( zk1P#Vuo`{sf@sD=qmM0J(>g9L_Ff@WMl0-S{nxh>1mBSyf#@4M%pY<}9k} zc$Jpm9}M_d<|~bx+HO(&H%dVmm1gm3oQI#OyP;LX&ug_5WC@lL65GJmBm4PQpvLda1 zh%Is;CN`Xu;~moz-DAXl;B7S64RvgbFYy|Vr`(MIg4GoctxN|-2sFd43iU#Kq{<@KRDwF0t$Y})$0HAtr-6#>Dn>X|lZs9d5i{O1*?BE~tOK1go5yZc#~Zc5s_EvVYO$u{HA zX}MWZ?~{!_?*#Vdj&Xdv8}BoD*Gbu)TUEO}I?{*e9-6*${=?{5sWgyozpD=3@c%dD zM)Ql@^qtHs4e9=0{N?{;F8?DmX$>44np8Hd4_Fbrn!EMeMdk+8wDvVGM`g#1H)v=7 zkUy8ng8q%7CX6SKRYG!^`+6=Cmx#mGNRFz)S!HlzPjN67eJq&<*R}-FAcLAd<(Tx> zy~F(`g*@TwEy;AZO)1uWCi&&Mv+3_2^B@R}P#nS#6Ws!Vl>BXf-T=K@Ch`)@u+ z_K=G^`S+|S8?>XxcM>OSVm!`8IAqC*58NP_Zib;V%WhmT_s7MOJK_y>y{jaPT;Xnq z?D%_BG)-HsnIe>s`bF-5`szCfmPm&Xh-K9mH*&d;2m|rZ1fHr}AiOl8tC=A4P|ng$ z-mdWCkdhuNbRWsaJk=qJXQ}R=+KvnP^EIzJ?Q#(7j5$#iDB-p*F_}89KTlu`kA|eh zkLCl5=B{A^C`T5UEc>B)t*)e@Y10@7p{2w0Wm_wkzbHP#P>P84fjJ{sC`awA0GbFO zXEaZRmwWAB9}yc3hxNnjptxu=!&r}{N#VJF)B!2N9f5;QwAd0OG@;=c(2~Ni*gq-^ z_vL}ch+Zon$q?fL`5f!AGFV{Kg`&z-s0QMXQ2Z!z3lqr+4uJ9yJd^ZEo#f*+ZPHDZ z_c@SpP7ZUDBZ|K7#{HByh0M`ygO}=cZom-=5$o{f3(XkcL1C#FW|FAZdj557Oynd7 z-$kU+?xhbW9-We^HDz5xcKkRwKS8BFBcN@2stb762`{Hghb*nnDzD;ui@c9&2x%!P z*K@(J9HD^p-6JqrZGSI%D%Y?zIoi}Bxx$z$;&(2rad%fZtC}8%R>Sxy30U-tnp#XX z_}!4|GxRLy%UCRLp{``t&o)nIj~c}>vIwrhJk-N)%&(%dtW{0d7z|xCrb~#x^9Ak0 zPEIEv*lYiAv2#C%EHaES){Am2bGoKL^yN$;a0RF7eQW{SV6zw3no|5N&@0;ICuytm zdlu7E40{OK82ZxpJun~F0_*cV=b-~$aM?IQcW^@N6VTnD+4_T3AUZQwm%cinG5$IH zB-C0k`8|sq@YxgefB1UG;8415Yc#fP+qQOW+qP}nwr$(C?PSNz~dRG8?i#;&`Z<_%EJg>cj8=C!cN&7Vn4WS=xz>dapF z+@Q>+9qoQIrUeXO{mVme)&l!#{dBJT)BblJ;)lKgP;oMGWD-*P2a_Ia+5Ce^zpAH? z_zAkFCS-{f5)auLL}X|uEO?R0bH^>p=sDqq1(B?v_5$Qf~&kQDf``(sW&e$|x= zc@Ll-{`nvaB^u$QbSoZRAiNV(CX@Cc?{P~>qkq;@`7?Vc2J$68$@naSa9?nGq{|-? zn<>|M!*$x1jf7U?h?1h zHH=A#ir;?y^yKp7Sx0p=&+Au*>iJt#kfa)`ynn#AUiv$*p{5i{WmxmZ9mP>JR#0O0 z#|V#d5$ynJ*}Ahd5RB-~1cSP;6pR?5ba_EVJMBZbh#^0cR5%8MfC~m0G#xG&$0%k| zf6zxcTiakHM~C7K=sRU_K$hTR0t2B2t}-cjf}vb62l9buY{0TqH$qgp68DtGki`I` zGUyRr{#%`;f zY+%kk3Cv_ym*|ktP~E2#_8RZ=Uf;sxY0+d|%Vbs5pE0|y^V#L;y`oRKdW94p!!Nk) ztLs^DQaw|AXoq~T6&^fhn^l4)h?oIUJ;^AV5f+JBcC&MsDriiUTVqmQ0J*y-G#;I4 zCzhViPLLUahUh{f`BjBre)BYVS1(Qt-`uL9=2h*I4z5&t+Q}fP*j){N40|q9CtH1L zv_b|5lR^kKNu7db0vqBgW;<~&ts8jY-eKIx4}+(8og1VQk398rlsd%JHcG0dtJQra zfOrveF4t4>s8*6ISe*fl$NX%O@2+e@stZc$z*D&7CkMlwz(!Y!m2zmCNDAgbyvRo1 ze6|A^)6qCR-R0woS31S>!q%u&c?V zIsOUj7*Ew9Oor;ic+_Na8pB>9c0-~G_~;?QRShw#07C#WBTH!fcY+B81o2c7aPZu?rMa4MkVJoRLt=T(Q1LN2O(z{`CAC5q5Kk~pe z(PX0LYX;&M!@-p94(bftrS9-q<@+JT&gW-BmbfKF$tXlE2}{5thw(O}hqWYTJ&+I~ zBokf~zr4?w)8{avt2GAEDOeO50s}$8+6pb1Wg?oa=x(6eQI=@gPObS6*l`vG1UJFeXSWc!se~m zsiG9)uDQr%p2+=4!udL)FLU09x$TmgXf8O1>r*_j@3}99>3&?(Lw6F6L>lc|>gm z^_ISz==Tm#uYhUgj>WZDm^;&~i!hj@CW@oO*9p-(Z@9vlSFLFZ%^1V1JSlytQKVXZ z0BS$uS4#1!BZ zGg=i_?z0LN=5631i^Qpl6`ZD#NIXO3_21Hi)N`xl`{$CLiwCGUjlmK1WfZiHit%hk z0yyeMTB3w~B#9!qs+^buUsLHhtHefV!OKMo!lH?=-AY*ZQNJKucGh~JW$P;SWH54B zeMl{w3xx;EAI0<}^us1&i`N+B6$3Pjt>BX1h}sE#3X(D6DsV!#s}jOtmH*}oXYYgs zxXlphMLUEJHzGoZ5rf)IAG%=t*d8oNUdYaS%!){FCOd_r?DLP}iM;O@`~1;^Bc&M% z;^cTw)}wGQhZ_Q<6Y)UI2}&BTMSpkk?6QBHh8jP|Un zb20ypSM8?)5a7T|6n=}sy410EtzpeixbM6I^HABzvow;~^RsyWvaMUS>?B~M$IA>A zx|XQ!EUb!3`g@Meh@xS4+g(_;5xcLesjg$yRCTw5V|8eUeuaMx=WY?%MoS@cB^GA+ zIcwuV2|TEwY(j&C^@cu5tbi*9d;mZM2Z%&4h(%e}NyL+AFC8YmyI-TSQ^84TDQh&> zFv<0F^EU^_xx{7sTI)n+FicAy!%tmwVR`i{rN4jNt z7`u-wV5r%Ss1@iWLG^iZWII-xYx6nz2TozX2#$hY9ddTHDdQq>&1MMhL=4V2@5lj2 zD8ER~I7#ThceXr${CVzWp%FYJs*TsLbqe$YW#)(Ue*Yo;`Mho1tFE2gu z@`M#!OTY0-^;64jA;bsoA-C1QOe0X-7rTWxp;ugS9s}f7_!HOZI!Ndmj#yI$Vr^cu z8%fZ347yw^5^4{f=L`!g8$fP09Wr0e0Si2@j#8H3k+^u1byvYPcL6>WVubf|dM zoYSBM1<^q3_xpcq$m0Jofwt#FJ8_Bz-jovtiN`tMag*Px!~L^ylMl$=8y?JqA?fO* zZmThL?;~tI&M{4Jwd&xiJIfJFv=|~HgF!0O2K!}Rg<5HW)41WQM}nU%8HW&{5a30x zYoPX00T3vVIo`d1I1Z^fmr0k}EZ$@T7Lc*y&eI?j!c>boiG}ciF({zHwucJ9urIi) z8yolPZfY1k250#1f-W`~{*hK+RHT4VP8r6?h5ixiJ@~Y=?Xh^jxe|MjjLf!AFQMH1ds-=es z@q^V?wdZG$hQGKo#UEhaCwW%21a^$_u7MhZO9I4G@B>dOCf}r+U7*(d?tGE(GcW$M zwpMV`&<^1xyr$9IUfNx>(CKkc>dY*ov4>v8ys(M+9r<2|hvlqVI!T+q+8TR*!yuC$ z9-UFKJ36l#b4%VuM{a9vj4E$b*sVS*>2N16`KPu;^|B&+KLt$rJZ()K)Fia!{|?*5 z9UImdzk%K}GbL#O1D897zat=mwLZ7BlXQLSiA&@@Z$B(WP&yk%QpoGm5Kf}}nDH2U6> z`Sng^+vs_x(9JNDwUYHXMu-8nq(~0+DFyLBmS@?AK5H$dc5kBCo$BDQW2ZZCyB~i=7-QltbjAd7*^X zVZ%a$K*1Tp!MXhI;0V2@1ZD)J$Vf4)V@5kFTOb&9VA#0P;07Mr+>eO#@C(*st}q@J zKsS=;$FZ9?&w)zF0kM9Vy>W>sP$a!)l&-oyaVDP@*{t<@oZ$wrZ2A`yr?XZQL9 zX@ClK$9Wh7N3($db#sadt`rEyOAGkO%~gU%WV*O>qrQkGt{{O`M_(bh0@jms(BCm{ zgN|F&)HS>jXkUqp5jlBcd9DH@amb}3+|NHN?yu(S`f6Oc-v-y$5wj5di@rYFEZaWo z&LEl{=z^}W_XI&WxQ5N)I&`aEfp!t6RTo|~1!$^CFW)it-vo7HBgyZh12oA$h1 zU0$K5@_n~82407c)8p{CcB8j7YiC3Ng5uZcZ-I*d*q9X1BKfO;p43Tqw9S6A`49kQJpjvi?UB=S2U1nP5gbO9NMf z9(5bLEjEO&YM@W};7CHp>`B))7;|J$r-S0D_~DA2Ry`mPCXp>m69v+W?)-7TJzR;2 zW}`BV&YAkBL2f+!UG5!A++j@GCUr&$y3)Y3Bnt&9rjtMz^=yU(kJp3aC}&msg7LH$ zE;uDTyk~ejN^0fFhaB)>r-YL~P2#A?Qo^sa&|dY6k-q_xOiDwgYw}_Fv#YgalTgF6 z8@w(4*idA&&!$6#o%D*1X4_RNBYr`ma~t&crbySKzQ^mJ@uXcsekfvLu#z7)G2jlw zr4|^r`C~$03Yp+KFh;G+Hlj+Vm=dnX9!qpro5^4gdkmU+>RLHH978us(8w2>6pb1x zgBNJfl(e>+xU;kKE--7^Q%)+RDo%Mj*m6SngF@VccV^IcOlvTDhmr0V6?poq=o#qL zA)K?82Z#$xO>oQ{MjP|wAs{4-Zjh77XW_?rkr3r1<+vz?LVY+2dhSFGRTX{hH+wm_ ztbW5dc~kn-kkz$F1ZJPseFFv8AD>Jyn0 zta`0CgFokK@%_Fr_#M_O72IK$fEo)W{ICyzrp;KXE?Dc48J~wDg+h{yEs+XrAH@L) z!Wzgmke9>-L9e1L0YyFyhh5^~G946C)IH6_T`2=2@hi?o;@6DOpf+1HRU!v)J;ixI z2$O7|=oRhc6i#X&`K@)gX-M>D<`SfyJ-<&}H620`=?VdBHg?(}587SyZ_y8IzknL) zB-UsPLrxiSWJbWcnGIOR8`l=DASA*I9mpAnYNw*p70L(yQ_ge^aDE=wlge@?r~(8g z#0p)+1qZmhWF^xzp}c@O$3h||OfC1RVtvZL%{T}Kq$Qh~f+7HEGU*Ue>f&JZfZ;G> zq9FZ(H0b9r6lE5vB~0clR1z&0zltf=Ns7r_9MtOj$BH*ID>Y12Du!`)omni`9yDq1 z9o#tx;>9}6cpZ0f;rO4ydG9N{?(giyW5GU^n0RpD;@-`U3gu+qZsMMRtt-3saPcxf zKnE_L#PkF@ii6E#s*?y#YJr5}Btgv$i#14E)rVY7doLWgHVps1M4H40mvsv%sn@M28xSY&yO~=ij4O2Frf<-WsYaTPf8~=9YrD^Gt}l2jNv@!0Rm#*M!+TIt z6k~J7F~aNV4^*C!7qS0FmmJ#t%HlG<B?I7v;97-mH_%g^n{ zy6Z@s9e^@Bwg$-prRG(GijDKHMSOLjVjA1}>R_R`l|CE)y6Rw}6PDgk$OOy|a!X6& zm6ck`6POH+EJ1n6>h1=SfZ`N#(c*Saq4!QQF{cEXzEp%N0I*0mBlV1yLm~Ga+apr3 zWXLNc5Xp~&g7=R!KQTl{2XqDxG$>F~0>h1um-MQ4II&OA=wc(e5-xO_^XY{GNpo{2 zFSrkt&lv)$a!Cc3+nGOFfMvzoiWLpVI!}$nzullw8Q_>D(F#>FA?}Eed35%Z+N*{w zAY>4%P*vKIUk~pZgN{MX0eg@YVV7(*ZPsjo3Z!b)E_vx9ZYcAU@RT{A$vHwaSy#Kn zg#zqx%|s^edXZUubkpkZI^~8~{j@DTYhO>l6wR>#Ppz?fli@e7S+)Vd(2yR)i6k@~ z*4skksQ6=t=#q_SUEDv$JpGhqOjG}?zaI3*X$V!=dDJ^>&*m2w;*q)Q6a~h<(8RC~ zz~c7tG@8G{5a7d{#NLHiT=8Lkc%dgSY}iq~2Z$FhN~lhHE$V=l8Eg9=Jo|*AC0)Y` z%z6t*t{jnj2%h7M*i(Xewm|eal$p}sta-1x*B4?C6O~QP&!sA@zZrK=@LX$#G?qN` zp>`mxzB%_HmBT1JKhgBDJa-0F;cGuS?>q1U9roAVVRX4v)aGC6T3OelAvsjf<73%A z$S8Ww?arbj{)9N8F%g66Ss_s<#r+O{LJt~2zDH!g`(i)N|F~SRT^lOuXU0|nrjv7R z=xVW-$N9+YYpZeRG0Gmb#2O`zn66`OQnG`YUV(cg(3^Hj>a&tbBeTS^ao)VrV;c{L z=7<%=zWS4JA02hJ67WT1TBXB!FtKxxE~5ZlMPO!_wqg6-c*;&4AHSx2@2|Nvkf=pb zP=Y?h9XRR|&WYQ3{x@OSa(2V_q4XS?!?4JP#33G`{J109Wi}-}kb6u1q5y%!k?@sI z`+7jpjECftku!i6p_xlM{>5%^a1xx3I75b<#IV#ZczS?V9bRVnI!I+nox_p!vz>c0;qM+WEqM= zw|Rs%WJA;6Fh8dgwU3Fx@&5kl{2>4k0uL~<49-uPRcUa~bkw<>OhqFDrAi9&{4$zJ zYId6>aN;1=e>Z<_deAhfpFaL+|9imo=M(>LJlMd++0Mztz|qM3zo;V_yCMbzUUtQ= zpcTs!n-)TnW+|vLo0hAVvL2!!T*H<1@pNB`Nx!`YLV?6m!gJeVVTS2$59S9RWA6~W zil0#AnI#X7`F+uNgTPb=3YS3JEB2cZ>Htt!#E~NCS?uAF2P+Oo!;$foSslLvA2!^m zn)nosiE=VqQj!QKS#Sgj?M0LVO-rhVeNtZt^#!63hi2xU@`PeM;*`B4urk%x=eEP> z-&PE@SlP*w)3luNiG~8`$wkm)<{mIGdS#1LeZIl$5~6Vo!fe<1vYv$=rTw1W+a;sl zoXB%|(l3T5Z}4A2<>y&=h?(LctVu)&iu3XHM5iyj;T_VsYm_#kAob481{!myVEFC& z>U&OHYXj9r@@(d-(>n|>Xh@M9#lvwL*YXwmF*l*cYPRm6eaCp_hHhEUZ z`D@qMB>9$v&!te$quXP`<{--ccKLd=}#8sMTM;c9CB>id6M5drR<^W#;KkaT)Q zOXo?&GknCHUHW&v!=I=ehYkHgRZNx;G$^4s>@kBJNb+>s`F8$o1hbPAMiyEsvaPeH z9Pin}Z49+sY0@`R)0DUQwA?AAVERiZb9hE->&bet$+CR>*>uGRTy-IPP(LC5$wbE$ zoRghCjd+9Sm-HPz=Wi0gHRQ};1B&IXg5!>BHS?L@wZRU5kDLC+ohVvXVsU{tw&*Sv<-7x!vxXG0JC?-cvF1@QCYzt{gh#s0~y5E3%B z_{l9X@UZxY)|k=s`d4bFm2>VU;E|TJte$MVCSe)XDcrc#ZbXhZWpi44?m>X`ui8#P zaXYr}{R+r?GP$PNp)^MsOk5wo540Y>{#m6;#5Yx&Swb}GF561vF*+e65FF4XGc0nR zf*^_`KXW53Gge4cylUn9K8n8YjMqcLkjsRmc)=MEcFsdCZJDq)oF(e-%YsL6?uShp?_*Zcd`zwrrZVBo<|DN4WXAEqUQ%H6z zJ$*FIUb7G(iW4v{$2fRiMqf18ZQE)VvkauHUBe!l_c^Cfl@fHyB#XB=w~(Y0ZsXS$ z#StQLT{}tIcAse`OmI6`iI)vGKp2(Yy?W9T%p5+zT!P0L0uJE!rj6qO5M4%|`gFPg zG!u?weC|Z;yY7gva4)NA+H|>OHAXsQ;=m!PNO5ho$ii%I`VdinM=E5_{-OX>SLmR6 zWC{=zGT}rtH525kb7@KxHK6G-S=6{#A_!It8Q&|gpCv06Qw8=cd>|%Q!u%1~GB^ae z_N>M{2G%T%IaVj=dH6-=QS?H1wJFXpPBVbbL9aRPoSZz5d^6oPU>RCrj?%?0152~nLXk}{g_j$M_;X5`C&7(U zdXaD?Yj%|01a$5vZMu&XX?kPfX6^a|r;m=7MBruqh4?KQ(V_Wt^Fa-a{M=UZqit!* z-`&F+BE_%8h!B2&SmtgAvP4{FbTFC>b51zSwlgHBghi2v81SiJMieskieOi`mdNh; zSmzhQZIG}kh1)f+CiC=;T8a|Msk(GK$>)dh22S=)NGyMn%6F|bH3ASQKhk8cJ+Hn$ z1-1J6EI*&u%D%1BL{YcELh9@Tr}!B90BcO0Vvg{wJ|#KIN7B5*>boTrDCfKY@}T^Y zf^C~b>P?$(iDO(PZyGdS%Gsd5d)b7P@z^v_dHe>ASs?baQ$W=6GOPOLdStXcF}W#O^w2ZJLOJ`w*85p!xzkIkbX2PRR&T9ospq9(kk znt}lP>K-1uTeIkZGHqFRLru+4!pp_-4Z3m!WaFr8P!~L@qh;mc*qGE)ue<9vuhz+7 z-)sxky*^FpN!CHxC0^J0U0z@Au<@6*#A%_mzQgMN#Nf#4>Ra$5;uxCcOaK~8QwkD( z%t5Y{vNrZ+X}@sWOc2v*TuUMz;g|GVSFN@_M##dhVmg!=Qzn@zB84M=+(Z<89Px7! zdLcDHS@kHn5t-_&#;FD6ev7jj#rv8|%Ptv!EF#GAM)#T}%KRix7ga$P<5Yg`oKY1@ zJu58?D!(ov6hXsc(xiM{F3n>rawa>2N>P-6i{eD>hen62#uqAZ9w)335@wxM7l~xI zcIJ1!nRVJ~q5yAGd0B?ED zo?pBrlOJy!_qrn2C+*7${>FlJ9cj7or;#Xlev1q~zv`C3bNa?7gj#rGc_4-D44wQj zws)l}B{~H8^lC>*7Z56qkzQ#HSb=IFopg24f$jYUktbfgfY=vooU_D)nbl!D5mdO= z+fWHF!2zw) zpVq#bb5!4;f~P%w)I!O%{-$1o{tPW}+K6%|^-dW$f3r72%i9F&>N>zBI+t{Y#P(MO zM{%#6fE-^F_Iw(`J;i!y2Pl(x#t_sit5Dk*acFjz(WQWMsE3=BXA!7dLf{vnGyPW# z{1~i!70AzM!5*3WH}tc+as%54&i2D6HVLriFZdcj12 zb~ws%FzPpbB{D3N6xcS(wkFVFs{er3G&M_Yb$EMSE0?Fofp$3HW&~|Y>2ni!z303P z5h6;Fkr$}r?i2c@_fTPoC_GA=2^8yj>)P$Q&D3hRkiA9NJ6+!-56dNHov5W(tFR4G6OUK|Bc zO4XW5H{K7+`#YA-yE_`IZgb|h0(tFAuNxuC50F76)$rM##bVwfOX1b`(=PDv;o>Iw zQ?FyPL#fiL&LizI%9|~qRBa>3rBk&TLoy;W0oK6Cf227R;7R58r{AQkCdQ#>vf@M* za?8v`p&6)0N?D;JlrxmX2_RJZ=*t<$ho}aSUs)BqnHdjF2squ_)A$3()Dkq?kT^An zVn&HKoRrqDK;(fWgNB|eD?*gVFAQ3A-U1nRhZg1VOi!O?x!QnG9sZI>>J|tC4|zc% zFLtkB(q*s>13xZ+yb`d>kCAeu{uAKp3Zx^UZ9~+Hhiz9HOPqt-BC1Ezj13GO-g7mv zIObG*+Vc22rWx*G))U^^ilI8PV7>s)KdxTqEqEs5$UG#>0 zp#K_7^3gQl2hiu#KMXdM2f zwna6L-4G)0+bRAbZVcq|{LDRFYdwWzW9MTu_(B03+dsK6z@-zl~%q3o(n< z*QV{k3wis>h3QZypTLb?!Nf0THcBpc%{D`O-dixot>U3N;v^$L4LzlutS8{ZAoa z-)5Ko@G>_%XUOGn*WUevOYQUGN<>~>G*P;5j4XaFWwnnj1Ai!a#{FG;5@3p>v>sUE zM>{)@nKY_olm-eC)8^*e?L~1p+jzJ@WCKcjaY%VfQq|BCNRi+pYlFuo;mwI6oc;U- z7r#an(-XRiY3v}qNRHm2H6E1bR$6UTrwxY!O>X-aSJ5ZkXIh2d`}EPP4*It$kzALI zuFT@aWitv>k(B6YxafJcu=W2Ur4xBEicBO zH>76Mji^y9*AP)%EqfYc)Vwu=P;32eprE^XZ-v%XyApCW#gaz7H5~)p&;G>ftV~SD zT^^Qs(_*FhSKIC~XTTproUoRS*d^M+===;RNsRlVfd2T(k_n|NHleAp+ggW@0keh% zD63so#}H$m+Y!X(=L~V`6(GXp*VlL6A@> z14DK^Uo0xay_H6u?e=M)IkNzkmx-jVOStYegh|oW0F`=6a`}i}AmI6p4JQaGjmBh- zLZN?(v-t3y5U#OxFtEeiqD*c5Wwd}1n_-Ovl}7=V4`QN&cW7b97m>Vu(!o43UcN8D6vW*nQs+>NRJ3$^<{D2r&Nod874_Gh<0l6jaGI4@Ya09!2ggm=k?IFuitPj<$y`frp&$?|+G* zMu5MkIzIuHcZUBN`zZeZn6>@`=>%PV)Mh^{hm(DarkC9o2h#Tz^rhRr<-+j!Xd=E0 zdzN}{)Rk+N5Prv|R}?T5Mx*eSwXuYhf~$9!?{gL*rR06p`61A7>Pz~VT`05A;!YkG ztf1|ndrl%hCvq|}ViIMTn`Acy!4gL=dEo1_aL4TvBq#5@h@V=U6Of{vmkpkLrh&{zu$MsP|vQ9wGJL0cUnaz5;uFysxA8q%?9l4RFeq;e_=G@vW2gmZ3d$286}E zZVKZ?lD8RTN0C4m!G#5;Ym318UlP`XlfwlS_+=9GXM(=J2mN5RumPWpt_#f76mS-- z&R#&8a!|^MamARv?!XsCs$fujIcHn06QSbrnPA`4MpbL^<^_VCns;~wnpjrt|Bf?q zDaP8{ZrK(|qfq#P8sMIQz~_D}?Z!oU${g|LIRWqW>oW{+v0SpVX9 zDva<)_nI{&z=o#)N8^JX8iqa+RJOA?c>N>8Xv>-<#{#SjjRr;Tdsb4xo$~SCccH5; zWX(xV`RvB&Muw;(HLFXpZO|v<+e8mV**uD#mU&v2V+xO^9j_FsVU5>;BZm8%spG28 z19#472x2#mf%3r~WDdVL^$#MV4@>)G71`%rAF4q#fex))O);ORyj;sMf_j%B&Ec}q zm#_zZq@e@_P5&T~f47xJ3%er>4`OSu{51PZIcaOADqPCSwYsKg)zd{tNycfu4<2iV zjjn)ZgxR7|*{G32M!z8BI@IUhBA|Gv3FkR#@Tj*j`vAO6fZ#Y&{i_!oZTA$XC=~(< z5bXzH_M{JO#k&nls0g2g;9Qv$El})M+?`+~>%v8gPM{l!dEy|^vpilRY5nk=iKvdE z_OR0+(Rec+B#-=XkoAR~cR06z4gEcO8rbV8K=-h>7$78MBs_4UE_!m@JsnE3$rBi+ z9AQKmLt==uwSH&NkiWhnf=cLcbTV+NmI9Uq|3?_jf+ZRsaIDWX9QEdQ_}ix@dC z10&imy9C0`6%L(*SrKNBcCx$3drW0kHH_Ulm;G)c^mTUNJRAX&3S?z^-eq8 z$$AqcrvfNU?oaCGJk7PE2+1MVrwyM%)uO|Azkp?ZkxV4@6T@E;l1nI!JO-3MRX;%e zPDvs|WRi~vxMjO@42UH-WEdBm#woMkS1NFI&0Aa01l9dy(8Z>pHZRaXE5QCU4NzZp46B1uc zyA;vD%pIv~Ecfqul@pj#g~E7?zYtLT9%#8f446`3U);jfXp4?q)nFV8#d5m3%db7n z1?G^zDN&AlO^&MK1KmpondENvOQ%0y3PTkh)?D3?>w@ad@)f2yO!aauMf1y#7h9T& zZPlXBob{h%Wei+fhQJ;iO^ooAC9;DpAY+W-ym5xVaiV-^ag-Dm#&6BX!I#dJsovh>!B=|y2g z#FcW`-D#=wBsCc)>JZgH{hwCA5QdX$mT7@sX&|f0}s6{I%W*<$sUv7BM`ZqxZVlG(k=ahgj z#tGX6xan$G4a}HK{RJBHCZSbw5C?wNAvXZTEM)>QwFE}f?%gzI$k_dnWk8bf6j0sDoJM1wC8Y4CMe6b) zFs_jUvb#FW4e_*FuUr%w*p~jNQB5q{>!hNyOPlrIqfzxFzhhtJe{E`^FcI0q4`VVbht>xOy(yM*m}P>AS~Ik z=xiXc|BCIk8F(=U8d4RHNK-=p>>5f{YtPbufbB<;nfF~&xw*!92g3*U2Jb7aZWus^ z)#ST?-+O0LmHZ(uziE?0H;)vVri^%K-XGKyj$l|uh%?@r>a#o`xl=n?+uv>t zFy1k*Z4}R=iKz(6XO`gc{ZsoBTHPtoWUs;YAJO80)E<~;4gSX53^jVmEpbd63k$Ec z<&z|&Fj9WuKppU%MZIKGpAqG zWb~2ic~s{;6?@{@T6yr_6?q5%^dHv&GntmQk+x?p{u2uneK?RW*r-ZJ3WrYabAiJz zV-uJQ?85(o5p0#>F*i{^Uc3m&C^iX;3=8Opl|9rO_6ltcr9X$@i5;F8|88u4>>wEE zjys^sH8}~0T*x#3Yb`WqO|e~(Q|~SKyuyy0Z~ct27DOXuL|H;Tg+g&Tf`)@e2EaNs z1R+NM0_+^|W#cj64Pc0$d6NBU86?SZ05oMLQ5b=68}qK%sl#U)hPGoPDAE8C{CcNr zVLh2O<-Bh9#_r}>SJ>UNPOc14j{r$<6tfE!jJ^2EQOl`#5Ce`*|PpJx;kLW4yfTBmQLwE3R zq%t8Mv%rgD5ZTC3+Sg?KZa38A$^qBSTz5388;h%81R9x-Z~*%vqSCL zSFY(Y$G9?7ChS~Gck*2p-32GZ^8I)Ny<;dI{jr|JU0Olgtdk3d+zf5xA8(D6>Hu&M z$7(J}0&?y%~sY zJ41ADA+77(yoZ}Bf;zh&*l$>nEETC0PHfdlCA=UR(zwoCp#9DyxCYR(SWPPlG^shG+cr6q>q z`aNXKvJnKhmNs-WVkQ?iD=b~lY+3sVWzFd+h{#xH$E3r`&EpCYN|JFMa;L1dV?i&! zY=&M{BU|b`U6IacX}l4$g7o@*d7M3L7s(yed%$2!5xA?^Ix#R+jMh0kUZZLKo8{NR zySZNbkCDSME7;sL(`7vN<27FC`E5$BP%xZ1bULXWcln4OTjn-TgTJ)4I~F%K)#0dB zZ5PsBTRiYH^ds&RJD@a{8M{aDd;|qV9sM)-&L3lckW#-1jK6xiLbVaR zoU0ALL)qO&Rb=Pn$Pr-7%FKFjLHLj1QCxB2<}nVCsG|FQ@kRP{Ym$&L15{3UITc)) z?{l(^YdK0^;eb+5G&Lsk?olGY1|)kMpiy!+E}FD?f=04o74L&`P^tiC%QFL+Phn=GCW{qzc16#5mM`1L$K*l)biRk9@`8Pz8yYf= zZV+i{P3>r^K-GR5Cn_bR)(2rhTXY4bWY#nMWR z2`i<@Xs9tC7yzx@0(p6@(fiZZDr=93SVTSj!GSXbY9mz(P(S)ZdgdzwT~a4IX3y-q zF=#xqhY=kz%`o>f!gL7(Qh|nPMGY9ca|PdtyJd%|Zk1fvGbW}(xuD7g%zMQzXq4B7 z>HorP2Wn9H-anYFf$D!^w*PN|4Wu8;_J8u1ob(J0jI0>{2X$_=Z?-=DZ|>6f=lgS; z-5#Ic*T?x%+57X&UXR!FY!3H7_Z*MLzkVKHZU8F-t4`&=B!wgd1f=}}9|p`A=r`p0 zU2OIjF6t#^1^$Hd=%rlBox6lrO%s#8L*xjiZfyZO3(FN^s>c*z!q7pZ+i|E21-wtf zLopg=^}mEP8P)L1Td5?%BQDFl&)B zr_r#$Aak-g!SY_Vmx+US;3{^IN6ILk5mXhaM=mv$MJqbjuR6}Ly6Mo23aiEz$5M2l zT+RQ860-ScIrpCDo_%&tUwLk*aT8;K9qHg^;Q$~41?DvY7ZLs8#t9NANCd$`1Pd0J z8r4H!)nUM@h~oCj^F`MSYenT%NE2aPA~L}=D=Uqed4Y+cVnnwJtqg2rTbNi%71q-H z%~`Ob25dL$4UkoYRD#~}h;4xEnfgHmAmJ>57;qrQ0v6fyp#l6MZmsV?-~{;Rx7glm;``e}c)&)|BHbWHFGj26m!64HC!VMak(i zAjjo>G4c{WNTX4w`7qur9)ASpb%>0t*(Gmxt9XX_soB?6c9yo5v|Ro25;IeC>$^Sg z&o?($r}4ORJXo7hQ>rUF-StcVZm(}|{;=2q1+u@L`zV5LI|=-SfFoGbC4gb%0{~9Q zLLu&<1+Q#RqnngTRivM$G;Sqog?W>qvW@>NtQsMlWIk83)I0fwOLOHn@fG-ag#@h5 z(eBE_0k;lF6CHY4sD6X>jBQ)28Uo+b+u^* zD{C)ssv=7{hp?oBw1gZFXBr)Lmz->b0%V?4_V_rB7qm3p^A-Hql}^U;pTyX*V;0xS zCLVNvl%xsWmrG+@pI3=%Dhegts`IBTLS6a-~|tLz*%d9eixxII(p)X&B4*y#_zLu-VO(kqsd? zd8~=Od!o06jBP6S7OX$1^JXkhLJV1idPtMHtUgNv627oSd&N=)%xj`NfQw_CyEg4(@Sy&tV7ms8 zBdE6IXTLkH(H2UqRG16UZk8RA_SxrIGWeL$UqR<(>v`)oqs#by>BLgI zc4Vv-O;Ep&iKa9utBccL5O+T$^N96Oj?|Ty6OWv8>07)aIMUR|-NqMMWZO}ofSFnrad`>TMAd0Fc(c3^JW=Zkix zSNV&pzzfhJ-rm|?T~IK+<94Lg%GhMiQKLxhmn6=fhY-A12-*4V%|8kfi`K5x7Ek~H z5wQQX=;Quu2{Hy2wtA*NzHd(SqDnvem#vd*fw8zA~)l|KA$ z*?^myo8#l-y}iA)wY9mqx$*JwzP`TB&d$2Jy6Wocyu7@eoSeA0IDdbCKR-W5M@M^m zdlM5AeSLj-d3kYhaRC7VPEJm0YH9)k0$f~NIJke*DF5&EuPysOeF1=e=M%&lTjZKo z){+vm-%^h~TCcs-oU&eg_Y>HO{TRZCtJzOj4h6z8}#~wCsA7t^yXc!)jL%~d*e~}+hiG+;| zm==40@5B1CuS{0Bg%5@ZA>jdNmap`8=8{-$3QGgwaRmD+CGL;K;Y$!KK&&xP-h=_& z*QQBntC9x0)(&c$6Eh5+L_8+_x{Q40Q z-~z&+vy`{%2lRfvJpqdM`}O&K2Eg8i=>ao{BLu)ezqk!(06|Fm2N3h@qewerDGTS| zqq6SzL!dj_Yl0S4_>YA<-WnW0kd&IQMR=E=5ne?J&u|NNT&zd6FJXKUj2 zZ()s^)N`TenD5Uz8`Ihhi;TY(2^M=+lIH9+n^~$U3^j{`>qvvFQeG@5CJ_=*=8S}e z3|FL6$&wVMKb}jeS+?GfU47p}H$P>sUb4aKoMtuo@xjMl%;J%6kpXxvrUN+#M6N_~ zkaGyT<9B4b-pk(Evo{IOP?BAfQ@5!)?p{W($lJW~o^#JRm)KX@?jA?A4%>$1Mt0=7 zZg@J9bn|qbt0(}V%dxAi{I-2N-<{`_<<^?$l;D@rC(}U;2H%h`MB;?WyW~c5qPw^~ z+61*7OpYcyi!L@rw=(fr)SgtIcrNbv&-{G%y_bKNJNcYqU9*DV!9-KUhV$ZKt75o1 z9h`_vG}ypyE&f?doFj+t!NAJKF@JJp@* z`M&pcm129wQd?7H565n;wr7RX|@4s z3tGuasp`Fod{5R?)$AnP@x|t28ajjgI+tV1$@TmAGd2q+DOdviTBrWD;dbW`dk`LS z3V!MwT8=XdNek;D_24A&EKxNl)scy`if$_EiuKhu5Kpk}vBf#ot(Vbth;?FxeT@CW zdiB9=ZmDu{wYXM-Be%a}QUkGJaB^>wZ8>#m5E4E3rmLO)&bd%0eWx~5r#h*6rX`DA z*&4wa0wW{Zrp?C?%7}}MJDZKGqiF}-kM1PWF)J*K|HE5vQ)9AcvIetqgTRs3@pC*t z3cQfI(8;rLgY{A+pz6NvIPVYF$Pp9w7(N}AK>sbHhfcH+*Pscm+z&)a;<&krAcAAA4*@O4hnnM8}a{o{0O z+ji1n$F^-79ou%twr$(CZQDHA``r6_#;AvSTvcPNT2-~aIlo9^%uo8aO@qz8*WKYN z{Cmm!2yT?qjEfD%Ss*~q+}zyxa<$)gwdt$R^|u;ehE$JKp1jRmVIlyyE8|%vrsV|s z^3wp%t@Mr)z59+~6v5}NfH;x$2!9QuP;m2)=4yfSmf1;(`U)!tg3tF?n5g;m5A@P; z&&Fl4#D!pqB~Z$;K9=HP=-^xklqKGEm4pYDo?5IricUoi&+($leSov5n4{pqQ&L4< z&BEK=3&)Ep!8Vkr6~*JV_j(gGPJeB{p#Hl?n`K@x$DsDs+vB_($dA8gwI^Lw2VS-6 z#fs$5C?N9V-$0s5HIHuy4@ZQ*VV7{>E!NUym+=w*+gWWd=+cCoYOOond0O@*075qB zSnc_z#FbPU;fCE~e6s?uAq$9%= z6SbrAY%=W0aS0=>6M0z^`?n_!d440_t*=zqWvkc{Y|8EM&XsbEkrZ%~)!M9)iLs2I8__lp; z9_1sqlNXKujTXIMsL+}_k>f@oKkYS1*#ilu$E(8|j_ah+a=a>HNNJpoZD-&M5x%+Mo?xQ7CXI<*z?TPGw__X#1E;a-Xy*ajB_?7|oIJ&2%Q4 z+!pG10tOErL_KJu7H#!-X1}f^P3B z)|jsS8ewTCEPxuXwdXne-S&m4#$cZ5NA~pyq)gsw+IchcW__CdE-28}jm1W*B;(`R zVRz%Al0P|@eJ#6W=Kqy6maO|#+k=4XQ;M@nh(h+u-+4@&C#n=DQ0t1n0X2)?prGbl z)GFqVWIro|VtEBmD3hGSR(P(X*7bR2&lGS`xP;ijLveU^BQB#x_k7{{$3J_(B51qD zc4d90jvA3w(t)VTJA&amYI|P8P%BX<+|93C71*i`=|KzODm&Oz4{=;d1slU8j;aWy z$pdriRjcl7jH8kqY+>+>KBPGb1-XJ~$p{YWd?^u@U&w!2^ z5_l+YVs`qX#R$O@cdP3}JzZ}oi#UFCDsE+!1hdn$C)KD+U3H5CS>tY-V70jjcPQfk zC#m2vlFx!FwtaV?pVHsfwvzU+K8 znA+DU^Y8$BcNUL2o%bVw$Hu&5BxTj+p74u_s@p0PVZ*5BYp8DRwY1jj%kUAZmse@@ zuV7djO>6>kU)e2G9YJR`H83Tsz$bFLh+;tND1FFqY)PV1p{^2&L zZcR0y{GMC6T!Cdi%LP*$0A@m-dd>Soy_E_QpAkb_TmK0@$>dSp8Cr*&KLi$o(4&T(}8(N%-!>h4Ahnv(wJ^L^{ zqE5~ImSjuTkEHYs-do6!4Ko0uwVZyojr;Tpn*;MUyUod`4HWVKaIIrobd zuid#<5As(#v3m<^gw6u76pJXYqu$mn_u{{`&JXn|mu%nr1yxSfu`pTRu4E6^&(&C+ zhdOvV7``cEi}S@tOUPKt{nLQT)`UA(fuXsq!cxE30AKy7<5$rs|7ZB`ua}vcJf(|Y z>QMaD^rr^Ow|y{!Gsq}@jo$#n z3s~^co|hw#^xpx5zyf2_n~uM7q&ZrgHhXuho~D{1`f*CGso_L~kKJ{fv*ZTLLD;sZ zK~^zFWok0N!%M(oMXgmWn0r7~Dpb0vn=y(RAk5{gl%27hevLSQ5hPaGnCHbWhF|9I zR;GZt&4L|>pOAUj(s8Yuh8>z_m=$xO`*4oxq>^O|iuRqJh+x&G%7nXTxc%Y0kZ_f+ zA#X@5lA8!N0~itYUn1W}25L^i+<3w~nGuxMBWAyD%1bF}COo27VpfDiel=U1e{K5p*;uCfT><|p2Mt@@%YNtr$eBZPs zA&?UyqA^5LGzVD=oM+xIAz{SluDt-OJQJH(KRY8DXK+Of!g5_a!)E4ariv5-#%`g*J4HtL3**^j%V$- zhpI&p#0ol40Q~lB=sPhbqAhWgh_pq2l+*=W;+Tmq0fs{+^g-`zJiyoF$qlPbEl{^| zgR9G;%?FjkUu0FSEGyMN1mIv>{aMxdhQXM3P>DW#VTuLRT`1_4wvSf=I7LtGyNT$k zzAozsBBhpT>P<$q`(qK<>XL%fB&9Y>4@vBA2f*Tsk9u_=o~VKanpacL6_|4Di-u)) z+iGxP3h8T?{K~NFASgi|3A7BXfkPLnO4nzpkMmSEY=$ z=b`9eqtN%|2wOayhm~0=kU_SKd@rqxSV2f<^qWxXOaV<+EZNbZl8CZwYE*s)fgf^R z$(_H<`iU0me&jf=91%WYzcN*L8>Owa7gg!JX20~!a*IFF1PS@WfP$fZHDXi`qBohw zPS@HKVyJ5acW!!f7W&)O*RU4?qjCBA6)lNYKatPB_nRV=r$3x@SmN<^^$Qo!%{-dARs49XDNl!99YP7=0-|rDF9t#G0p(x?e{l2%%r>gp{q#pc#43%e_{Da`1Q3+Ha20Bec9vFnPhKcTkk`)*~22BgV*=DOZu4>3ohC!t<_~3D!6A(KvLIYxJ66+qB$t7r? zJK)ZhKBLGsE$!B|%=S_;Q$d@9i*ks;&jy8^O>U@s90;&q-4R!Ymm1?PoDmT6jP!7@ zWs?2Ig~+PX+xv>1-^8aM!tg5& zXkkVUpzUkHQ#HUXfY522&5E+i=4Ro-xnpVu138Nb5QtHkcLu44X$$4ZC9~*!nbhxC z1-9Yw>`v#>lXw6lMZGo{SY#sD!Y5ovEdo#qB#R+Nu&39MTk%>>j7S6ou8{VnEOV!? zlA@s2miHmbQE&|kfAutAJ^SRkF+ztYFyDj<;bu0gwp{rO?J zpz&kr{H;_0NZ+wU@OJo<1EFvwp}r9qwqSy0qW#*2D>-VZ>+}Tt;5KExuP~1A$g6|k zRM5Mu27L7$Pi}q21UXgfaWAIZso7t7ytPCxBHC~DZ;_gn!WnP0$(&>DoHlGrE^%DY zM5@$i%~$M;>YCY_(?V>t&UgSwZq$8qQ181z5ku5Zm`TLAz9p*?6LENO^QNi^t}!0v zYT0};$CMtjo7I{N%3WU!@!x`rLL|Q_uYmdX#AlJ~+PUpD3sGEBoXm-XAl=g3uvMr> zcMvdB5CJu-J;k~^zM#MNaFGUp*#bkphW7rfy9as zXh}Wpg4p#H-`+K}5<#tti1q!UtvC+|1T}!+@ne-rfDnj;%Toilr`TP?SEPtXI0%og z1cBEM^PQK+69|#8lV#dLBnUy+^x?~)LE3Hw=H=Gp@w2L?aJmL;BFaG5_yX2~9eb;N z$&kz9a)BKEA5m;Te9H{jImA6m!8)EX-H>4&s3`L#_Fb4_Y4{^RUX$p+#}|F6h&F@a zRs0+-PFU`;6~A9iw)Hc@cox&POKW>O{yeIG)&(I>8t1=36R!c~-9_`osxpqajoD5y~n;6yvBTidhOjp zGNzT){s34L1a-6_*wzyAVBQH4{!@EowqAY_x$pHBtbln;I|kflY=T0CkxB)vF3=`q zR^1;q4DwfuwG;kBK&sRLkgpU7z!Jc@?bi*PvnCy8{72uL2XKk?QzyaxQ2co%ODmKU zb#NN6cmu`eXanMC1;S!qy(whp2kwhP8488Z(cUm(xMM*k_X0g?kdr4s;HO>|^r#UU z);QsCyEP8=ecmYrJ`|KJ33*Sc^tD|+`x`ON8{$$62?*0Ipdvpvu5bFfoVw8;J0 zbF$R%$~8qF0Y5dLzU|fdX|U@I@E|@1w{0ZAn|q4 zJ{m;)?e#i}rd<I=%(5>`&7L>gGZd*#)>A z<@yXa6y+JnRNtP8IbLM)a~xG-36s1nX0H$vGVzP)+Qd@SE&hr#TC?4p$_Y?QuPAs0 zVvjuVP6TU#u!mXq@qJwM^zp&0EZwvts2(x4KRgiVY`rcfxyk%RSh6t?j8L`=Mhegy zN9P?(#+qao`+cQzXrFCm7jH8i1Oycgynaa9)b_%c&4XUS&PB)av0KOluW@f?XW{3w z)s|Zl99D*h%lF~QUC>*-W;c(z#*2vVy-wRH&pP$c_5ImD>vVsA6;g$RDzTn^1$MaW z_PFTvk)G~*e^}5P`a$b6pI@cW3_WheYkF>9Jlk}A6)%xhtcGQahHya%v<(;aV50gQ z=bfdiXl1_&Ao}Vt0aJN#o4mz^!=bccH^=~~%hVFh)oN!~I4vk#+%JphN8FfJ( z{S;)d26_`eomon?31A6sWnZUX*J9dk=Z52;)B4ooOVh7-R*wrq zTo7N+&#bA0hUU|-;F)#!Xr~~p;e^h9y`qmERSGb5MC9-4J$||SYgiiF>-dvyhv!uu zEtcL5WFK|*e=o)g8%B?2L@8Ce>zRr*o*~xrJUQwOS;22M?*b}eyQvV6vgd0HUS4XqUHrz`&5(RHS?_qLvpnMz|ZHi9PbUUKE z3jk7V=Qgt8JHf9+%9FHAh7??RZ~-<* zTcXb*y8DFGJi)m@y`xOv#kZ|@zv#U-R;1`{GR&N?j9tcBsig;Qw8p?=%j@`dP}pQ= zNjTwQJWx!L-&7k5+tM`hxURKGX3+GA8`IIwD0aDoyf`5XSFPMxFA`5hR6SgfvEE6= z_SkoOUTdDbu2MPO688$?poq3M;Fn|&(0_0O{0D|xejSG5J5T2tv0eNI&$@Hu?zhwtOH!+Eur<#W5-YO`>k) zY+cR57pWh*!i8cw*6BKD5vRsTzItI$>+JzJpxT%&me*m7r{>E$%tvk?MfauZtMY8( z*X&$QX6*jkwF|0vdvvI$+kU}dkQ`rQBc~vjDM_mLq2IK-{5r__BkJ?M$(63xYz~jN z*HwbB(u0;xUEeXK$YMXX3tWh;HTrjj560$mb=6dKmb9^ticoOOwGR6HW6|H^d{)q9 zZDMVg0jh3~ashV2F`?aO0M+@ib}VbZ=?l5ima88EbdLl1P|}t_r=>q8j3Q1#4G}8N zM#P<20COQ4xeyQ3H7#0@$v7(eNSJ~46IZNQTI!%8I9OH?^`yC+_W%X;Y2H{KC9e;M z-JMA|ld$6jEu|@NEQ*^}J?l9%3(|`vi{oEA4wi_O)I2AH_QWc>y#`wC=_NstB1ybl z=F@3|aq>nX?v=uTs^+3M=g?9-#F71Nakg>Q+79N-F-W3t}$9US)27+ zXQ#&<>qBtP-(#~j`O2cug3hERDqODVujzm%8j6rodpP|zWW+QKm%>Em*J~3s$sT1y zV0Ka5ZJraxs@xEdT+%vNX(ay=VBEX}G1Mgb@MJJWy>6?T1hh%rC&@^Rqlvr_2EH$> z{Tf9AS;a!6o7(2_MRhiOq{I}4O9 zx&VvFvk8HXLd2pxt=L4%+DvTh&(aJl@l0{a{O?jX$xo(KeMuPv%;shIQ#&KcVqLi*M9}W3M&?z zC4uzBvV+t@dufyKAgri@Rq2kN4j7>`Q#K{40_L^Ck){_e!0?u;$iimt z7Xqzxee90`t9@I|ff>XKmvWgUOqQl}sCJ#Yv#!oxGwM;4+ManqP>jQh4%f9^mCXz7 zlNyv=bPU1Ihv9(?7~NYOgBA{i)rYv%hs9<7I{QubzU3Fj*9xg^NcA&Ear5OL1%CF~ zSi zMg~{G_vi{G$dHcnip>ZZShDgD5m)EHql&@CU2dUyaLe?&!Qoly{+W?~MJJ^BL;PVk zB>eD!Y7JaD3 zdg$U=VW3kk{XLd6!7qB4-Ryq7$<6#|e72L^y$4bT=KO*(63EFqWJvaoB*EFU)ZA&p82Z zAH}%U{F$?)O(x(hs{ZXbT&prA^u%|L&mP`!Pc)?;g!im#eV1`5fb1aJYl%~Fh3dEk zzV4A2U0iU21l^TZp#EgY&Fo ztQl+Q4cxXw4Qd{p$QkH7PH^183YV(I} zT08U3S~R7ii7V}P9q&_di>wOoNIYljKOeY?S(v5i=Qv4%K_!7FqJgvKdk3gy$#pQE z!BfA#sB(0@Uu@QR(8>17LN$cQGpIX@3i?52A;g*tje|0ouVttd4=J9LTHvcozFidX zW5FfjGm6%t&^b*6*amVt4T=Z8!`!4$2R%n9C!4vZ~t_cscl!DdibUogjXOLp;|nTvxe z4~AMi02hXj6MT@Z>tV|;i|v-rsB`YIMN~U0R*tw?;W(>kQ&OWdKzWN}E4-j6E*~zU z=i0w=dY;Fg*LY9TBB~(n5-swOs##yUzl=x;S2mGOv+A&AMCtCdW!`MdBx&v3*cWf^ zno+>WeNlaNh;9(@{g5#OM5x2LL+j6DWy^o_Wwy<22|QNV)SuZ_qhDz}??+x%x-UI= zv1hT{!OV;VmoA&uRDt@{v&a_l*bhqAatafUpBk%wmn{TsLd-UF znIAc~xEiU1pe^>KD}iAl0zt>RW}V)&WK{A*iC~s;`W$2;g(hTv!g7MK&n!SHWw1wj zm-VVKs!Rphek8toZ@&L>4KJFAHXXSyfB|Nb8}G$h(`{-h_)R3*Az*SQcBl}P0}`B= zs(*%rZj4DB3mOl>;Z6}9$8Iz=1R>V~h7B4N>&KPq6=iVsT zk@|;kjU;F`^QtO{eK>~c=u75RDkrf_0a>M^J(_ zU(6hC5EOORP-AmoZ)$!fSo!J$5iLty1J8Xbx@gSwO=#=-Uoj-AVA0zd*KZBPbGzFF zsu1wIhQrF2`;#drO?Q=1t*rGBSGSL#vnI-PH^D977D59U^6=S~w6>G{O zjbH{5LPP7r;l35efDkdHGa7t!o7 zi43l888c88^!+A&3~f_e_K0?%#LCISeKfuqSZ8P;r!vm0KCQIfE5dS5F0?sZ@0)QE zB5&_lnbF~NsZlnm$le&1C-`(|L6=5eEWdS`%oreKx9?Tac-cS(n7##*`W#SvesGdtIVVc z4`8I^f?T3SaHGqsj+)Q(0-;3x4e+|>#>lZ?DN^>G#RuFK`GTX$w;sKVdtco10`6-l z@`_|HII}oeAFL!Gdp>vk4MDLkCfv+fT#$LH9pX+LyUX4`PPtf%4foJ>s>mg+Z%H5U z)00$QNT@Dpf^<%YUf)X9IFeV>6uYAnl zuqpNZAlg8Ac?suqgQX07?krE)!;O6Sram80Lr9n?X76b!bzl)U)Ers zB3=8F>$O`W(!+2w(v_c?wnWv~$Wl{~A@J>$?Zj=AZU4S*vpT2KMfz1oDQ&x$3CUIV zmajVs_`Nae4ID5{BnLS%OYGR-8j6X(61B!48#aJ4V#03hB=bI`9dj*c##|q)=thA+ z0DD=sA1(f=zELR|7qn*#C~;%-ACRtjEfpdw(LVw1wf^?hQN&63q^xZ5KWl7xoflht z2u-^}8=YmzB|xbUo==zA_Cbc$Pnz2at({cx-hV#^US~U-gDe13KzCR|p4jZHDy*`m zuJUj--76O9oK-7-SW!sR7~GH37@?tfSG=$0UP8YPgp;kXdEOv}8HktvkS|a1wjjz` z07y6tz{ZZQg>g*v6z^ygi&^=SXA^=okcra-L!$*_64hr6O@JBaXNrZFO~XivBWAm3(q|jKe`QC~XI;N3FkLYb(z-V@tUlb-svJK3b~caG0QTONq0^ka5EC%Pk2&Y% zC4dcL0nN0mOFY=NBagP?r;_EI<_o@bBaA>m_5Hk_pamP*0^d=D1>5oGcF8FM$?<`F z2Fk-&aknVoC-r6adR_1?^XiJ=3(;|8>zV-A$0O2m{w9pVJ6?0Hg_dl+tIMr_S6fIb zF2!{2#rLuK_)yFp!n1C=89{j|&qtSp+6?>Vq$C40J_WBzj67LbTdrDdSmlwOs`YrCR@j|Tpx8dc}3;2&f zaTNiB-o26J1s?w^53cze1VK)({kmW%{_`V}WNh$Dpq@b4*(@~RYSgn7d`ur_j6~De zuJ?N+@_dt}&@96%Ao-5CitaN2iQ0(>WF;ERT!_rG8aQwp-;DB4q-#oaGxL(hlzP{R z*-w#-w@*z5n=GDdW6L8o!XxX(0sh-hvmK9W`NY@nzt(~DKKE}vY_IKGr&Y>)&cN?|^5r7EjS{4TVD|cr}hjcks`E&%f??w)k@B0XOVrm)jZJS4yZ; zqvHHg;9DnC?~n86JgUES9`;?W*OX&_=e?U!vhrB%CON?eBHieWyzfO2fOXKQn|)?e+>j{EvE3 zt!%DzMKgK+OCWTJ>uDRReS;c%0rdkey3H;(KP2a)HkP7z-l4u zL~OR>?;i=ewckT)B}s4-&;ec~%O_*Fyt=gG$2}3Etr1z1{)-=YQ3rkli(jxKq3ihX z(sW;>2Hhm+OJo72Tq^IQEHnHqv8(%+KzAvx3%4W82+|kcZmD#_AJJ;>u z-RCJcA=nVxysz(9a#zLEKIo9I<&=`TQb}D^I&T6!^(k)ORvK@3bq|*a9m*Nal}xso z^tP1+*|TuPzjQ6AVm+vQ zJ-lios&+G>aXYDbC%I)Ot!+1>eJ`(jzo7S^xc{(x@ThY5xO(Kce*C0i{HTBFa&Y-- zbnSX(`*v>UZfXC1{pf!0{ORQSCFWns^~2l!^G8YlUghw9DKDu+U(Bk%=XOu-u&$L?ELQh z+|JzU(dzQS^3wj&;@;xI?!xNf>dL{&_SyE<>DK1S=Em{H`qBE@;o9!S?&k64?)mQe z!TRCV;lbs>{>A>@`QGyO^1{Z#%*ss9a8FZbQ$u@0eOvv`$fH3w z^wi?i$n?n2`N8b+?Bx99)x*{0{pJ42{^RT8 z!^^|{^Znh^-R(j&Y!^_*t=hx5O_;~+#e|vv>d3~v@s$AHcUprb|+FRT> z{u%1(*2(74&j^2pceXpZFflee+S1j0c6)kybF#R;Ffi7CbaA+Mvb%k_RZy0@vs*PZ zoc8`ce1F&VUs&cpa{&PP4FG|}5v$ST7jln%VFVG8OdylaGXpXlf=A*Bg|XNesWs&1 z_Z=`27pN-`|EE3xKsu-`9QSvch~yTpH;Jb)IqTSHot42PXA4+zR2YJr&i7c7LmX=$ zOJwzkZmZZYG)JP=8Ol-LFN(rq)^B1cJryoiinc3YIP^b)%;E`y!NL+6iAfGc+^J|PAbsthco)O?GW;*h_S7DG(>BpNzVyYTF1hn$16;9Z73#^{bMbL{mCCns+38W z&EzT;QYll*WIJeo-yfyrWbTW1z__#)9U-x17xG3FmMu_Sl*lz2IEBxbs%O~MMbplB zDrWIHTk+3f(XYx2OBKFZw-|)|27Rp+LNaC_k|*FhEZpEb zJTQ=;C@epj>x4Ce5vjbtB7f({d1} zYdP2}ql=*W#+>4_BC!XmZmJS^3N=Jt!0v=DXt2aBx|8Lmm#}qa2L;i zOdyU$Yz3;DB{Z0E1hWRU4hWB4v1X#6svo%vr@iJQ8bDw;vFnFnKBx(R=SLwLrL*cX zkan{mAr$chJIz%SPe2lirp^Q9qDiSpI18r}KJo1ZfoI|C9b#m;;e%nmK^UcNzJR7A zl+wx#5fPhd2*d$XuNSB2bNGE0QwWzY2?N1hbNdSel-6+u>}3a39f}36zYvDHBnG$#5CCX8G4KU~(z9|Nf_2>J0r1cu%hC_-Fj)c`+j0@J$b;l( z*h*)8D@Mzc%|wl7@IHVqAZ>GN)a(w7{y{q z^NgZ0Ie$0bIW1RR0Q-T{4}1wgz(~%BSxEp_`DvZl>R1eZ<`wgP zy~6tfKj{4GTLu9o6ZD%s3FbQ>;ZLg&CCKiZS~?rft@5f2`0U36url<(MaH^JybS*O zMmK}?+bQ*8iTk;9c__T7G4BclUzFmKh|j|tpT_fDcn^dD_@R(U2~WmIAOaB7KcfG*Py$g_{P+Q&zhkQh z|K!*yiEMliYrtY1@bJfaN$GkG(l8Ll=z{iRzK2$O?t4U=ND(0oVTk-5=mn?jnI^vE7{x3wf|bef z$IT7`bMJ%$w~1t^{DF5lrL4TlG~7l?-AE#bDJ*c=>4!O6>|;lq zprPbRTms~RXzWYU*vERKEV%{eYodpkD{7-`jSLY@9NCgk`?1X{ z{-4JA|M0^9zn96%+<^YCk*%(av4Jid9U~pXPcM^0MH@)0@n#*ZR+IJme~!y52dCBl zoU9tJSGj*?{@wR^-f(?xC;xhW3P53jKK~`289xpPmBh;hJXN9#^mHi1?HzmdWGhtMdYSf2^eUpE^yCq zegKq$UcxgUfVTd(I`I8;<;^je+_&0{)}F2|;O>~Msk!j`T9of&7*aC78$0MBTckA| zi-Suog){YQ(zW4x-_;cPy*pL#V|$8`(UGx%p@F%U(aGU!82G#4$Vc1vep{1IT}WqT zYiVgqW@2V#aBKA6)XLDz>Z*#lfJ`VN;W=yxe8zQASt3y6rnSo-N?%ZDob8i41Z_%8( z^dINlfvT~{6}PN;1nR$vQzikO4NQ7==17#!th1=lUwNJ7cp%VHFNOp2v3Ec5>DM~- z%QsP2AtTp*ag*%0idFX&64{nf*=eP}L34qL8NE}W&^$Micv!)+QE2sJii#4sU_gQl zC6;k^DJS8j90TTVOw$%lcYCJ#^2N!9A&|9;icTXv{S_kS_vq?^ihiM}NT3ag){d2dj zD3|%5ZjI-!f;*ZndQo(1jJOdx_&?t5DUQeX>dwDe*__qc^&^iTa2P-(wi}GQ1d0O4 zHa=e>A>C@OhEyO0mB7Z~%!DJuobRc4Y%3=MZ0p9Yj8=XBXbtn(2!;mQLn(NT`uN*i zOJB6EveUeQZU1)3Bfvzo1{N%VkOGZzx)|4AHU%P<`^K<3jIv!PZWFKj=*t_ZKpD;X zHqU5XQLO8Z%J)5$N1A$S`I$reG-b#AHir|7Fx_CptEdqVrUaQ<%br@#jaC^M&=%eS zDx!!CU^iirfS(79i(7MJL1nqhzRV%F0ZW)r72Qrw--PlkBC#~ zY81pBxe@Ln_B1a4(9Y@>mM7}V$ee>)({k#U5aKB|;7{V-73cy=NktD)!RwW+_q_aV z4xlLlRV`hBO=5NJ9eGObqgrMWXIxz|(JXj9TPg$Xu36Y6rxxlF@?TklppZM|fMVpA z(}V?LQ<6=W6HmiZhLECB%p^=%cz{3#0!(YP{FPIDyy0M+iB#txKj%YE)sHvjc(JIR z5nB_tAMXUJlO&Md#h5v}X9j~I6+B3nLi)VbV=fRaU2`gL)oqfRR6s~Qm@8o; zULpAx^)H`Q0ioi@=X74;r9f^JKA6Z4<=(0E<;Y12zO#7LZ%$gLL8aIq2PGlTHkYC! z<)zO&4-Fkg&J)7oOAKhP*fqK zjwg5}(_AdfU?dO`G9IdL)O%NRO=kCdsTX37_8$mEjTnzng;Z+A3vH^;9TU%iPdF#v z>Z2q-r}!ug;UkF5zacUzF;S5yu){ciM^bVPC^&hIJW=711_J|wx|c~(lNR0XOL2(0~xS8Wa4vDniLcwKIrF1m$euK z=DMr*b0>a@VI+L~t^V3(yzn@%((*-S&<{WNIt<1nL zWu%uMIcsQ+K|IXTJiYA%8+_-2K?b92WC5s27fOXVsqicI%P1y=1LG|$surE!&FLSs^65hlZ&c~Gp3g_L2H1U^%ZP!H$;k` zR}gOEs(5{bo@Q5OLWQ)6TNRvE`N#%k3w0%m+I0pv!29VPXX*~$bo>a`X!^;|hLnlJ zbl}0N>A50J)-DePd~j?a54Mhi;3Uh@+N55uJpN%98p4{i*t$A+FYmWK*DB+|%_X+z zD|qrSLh_S>5t9*2_96`_tM!-C25FY*UKz+JMC0nF0%91v{puK^bkB5XS<b+E_nV90B^CP^49LFb>qvU!{PdZcev*)~#bEkA; z35h&bknOESHBpjaNalRk83U9FU)YSA+^1c4CgFnr9(n&JcGIN}SDFRm+n+Lt?xT&2 zT=FC4Zr$0mu9#?bUI8s5-PGO4r$E{1nQZo?Ux45(4z=~o&6F8<+rCa0P#mjM=qamF zWlcpr)+Mz=@HJ-ujrw#$aa46KP9Zu~&L*DiYzf8ka;`;nvKbAz*>83F>fDl>IuyrC z<@ScV{*+j#s$2mFLD)M`&CBT;9>=1V9sF25uB@NfV7t>$DkQHEF*WqYrFpPj5=e*W zUL8{fofyheO6N`t+vaeGwDpPw4F;k(Yj=exP6OYdaB3CKAN=2*iB*3E8=N636Pk=3 zZ9Ety1Stn|^Fy>FnZP)OW?jUpq*?qJQoCqc#EA|x!AF^v)HqzCw%kyp)a?f?<`hHv zqpwJV9;b+^4;NZIRU!yE5g4*#9cvH4_PNDjW|y4*V6MY5(ghv$T^E<@!(9%!QIARI zR4LMs^q%JHR}3L(KTT`14^ut~h)T8~(`78RUH1`xKs6cLPCaM)*^%S6-$vn(x<;?K zXG5>_MB1xzt}|hRCiG#0uH&@#ke@C~U-VtM1Fb$6bpLVf^19av#JmN8&Rbt`B8Z%W zOTQE8^5Hv|lF-$^(kY7dZNgu3<+sHomJjFv;_SWjK7sPhH=(qtj} zEAL}4m2Rl5^tARsai5>h=VwMSskwaz8AFs`$b8)P+~3vpB`WJf7+sdac2)&xbc<^9($iCiNW#cO?_*hn@3MUg>$> z#X_XM!`0(6$+n#LQm~%QHWO_vc48thxB_mLifdE@dh+% zdcNimeX^E%GDtt8avO%uafbG3FxaA$IlM8PyQ&j7uq)A~_Ph_K87s}SF$R>o9{I8Q zi-H zKrDfXL{;X&vK@CKwyTXB^!Equ7mPl`ZQsj93{!TO10^XSzS~Ti^XD|X`SZ+nP7eT$ z(byos05SPZtCgpZeDj`zwpjeg<{s$=kQ6HG=%i-u%)J;^sPPUe%wF|XL2yKL@CC14c3k81yJQ0nG>_(oR+zy=NZG*~rRk|AtxjG~OvMhN zCvp1i{iI$amwrrV__CX(wKHU22z|~YagHBCP}@KQpG+3pePb{i3E!?MxR@@)g;ETVAjY?;_fW7!_3f4eh)tcIsWt>Ijjf*NX<*cYN}@p z;zG?X%4dx<>A(~2U}EMKB@BUn0OkOx4r_5acWd-YsD-2F$cLf&InEeiwy zFb?u}AS%sFWdQL>SF>5fbN{L;$>(w0@`x&hv_ZgO~TZMT3ksX*c6G@1B z%nNgMbL*T!pe!b12siN#Zsny{EFp&QMYfs6RSL|UOmja$Rk~}O0E#3i(;mz|=@bID zZ5P#rc;`A23^HlMur{il^=}@X#LeO(hE3YfoY-&?;#E_ROiEW{>W*eJmhhr4i@+q~ zCB&zOWQQf<5v6Aj;mY(7>gWO6rb{bY*9>h@`r5%aM_G+(Gpy)H$&k}~h{Ifd=6J{8 z-ForGZ$RhP=8ONY}7ADnCENY4IGN$a-$=GLi4kZMD% zVesQStifsnuoX$X+r}wv5(g?~3b7}J;ZT^g-FbHmp30@5{YnTslHQxT0PI#txN|ej zR&2f$-WceCgvpIX+@-l%otvb1F@JG!)9AW+X!Dp=1VVk^8vO;-|;kuFoPof+2V7pGcs1grQl?Hq-Jk@ zFCBAgNt(Ut$QcZ~NRXNxXBtKwD~Oeu#@xhf1@ZAh<~2Oq<)~&lo2#O-R1v^u6NSRE zJTRzk0A4)Fz(hTJNL>t+8x!zqc3VdtgV-N1^Vg~$;Q^|ZjDx|7?rDfa*ew5*cL?qj48Qzurj`bRs841sxsb6ch z4#0y-*TMAYv-d_wEea)-`i6dpN+>OXhiF2#Y!=`x_!7E;C-Ey01c7RTJoC3?%I@Q4 zQ34{4G|cpZLP;4l3K(_->W)My_G!&I4LT-ajmzflTheDp&Y0=xx6$J26W4vQGy*s{ zk;vAWB9_$u?N|zuK0?BGt4jwakSA^L0*#p?2Bpb`eJk$lLUa~$1Sy=4-<3_+gz>1{ zxR1DTM@)XEi^Pa;)90QH%{G(Ch@bjOoCG2I5qC@^mF#|FNwHmH*csfWOv7;T5pwZC znT)Bot0gEUjr=Tsa|23tZ)r(Kn`Oispll=RD4^B>L;v;Jp`S=OR; z64Tsbu=1K?u0R!IUN-!hA>vniAE~&TI~-#1Y!VX9fQ33`X2qfN{Nm>pau-R46^HW6 zgk@%;xkZ)PMZTtrtG$aYl55;T%B_729r&_ZEPq3&$aO=3da5wVArV)F3S)CGoE@4z zKFb0A_n^N={G5p_3lcvJ#-ViazSlqybL4Q#C&jQ~%sSjQL&f>kEYA$ZLexPv{*#ed z8`L(BjE(^d+UU&agl4;v1EQC9;UmulVqziYg$_=jK^zZ{$gsjP9&D(M&i>PrY z1~aHFEU8^BruXTVCMSf=V5r%~ov$O_K=4%4`)C!jIA4BQ9eN?z1;G-27h_+B;KdWV zE#D(G2E$Cz@67yc46Yl^llgonFrd!)8@BJTj2bc_+N>)JxGG1HVrV@^IO10fdnVWaY%`Z&^B zd{3{vZ!sAG@_gqZU8RK5ep=Q~+dq>Y;%9;KBz49)xkUF_0MkLD6u>f7Il$>CctEq& zUNBx-`^kHqp=JW*DSfb9)OMYBprQ0Z^p#$iUc&p;`&Ll(fVLH0$UH<1VSU7RJ9gfo z_yPEpUKn4>`e%CSQT!nNs%qirsBC^pL)Gj>6-|uXt=tOPc>f$YP*>w{h72y^W(TBL5dB{|g(N#!kr%Fdzht zfW|9*Q9Vv$(&;)Di9-REsm2oRT#!^ODk6zTZyc?0+yL;P^b-~-+zh>$jdW!DetY-= zGYrp)%kNMvgO-)%vWmMl84Re9rz2S&3METU7Z;~kGPwF|*Twky8&~=hoj^id`NB9{yevAxo9Fyx-|0OH)Av8tiv#?BU|;2b z+V@}T@lmnTQ2hchA>S|M@(3cG0d_bd2z^CFbRg)weJ)sy^KK?us5M9Zz#bHi;Q`?p zboCOW-@!i5BadJPVab6&hJ`L9K=erFPw@lMun~hR{V8ReW2^9Mf6`7Hv}S#&Br9h} z1)|31I}%Zf{i;OD8o#6wiU&~efH>CP5k0ty8|E^Vo{omTk#nAlk+8%U&Kk=`!x221ap|h!qq4|HLKdRd5*ncU>lpwM| z0?^9FWW7eRT_!Z@Ww5+MDps9?`1NvI@-e`Wq{+cakXinN2>ABoMp50f1o$tCl#Hdc;=WP(B0HbhFNqvW_4~=_9Bf8#v5hawQ_lpWT9Lp*Dx`KxZhYG z_GJCDgDl6EjOa+AwZ*8Ud)|=T(lMD*$+IU?aIdmYS=cXYAZ4GgrCJ0x3*t^*iF*M2 zsj*mGpkb14eU>onf1Ol>hI+~hLm2wkDnBY35X9eT6q>_Yt8cqN7dK(Yknz5{vv!7R zC(a}&lSD`xLBf!K6l&K%4GM=5poysLByaZ!zp1-SRXW9EZXD?iK!}019{_qXA%^HRKF>I%#NuC2^9`DhO{sq#O-&7 zu+Jh7W0yNb zg?_+S%oU>R2@PmWGLZsz4J)+uF<28Pu8CDzvYyQ?G{pE>xQSaq9V=+MM{)@_fRYHOYEJ9qVcj zST#(x_VR_SJHyA%;AwVrL!G`&R@% zbsZod@R<`tppO+PU}v!OZ}Ek5sGK|c)(_<@r@}lY&J_XARy|GoQXgFQ@$qw*_9$z6 zo1imx{oT(V2DiwGC5X3FB!l=nd}Q4#s&Fe?S}%6=gy z3nD$=SP$GUrICEHnDSHz*qr;05?gdkzl*Rc1wg3!9|9Dhls-Zqna5I6(`vwi&JKAf15uT^Tpk^2aF*^fil z!1er9#V;=(v-k_f`>vqBYic`P%Y1c`G{!!*ULgL#H;CG!-+kMGjkjo!`RIw$Sh7r_ znzG$KkvPpjth<;bv~itRm66w4b8N_Xa#4LgzjI1TtMZ^lmg==rM=~&*W%NtN_es~R zXO-mLa{acJNlN?+{4c1<2XdYM-DY8@JBO|#!4T@ z!;8!aG{yIa?!F=~<;5t&n#atl2p;H|Xc<##g7mE)>3RT1yrh%gGb}Vcq^YD4Az+GP zyhRB}nHtgnlN$M+v7x!q)75Y4JMj?0sWmDY5v}gVwQF$|4Ke;8_vk87~ffX5)$YX{sBga2sE-n*n$dD)bq(`P?nTk zkf{E)^|mc!YqcGg(Brtb!$aHwZ~4qm!HyA2? zo%4hY_Jg>}~vNLC@0@e|fMxzt!ygo=?h)^3$V%?EmDAg>}(U1~8fDlZ$R@i#5oFRT&| z+_DmqYCdt?`c12#ca4oyYQavF4t}Un)Ej}SBot%KJGL5T23Ja~I1+?N#zb|y%O_h| zJK}m)lQVMKFEe{n&NxN)OVhaPT2nzA#vdKkLxEI5G^G9I7mYV?ZED&dZ|6(MMiafyH|mnh-Z zxNzni%}KA0-THPg8hZLMY`cb7AGU#LyGsRea;-dfEBpk<6NQCnRqq*RQv&isE-o%z zt)@HbMtXjg2G&k)@|Yajy-hcYi&0K5)Vc$eE`Nb&yXDUmkar$sMpEq%&?7+!uMJskxIjCQ4mi`Tn_3$<%9Et-*3*cE9lHla^oZXaIKUWA zhOsTGd6J;^yAT=L+({}07Zd3|HAd;^}TQT5O2!X z>4B{FlJ;X-9SAwt2_Sm1B>7$%vWFiW#i*IXn7{Sl%;3D)Xz#J64~n3!r3cK9nKO?P z++1E;b9ad75UcAr9hQ=QPN+wwEINqxfwzux8d@L=1j6;XPUezJm-b(HD|V{ zSC|DNsI`;o20<3cUE%WhN!I^egFA4_Z@2PX=tr+R3qwS6FYv`Tbp!Xw#Ye*lq$j-d z_7809(x(%e--L`bh~8myPLl+uQPZ3;$J4T&d?&KgoH^rJJ>)a)qtD`{aV2R5nwc4b zwjoRr_c66BEgh34KRi|-oBVs+%x#Y@r2IMd1X@B3n(wNjVqNci`1xJiM_mDEIYwLX zzPvaS-#knoh^NnT`U$2DA=o9lf{9-c#c!Ec^c^B&vwDp)2l;XEznx$tpf?ElTXG5$ z_6@!GhskBch|iytb@sI*?%lHNc^5qbU1^j@0JZW%?9i4KI!$1Gqv@rV6mn}rWX3h_ z7iUvkq_MuB)EC;TOI%q&@e20zdc8f+^tVIyp7FY4GMHCUZp4@qONDR2IweEvSFdH` zB+R+cTQ&e zYx)|1^wMHP;tS5-gUbWIc#reae%H-3V|u#f+C^Q?O%{-bN;9;1Cr?H&z6)5$aXIL;R{{H-dJoG&3X=);PCJ zp*K$;eD`I=Va}Vq$6-`3B7Uq-gSh%56rR7Bl_O#qadd7ZDthlBL!0zHa$=1~42`)e zH`RO%{1wKHpheTpL#I`9Vzb|^xJ>74KJ?=abiJ9kca?Fc>)#&dj=H=QR#AIAT4@vG zM5LUw$}!Xqlv+uDX`ZhBkq7m+k(F1-;lXL(|s6>6RC@BZcxyFR;jyFM5 z_RXlS)cs{*P(`3tWeDBPb;y`0#BzuKXwz94n8s@Tkq4%KD-Ztr62Lz^Cg|#7FK%jQ z>h#BN(x#sOsuWbTm9!DoN$(ccuoa~W5qU{=xl-iUKnH#qyJBZDVMK3#TH+Fw3i_I!Okx&thDB=-L7 z%?fX^=RWj(S4avRuD(mcRpHg1&@!NBYkC%F8&A=yDyz9?QqZnX7SJ&;lE)h*=2rL; z)V1`cw+Ny;lh|lnwPC}`t^u9C-;8^VzXKj|&Ou2A9W3u%Bb|Y5ba9nj&agtLia}^? zY@lh{q_{2%_p5Y+7_Or5FEe5pHQpbR5(O31lXRCe@G#d^#VzC2C)gNiGQJJppY7b| z@)9ISo=ybWlh#uuMI0y%UU87y(V25xDme1feATYkA+MjyS2y&HS9RL@9eJ)xj*xnp z@Wx+C8d8@&A4ein!u%Z?Vh9nbEnyVo11{wb<=08-!0qd$##F>GuZ>2NiOSKiZOW$k z$kz10YKYwrwW-BfUK(#=x2kV=U>6{brcNq1i&_KQ=x)8T6OC1 zIk?!d38a-Iz2bXnE}*iPi&MNx&hi{B4*2jCQm(!3K|lx^r{bpHmE`m#MKNt46h{}Q zri01!8HSDQ+#N;>)^Dh;+mPEK)N@h%xNp0*O6dF27y}$&jDxBH6@Zz$F;O;0Hp0ig29tDm{9}l%zc{dukj&L4AW|67_*y)0?Hhqtw*dHw9(~z+ zW7j4{x%B%oY>z>;LVtzSx0$!TT|eN@9asNiSgyAchcI8!kWPK!qQ>uqy&7suXHd*> z!dpKUmY`>x**(ii{Xk>hy#OT}_|(6d2IwxR^&1#;yCOeunsGdinLguf2Lm zOLGk2T@>;NoD7hXRq#Nsooom#EEkASb!s0@fDQa;Z%gvQekD=-G1~sppRuN^44kxm zBs|Y0l0DA!?Q=yc*1#E{`-1t3?(qUsW*j~&33S6r`35wwN@l9hG{$y)Sb>~a)Sg%b zVKY@oosMz-{g2bgWh~t(CBOgxQ{ewM=>3mM)&Ji9@f&u3H733#GYg%zfNd#flZD|E zNd!ItM3XG2NE84d=QnGzR6A5JM1RBbptBP=_5t50glTfy=0@ec7`eHB%&>=U;q&+S zg4c$s0i*WIRVFBiO1?;n9SxLCnpl8wHSP@t;bxJHKMhI(?5Bu>c!{Q-pDb#`t#@NYo4^i<2fZ;TQF#lLvT6GUtjqzQ7KFb7@R>nE>n4q} z7m&nj%8Lj~YMh;=B16ax9M>&0l#C;|b*!9P<}g?n`qF|+X=EX0vq|qwlg{jGU^!EW zwr`)k6I6n=2BTh`vrl*68IraAY_6H1;Slc+Z<$Mrq$Q-OupnwzTG#@3uAL@+4?HZt zBT_@m{(x^tjeB2G9sV*EJC3J*ya4eCtCF;rJ1D2bot(-s(=q z2W8`wT<$HdAq?xPhwW2t0ETz{`dJIRihL*4xxB8=_{^C?Q(JXBZAw!Q3k7IrKnYG~ zY>MO4dls(Tg8!p$O0qG>TX!!ivsSBg7^I~miraIKwNl>LR>#bi(YhnZ6(8PdnXIC? zwwb;`YtkyE-pzTrfT#Es`mgA4J*^=h{=*dLf7=~r`}^n+wRLdu{HshX?quj-@n2F( z-M>;wKe?Xx;s}AAN1fyoo>2|X96IYP5CqHi1u|ui7 z_k$-TFkQsxvu?#X`OF(6trA?U+}n>Y-aq-Sy?-b4e7|18103Jz!r%fO+qRf+wZ*ql zIs3QJ_*#N_uBfOHGL%SVd-)A0Ez@q_CD&;CXSP5wx?)Maa0n-P4Pi8Hu_Type;%ORsAVLoR0O z7?GH2LlrVr5m)}wYp}%xSt(M*Lq5?>Px2g5s@~SCBfG^P$}XzB^m0j=JXxH~SEWnU zJmfwMIEv;r6_-HNpfeWrrDkU$WUb&U%YH{N|{U* zw%gik;2dWTR6|!-mBnIUppGxM>jEPTG{7Ca*~=idO4v+KOFB?E5Cl4Hm!U|}NLj>J z=*Skr3`ESW#YjpjWvSbwJji zcmoQn6?RK|-FK;^_ZNhJ$b7w0wr56-gqcj}SDJq$TvtZ>!YkiqUl+y|+vA~{E^v;q zTrWgndvTavb$-~}>7`&-hIU*tQNH6OGM+wP)u_NJ2|BEgKYaz}r0N*ZNIKJ~+KNPg z@2i0Ldn~vecN+&DqQ}I2c(kpmG+S^DERR2FE&Cu1N=-^p)xMVQn}PMnt6MZN=jAcp zv1zv(56JxY{;Fdv^1>||7B?>u%Uq7-TtlHdc)Pr-buvt6;8rK2#zcB>n5c$MFf=Gfw-iluN4>=5Jvi@>f$Q zRGkiG``T+&ie-FAe=_(RTNO|TgwThn2zSZt@(*gb?|M z_t?95Gr7*8cc3(tH(Dj28b^<;fkStkj-1~=)BFPAzbbuoVSALYF(wKVkogUNuIJe8 zfKf7YWw)eW4swl7E~i1m9{EnOER5BhO^(2t$uTFS>lD}uxP9V?dB)DXI`9s8YE5|% zi9F#TvI}1k>JU5=F}4mKLsj3U^-`cQgoI**&M#A?_N=@*qSUXIi)j5fz%1 zG2?4-C?ti`oMesEHtv_mR9IP4*0ZL5LF?9NWWj>)_ezkG>lL&{|5jm|kR2ESr~-&t z1&cX7hQwaV_sy7!-#&1zy>dpFDLBv%V(b1y{|hZ|N9#!cI!9Cj^>=7V`#os*+Fn4N5qGu<^0J|Vp=RxL(N<@fABE{>HizaEP6o%J1({Q1ooed zN}WXE{D)CL>H0Y3j8F5!z43Hpkj*xz;;z9z70hrEpGXYzvcxh49I*J{v!dHn(sx?O zFKlucs){_xjY(zF5%t)lg=$Dc6-k=-;)&LtJLn)L@bCNDy|d}R@MxB*wKB3gh94Yy;FyvK2-GrKgoQ+GRf`sc5+ph)9g0lv>B!U(LUPEK zi#xH*w?g-WF!#dQ?DV3&&q>VL1E+KtBHLLiGiS@Q)9+_b`uFP}KR$sCu;`6W5L!*! z-rIFISKv+NYObW@&-})gfEzB(BT!dTG#64p8*qeEdS9|%=Xn-=PrE8d1-9=i!WHqr zxH#{ctd<^u{G|&w%uKbtx-Yr3E2M#l$Y(oFxcm&b`kFP%#_Tdbf_jItST*aXdLKcQ z#2R@^aG;Y(efg2A4+ff zGcQ;BIt9#~oV0VT=V-?`xEwVH%ukR{m~F(XSDqr~sZ)obw%cu5(R5i)8D^p;sts12 zK*=^%9pSXQc~p`G3z?b6+^qNxrbQtlt!8JX3roLH`q2)RZIi@zsvdmH2%|y#Z?+j* z2pBRxM3{whBYXsMOAhF`Nr8~S3{(laeJsYx_nwSf$Bt)?^`~pt()Jn|%66%`B?yAc zFy?uFRQ|xSt3Ytqrecsvs5ZpNA$I_OHfp85*-7|V_>Eg>o4b4;OGPM< z`G=0*T!VlSjXF*m(SaRJ7$l@`v!nx9c%T$pE;VEk;HNIjgU&RbOg&3oI06fF8F88V zcBz%wv>qhrLI2dG8LAz1$aa6qUDEWVnir`b3Nx*o_4C3(3;m3ssX{bigCg52+s=c1 z{TY(X>?pHSM#UJylf)x$-$r@ib>&~qbQD!SX^z!B%)vZl1?bLzq~%74#b6^sBz~59 z>*p}agdVq#4-Gx!{h3Ta@mG^F-f+|!gMLrw3H1-Uu) zwEj!cWgkeMF`H|4fS;OUvw_(`m4%IcI>lqY4XS#pY~|#e*96;w0g$-0Uz6Lgmmoyt zTTRqS?gc*b!%fVCM=7-li_qt?(t%3pg*uWo=y+@^uT}Y!pYd+_%EQAul*wHfR+wA| z7S_r=i=Z?#O|)=pM;BclS*ikKU(dfa!7EsMP6-cx2ek&(lt4Gh#` z&k`9JC|Tir6Y99lH~e47AuNYCvHd4e%m3R0Wz7F}Ywln1Lmko`c?I<=8{OmpFw(}D z;HM@KV|)|?3F#^d5F1>6Ghs3#p(UlUrOm`>{A?rx39XAH`ucpKww7|bOVmPgvp{W> zuuv{^<7sz`q;zt2_7}8V4?AZr; z1Kew9lO8W)E-7mdUi3R`lm7GdLK7SnZ@oZ%{c-^E(5g6K#wRW~K0+P}^ zm2HZVq)=!^b2bn($_(iD2$%}V`){-A7@o;QwC20+H6)}*wNL0?!sz)O+|GZ&AcOYb z=H`*Xo;e`DaDn<&mhAaW)xzqlwyb%8DhqMC7uAC0h&BLTAGWg4WX7_KV2AQtD`Ig91?ePy*F@VnasXkZjjNbNNEbZ z>trJy0nL3!lR#aOi^>g(B4x|&ar`?`P`k2hf?c%P_2~hQDP+=`x6}X~2G8>QnjfPl1ZSHuI1@gz~$mYxP9rF1){TI zLYlakS|C_o8Tc(8U$099i}H8=is|)iCl><&L6AV8q{ZKPnB|ovwsED)WpIoz6KYhr4zmdcY2g?@C!tMLdKxNyV?#70zU<-{|_p=rwdApTrC$XhCn7`EMGYQbkw} z6nBc;1A{IhO=Vh+O+~MmOKO<%GJ|f7K)v?N2;SwQqfn$07dXrGK`eJL`b(nIL07u5 zb#X$kVsR}71)w_yGsn?vu+?)vQe+$qPk0OkSKufWcQ=Ws>Z&`yt{m#_OIB=Fb_a?n zkE^^OgYpl}oQPsE8^C4dbwc*TaiH6w$sAx-9u3pqNTchSYNsn%;+l#~PL5KU_Vg3! z(F^uAMq_bpW~m5A#%xQ#_GDEPVlBNbm8vo@VQs#2nS2hgsNFYbITp}nhX*%ke3NK? z+Z-FCQ4dUyVznmnof93g`?r;8gu!T$v8y+4pXyC<%0$mPr)CN!SZdNOu(X-bO$VSYPHvR6QJ4IV)a@yI z3A-s-y%(-|%mihgRya&UI)q93_$n2iJdY4W@R7g89StVG?_7GT*FWrNv-jRXek*{u zF0N=gw@$NeH}A7D#~9G2x6SGjX*fdxce^2sru}Tnv)Omqhi!4E*Ov#3d_oFO>0KQc zgFlQIZ~vHZLf=nub=3)U?H}TZW0xwhm!znYZuF>9Ccjfk>y0}i{xY=al$nE0 zVih-g_|4JB1SF!NR(e>{r#|(qgQsbsyG7RbJMyEu&)IAJ`Ks(%e*79wQf^`R_BGy_ zWoLk+ucy@Zg}FHH`dFKp*b>^R4)y#NfUR!odZ%+c1R%5pye_39v^I2JFo;9*xd1!R zC&G|F+ChuYU)(WX_$DFqXLdk1eLlKA(J{ocxuiE5u#G_=N6bL$pldutwbC0IQmZKJ zw;)nW9yB^kUF5zpFdlp0t{zvqU2|Yw*aN*n3qi8nS&sZBIp(YU{sc^F#o|3`0-4Ei zUBR0Dh&E-E!;z2NAa5M1V^Lbz#u0@NoBB&*fy1ogOPbDZ32yLbbU(FIaE?357uTf~ zq&=y7+`-e^u!9+u{TA6Hk*OX7D@|>y4Xo2M?7BSOhpf4-xwC7Rh%P<)>?5uAN=ue2 zZ$ia6nCliz?m2gJ^)XYs+(tXwyIuZ4z{~&Bi zH*ZNvQUfcEQLl9+MGbO4zov+N9Zh%N-V@pRwD#)HmNcU8>40WVU|Z&HdtqtLw=13M zYdh|@tI%mSt`uWp#c(CYil0$_CcvCA(9P8w2XR>iNdk1gMVPJoiY74ZpLK_&_g@@C zTfVUDB6s&Fl3U(~Z|@ap63=VI6$w|iqw-~{eR*^nOT5DwEq2cf{=eOM-{ z_#9=+?D0WjV4GZ7i82-x$02NgGWdOHI&f?eC#`~w3rN4dv!}q7k^VI3ybOUh6o6+! zaw2$->3HX-{$FxVopD~&4iW%h0QK+W9OJ)PEBG&mMAwwC#Zh=+f&4M(`yfI&7^BDX zL7Cy!CXs9qb^!W0z$TgljAIJHU`Z`i()(gRB)bXd{UpjeQ6xz{XT*z~+UJ1gB}5Cc zT%WVNXLxI>DHK;eQ(}kF8RQ1?9rD_JILs_kihiA4swG0u;+h<< zAL(`oe9_slvKFsuKWtYDtJTMP0Z?DMvIfTAdjlwDKpt!qIH;^+Vu-Mp=o>!->5nUP zvO=qz|6ioNW0+;@k}aHerES};v~AnAjY`|rO53(=+nJSiRhoD2eZJ>*_wCdBboaM@ ztv_@AiI@@NeaDCqHJ-SU85UamyX+2-zfEjAo8<^Enw-)Z>%xo0khZEdj(i3KVAM;A zEtGPx`gE(n?rb-?n;_Qvs8_(?Ds|}J)5ns!TvV?<5NhXDpf1*+4gh^FmFvLMR^=?F zbl|Sk4@H=5aW`P}OsE~YSGgv3IeeVZ>#otlBwbm0!}M1(!Hf~I%b!)18buEu(Bo=7 z2e@TDt2WA!S0t|sFfGP4HrZt{c05c52jr0GytA(&2UY3^ZBP`xJ_!F=mRGV8Aqt$XNJevCvCU5BylL^lgoz1h~0r&EOtgZ%8ArG&j@Em!>d zsdrX8yt4<(r;oREs(naqF4maDvI^n*nsbV`M1iWAT2*2fcP0&N>vsf9;w$wMEy`hq^MXZh!EM$U9!*l6xeIg769CpX{i0n}CV3Wn%6|zH4m0v!kyEyi^Ym4XnF@0911Ud>OdC*3$Bu zTsi7uPA%Woa5BS67!O!c2mQ3~8zhk2O3iR#=rTkpEwHGW98Aho_ja?{pk3tBd0~8P zgY9vdFvnR(!k{vIk7yPNNh`D9iCj@#ibF_`f7Qj4OtmI6Fo^4khuY3#NeI=Wwb>A^ zgg-#)S9!3I0wPg36b@VnG( z1Y_MuH?en<_jkaH<N1&W z#(M%mL5HPVsL48PzX8@^Sl2Vy7rSqDwk!@p5c-6XD$Fs$!(uowmUY?ueIMMPmLKAB zfm-VI#3OF0nJkMASv&UD{CJPDNj6y$lquM`j+e5X#dDSviCDkNc@$PEp&L`3t6z0z zs@d1m+{MAX;;1i!(*7DGm4P_{eQI(dr|7~uIaT`=mfMUtTgS|^Sv}U7 zA#sye9mWFPZ_YA?;#c_rF2B3I^O(V zLCsPfM-|hL9!zL(P7Ovyi>|slGuV{cwOl}3`UgyK0d0OvwOgXjfJ0(Nc81~npIRMh z{?qTe@Lo$dpOkU4-I^NA`vy+r?io+MJ14sPx&HoNuzi?LicQd4Go7Z3Gbz)&8NX?? z7m`Z!9j5!JUymbcJ3F0boF^?e5lZOvYcz)`i9tA8t97k+?~7Zt69d|>)RRNE5M-pP zu2raOFrajPdT&yj7M*O?H1hG25Tb*5Db*Z8rlOcsEyP|5Jdl9BvYS`+Y0cP9`qU9~ zj1P}X2PC*~jtcLGy>#7wSXzEh0y$w%GwE*uSw)d(QK**2RlZz4PN@`+ZWStv!WRy= zE7@{dFS#J5nfq?a?dG7L#|s#P5>c`f9GQy+2JLQhfd{$4ZVPt@qc5@*=i8w=DQY!4 zl49M=a{C>fJ^Xy9(-{q>-NL}Q6R32NouC!R5Y(|sV+~Sx*BC~gplDKy!#GDWr)n46 zT1y!epB^)WVjhkAfWa(e#o|0Z;ce7 z%B~Dy#^{~iAP!Jn=W5D7@X?x(3zv60L^>{f?kL8YHnlVWjsgi)El>87u}$c@S1o== zsEm+-lh%kmsP7YL+`wNxAGVwDLdRCY_GG&K)`QkIq;T5O?4KAywy`H-62}N1wy*n* zXOl{9gfUi?4MIbF+~fBf35T^dptJNMsJBh4(|-?4?mD4Be@g;EQ#4fCi~g%vt+eo8*6O0U$( z_?EbjtG7K^gH|Z(?|c_3DijRX#Vx?)FXut3$R2V?$7q%FN+_6-fn^ZGG&S`|{z3~j z7?wApL$t0ZQ)?YDLi@E%(G_*eTJtAx7-t~g-BaevCD^mWVQ=gFVqwrTl<4N{Yw80& z-nfMgUGO(}KfA>#3fnb0x_PzK%}sxzU|=&y+$HPYF%45GCznLmFr}(0B*5wN9$>Y- z<(rK66(2XpHJ)V(!`Mi<=rBRIu7P8z*OY>uDBEVaLJc#ND53A=Nhmk6C;=S4m7MDF zsx>d4axFP(i#z~BK)k;}J_azq3tedZL+DxdeA`0y2XdJDTjcOBhT8s7i2jpW5XThL zj}MAAxVWj{L=k}uITaeM08=`Xcl2?m$(S<}oZ z9>&h&my1si0|j9O=s4-_nWy}$_w&zhq9a{wmc7iZdCLM1p5W5Vh zCWy2Wo3b#N+Ele#t`_<>FmU$OV+F=x0EYO}{IUqn5;KPx#~cT}Jbv_9Xb~knMX~uf zY4VxF0Y)%#*>p@a%t_7~pDyKTX@2Vyn)_#?5gJCjtoh$tZPCG|6sK1r6pJoK4WxrL z*;6A2=7yr}Z-59&F|g3=JV``h5>exRCK63x8aMQ#OaPC&NmfPX1WCQ@1G9!jc37m| z1|2iKt-B;)<_^P{*4P3RoXleXOo0}>6`evd(-yNM_)Toz00jgec}A)G;!x>x)%2Vlte3i?2$6uc;Bts!HauO!nX!)bU+R zK&>~snfY{PTO2s>V$Cu&f9XWa9~GWDnMDL`RUA_MXSe!g)gA*=S}&9O5Bm-cdWfOg1~|WE{`@WO0ARzEjpAE7*iyf5ZKTujYVw!D|A zs3TkW{^h}!DB#$Gp-l{hfe{eSGde_o{f7QEYdM`(?hP}j!|>Z=W!@v}k+VjXgq>AW zXL(cLKwjsgyVyiQ-_JwDBadv#=!Tf*?lSmRMt%RnqnC(B-X&Lvq9pgwYV)hCr&~Cq zQ)|!!Z+R}yjbkjH`5hRKr~G1qiT=FfT5;6}L6>8^VPRP6P+R9D*tM#;=U8vw^Z{*eHfr-W;ym{r5%nrr>2ZO(8A}c9^qc)xR&dtL;Whv zF*do7*WfjJDhWVQwZw)A!bXp|BDF5RMMmjAD#Z{D6!**@a3$eyxvGCLMkeZEYV7Lr zA4^4yn)N^QVhp53Q382+P#{jyC-AbUKRPANx*%A`sSBFKRrlF^^}-a8y*uz$HpXt*(=U z+*oWh-=G_y`!h?-PH!XD63s3;4k{cv0B=yO-!UeT+y19i1IkexB2=k3+-i7MEH}v_ zTz-5q$h^nzIqHI-@gkROB1_a)@RnlpB((&s{kBMjS*(y~zKabrBH`=D`y!c)Q0w*T zX*JT7jBiDy-!{j%LAWQ~q-!!3DPjtoJlAQ{uYU-57n$qj8Lvr=BW~2o3uAgGhib;J zO1}g*okWYwL`_Q}qXn%w+@Nr8RY|_pqZ_hOf%)D{OSD3pl#=jjL)vnK>CGbwr3qkM zrLg2=psdNVTr{dS)LN~DY$v;(n+_&GD29l7?@+>kDX&-%4gcT`9|0FCq>42v#`!H9D@!d_@!zAQLfS6J315}N;a3%7OzLs_be z4$%*6f*zUP317j%H|i(3^VrgkTOvEi+xgH`yQSq@COF_264q1XD6mqky`^K-azbVT zk;LbXU|FsjDJ3fj66G0#5*c*P2BM(#U+2Kk#vX(=w*+>vC#++EY*J`O8Yf7D=Jnt}0WzgYyI={pj zWY^*ueb=#P!kHC7rO|?Wj5jZ28Q=!%wBCv%rP)|x*tzq9o7pVorliNV9Mfd};p(iW zIiN_sF|*l$0{Of-qWhzh9qi>0?VuY4-2N!ys=AB5jXKkDR;n|L zORCtF19;CRz4Lod^v9H9AK3FNFhPab_3@vg5*K?l;+kmcFEu~av6L>q&p-_o>M%g@ z4CjyXoP3JRRp#vNAS@Y9iZH*#HiM+;~Q0IO}6` zEAAR2{rP;%@%Z%*cU9l(h}A8u9W)ykDlqQ+{NB1Az-}U#(LwdrYY~$KufxJe8QV#w zd{8kQVkl+fQATC)zaVOi!IeFJSiVQ%+&Ay-yCa?3?^nd>hkt99`7XEv?-S^aAA5eK z-19InY`#V1;)%pY_4{LlnIbFo1=eT1YN~#O*}N>tR`D28M(?{{c&(3i?{mwm(O2G~ zBrQ)%Xf1(YROl$+;L{j4E(8TlYM?OKc%K{J)SJ~OEIIQn372?}zH`_NiXO5`eEy%K=ZmwlD(a`5WEQKhjiIs|FcIuMG_jVJ2^AeGXo#JJ<~>=v zrT+9vS6WM6n|;}3C`ZplGkB%xE{q)`Z0> z2yqnOQ9x*t#J_Ex#>9-bZBrx-#Yad7l!@+9CC)p;=WsUkI&d}**4HJO^I?%MO*gL)lp(%Bj381 zp)ACSYE%>bK$}MNkQ`*D#n8ZJWBH{*gqQRJOp@y4V0vgWOvr)TDHg|TrS(9hdIL&S zji2BqJE9eokFhV)zg^WIhYp-;nR0GoS=BV0=oZqT+Ha*KEKJ?+_Kh2{$UjzS4}Mc6 zsISDLSxHVEcjE)fxD*3vL>&}Bx)*3$g1bcP8GnQAmY>3S1U4+p4%T5M@S3YC+(;a0 z)8u`pwJoer4XJvI|4q71ML@c9u{4@>pB6BzzWbxEX76{UjO2J4ebV-nO7Zk9SlF_S z@)q73%DUg?*k;l2dO3b(N67)R`R_7KJ%vo1N=Z(`qX{{>IY)^>L)?AI81990sguje z(O+VAD*Jj8!m*3AKj}Cl?HD@1gl6%I_A%L0S8FI2<(<4)y8`K84!E%kI3+VB#Od1Te6F6=IloanjZGw#-OXT{H~Idj?HJTb>H{_QBwDpFm})n;ej?<~6K! z1?F4fy*dH~RggJc3_Q4KHNiz6HzrkJa9ZrDTFg4qjrLES^LCqJM&|y;rl+LkGjiO> zK}cIGq%Cmd*%6X=u%Z9cHVBN>hek zXKZLE?fUISfl%5LoqZ_fFpSGSnqc272UR_Hm%!Yt>;QF*iJvI9LL8vkuzE-5xu>(+eng9 zJT_v$QxW5Eg~hkCg&hm3_6i6u;h@mrrMe?4jq%5pQ0_MAeRS{*mc;R6Q;OOyE_Vcb zN_{c84)va1e(kYQ)7G=CM(68EHMGf+0lRU1oEVKsc@%NISnR#Su&3PLatbp^+uNSM zuuqhUj+bX{QgB`8=%4Sy2#i(NSYp`XaCg&Qx`#9kA$itD$_Uj#oVj*1!XD0B;n@ue zvm{THr`baN2TSxPB{Ol2FRJ!NoEW){WA@k(PQZH=Sv+VI(Sqbr%t3P}2arO0U%~Qw z^W=@)ixYvYfi_Nib3Hf4#KV%DU72R4%XjoB%wZ<4Xi-DX_pj`vT0Oib~$BKXm3E z%f}^5DEKMHRnddIepR!-LHiiI(Y*)9?9-+#~z4A*zwJcW%sa2XZ4YL4dCSC z9W}OLA87eZyE=9SC%|ZJaR|2z7MGb<*gY^-}}ANT0l-0f3SHzu^K2IK5>`M)7>-gPUJ} zoZ#MpKPeA0wvAHUzFiJyXEfe;&WujY>hJmko#v?uN8Iu(IOYv-KGO>SK2s@SW(394 za5M@e!MbqvOh0d{jJ}FU!sZ#6q!GV_Cixy&XJS$@RL7uP=<@4s8aQAF8U4}Ks7k^{ zA5Od>@SQ~HAw?>An=Co2ny-Iz6;x9ki^FG$NnYc!LZpXaIA6w_7*}e*NnQLe$#h%} zfLAqi?o6+A6mOs_;V}o7($H1PW1cp=H@+*D*m4ShIxbhK51GGz$gbAj+si4=JD~Fp zxzWSLa)Jv*!xwDM+z^~sRuExPQR2;aZJZ|Ckzpiyr> z`L5SX=r!a`sW%+-9+N~-y~+${aOtksb|8-WY+&^|F8Cc&*YWbr*`9+H(hh*9?mZ)k1#CjBvlrT%`{Cqvu0RLdFGWx+L9NXKXYYA z8E9?_7zl{tZza=I{|(9XzsVgFHsv<|98eoa!h#&gZ$g|YqXt9MSEEKl1|tes&=Y`K zwKfNfLbm_ux^Z$YOY;y2xtCuNn^S}<0ycor$$j|s<>q$$c$13*#JxsIEW8FKGrH(E z`qtlbrRO*Vu*G6fOIxXIjyVeLpd}W6zRkWBC^iyWcPdit98Xv#=i%ogorBI-VabnC z#pF=!9QC~CCr0f#RT%XSzC2b-im%K-=N>Z}2nli=FwqTruU@_TZbjKU9emaS{S$<2 zRf0$2_<+V1`sRYcW1ik{%jrEuTWgq{*k=pZ5J&1U=tniL0ot`48y@1ZPSgG`X4+n4H#q-1~LuFQ)+7J%z#T$@19qj z;@ol*r4^yfY%xu>R))UhA!rAPM$q4YGM0#rjt^M->n*v=91M9fvZ)7EP$4HT3V$lP znqR2acTCor8Z;ytG#av+*5&3Of5FaI`jzm)Kj)PHmieIk`^f)kWAbnJ2a11&(^V{8d2XO$Zjm9;k2^ZFP75WOhJnavWDXQ(Pw-=FrE2Tbf5vh#^F?@pFs-H`& z5B8)(A$zsWus{<(A=p7VB{6&?jcr0ou#EatKu@3}PKH-4nnEJFS>6a9kladv|K)K! z&<|%=Q%?M1iRostfSl7qs*>s02N7ud%x8r@6|xYVbG-PQ6^cbGlVx3XUTtXAXksm9ri``JHF*d$wRvO9l3?(5*^0o+LRbR%I|#4wbqX`L5H4^LDKlriJo$9 zuR72up_JiYkF#~5#8O>pFR6p5Fh0k<2j@3%#bKUOoptu+1!MtxzcU#B=bwfKt}NUK|prAvm#EMxM5=MCO7lF@gJ50 z>~+cFk#+d#fZ9#oFTm#GVF4ZW-`<#lprwLS6q4Z<2X#x^C zow$~(Hm;`az+|B>2p)=*D~eXB(5lilpE(n!$e8VgLMNV(mua);*ph4*ZxNGTa2SYT zLB25G#nT2Zn`-A|@L4EyQ9vTQ5<-7;=Su1x$0yqndcMJWj*~czIkD!#1OY^D@;0G? z^^-=3b|oD`uoDv6)Wi>dpP8)S`kgdOTNn92cf(i3K1eP=#jm$X9FB82Lrt#IL-2w~ zTBpR{O2v%iX$QlSv@i$K~-^_+wfY&n=S25yu)NN&_-t1AG; zr|L&!7d_VHp?n^LZ+Hi*Jm`rd%OZ`>{}_I;JDbw~BYu&8OI_3ax2^^M=_gH#Dgy3b z7I?Wb#wYMCB9A=ND0*o}zBP%tsB`mjsv@qKBi&;k^jTqqr8C6}G@+f7#rfAqPDXBT z&lgY~LTxOvA%{$Xz_)_EB;3>Sav9USFiC?U2}lP1Nk*0i3Ncp|sL!wbFd=PDL(xf< z2uJ-AEwa0?RR*a0&^n*wp^fmh`(e%`Rn#b`W^-z_;~xr-?|k`A$#BI%%yw-Kbs`on zs+s`RBi=`#Wz4}hArcN=h1m@8N$KB~rR%{CL`{*`N7RpA!chtjb?)LWs51yaHUeBgn| z3D=ZW;Mr|!ap6EiW6rjVEVu~Yv+>&>hNSvsOhZu<=v-p)Qo_QCM9Qgvwl+uEeSOD8 zB)Ij4hBoEHp6HbvBOaTvANy_Zv%+h}>CHayz#>YKzyXOZ;J+m zzF1AuMnx6#Q?8Xer+qsV-b)n>wJx~@!*Y@tG=!cObi1h76s4QRnXB8B{kmIOOTe+; zckmk>bs&RmcxHO~M7#wd6DhW_%pX6W`+kgF86Tzh*&Iu2?w}^u#P+8x=b5h@|Ci4% z{@qXC2O1#PHd3Ovd@{_q3NOM6{1adnrm=4|_z1(QB&Z6)nZ@6%>J@@DD3~z}mXH%R@g~gwypgCx@*P+%~bW{`y*Z#+(qo!?(MdBSGirU=xmF z#;vd-SO{%KTK+lW5UhP3pP|s%%xE7oO3P>T;*?E$d9z2P+jt=6%s3|77-G$o`>lwa zj<>+g0y>v*v)z|;3`K}YIWVg~YctvcLgpxGv-GwUh*X7{wjplru%h=uA2tdr)5-cf zDh!xv4jj`M$@z6l>WWSG$Gpf8G{SXq{vJJqe7g3c-Q`{?InPvGxzz)m4^wfEuMR6o zzFg$1P8;Ntl*YhZ8zB&ubbWMwI%=b(V6cYd#86D#L=Y0Mp;L-Dq{={S;>jhDjs2=@ z6nqZ?4e8db0y7Cavzif_<2@w-86Tqx;>JBhCh<76inIo=a3Z=%mEgA^VTv@E7%cSJ z_y_Z2=sb99va+FzOI0icBfJD|F)-t@Y>{w_`nt^HDtRH$J6ErcQRaIM4a_FJ5eS>2 zAsEFdBw`OwqMT63APT3m;i z>{Dq%mVyg@+-_29{R+K6j#!;wzFW$XtT_87$)mIr&BWq9zS=9d zI+F|Hj*^mMRvc?BnPM_7lD6Q4e(%%>mttsOrZUDH9WRa`H9Z=^bUyF{wVD7HNz@mlVln2emhf~meID>d|cTq9G%WQnJ$jDe-DFi9~RO;EHt zUW}*i6Z%1JZ8#EQ$$$!9D(h;loc+FxB9AR7chF?K?ys|c9?X~;bRYD5G#_pkcb|MJ zUCdGFZuo%V;A6(XeWqz5PahTqaPk7}mOj<}p_Dvd7(s_2Qrjj+_iv9Z% z!Ti%}m6M)Q6ki=CYe*+aUF|1oOM*d!k`riYN+RmUX(g+_?>eWDRCy_F&>wqEOj%ae@3E@tY&X&)GTOn)Kg@G%LTI--U%c#xjEEKIT!>6u*r zg!mWdmia__sSK5@VetOKw6nR+)S*%&b8c7&8U@zOZdLB%fw&7W$Ol=+ZJUDZXJrsh zbJ>sIj;|J*YL?!avD3r@}h#W@ye zD~S&sUb{^2@F^<*QL%JB$s@7~sj$>B)JP|g{}v8FhOctq&J%VLfhB!QbM{PpXGrGP zFYS>*TQeBv0bV;G*rGFR%^79XaEH<*M?!JtlR@j1B*!o0WWR6A#Vuo=Gsx{CgiO9u z{Gt?17{IilF7~|58TSZRe`(6(>GJ#6 zSI*a0@7LGt%U!PaF0jRrD>Qs)_r8hFvasU=D?&y&lAXhY3u!raLOk|7t*wZ(h|w0~ z@*q!%rWbSmFqb7)S=LIxWn!>VX!Q#vdH$5JM&77GhqnBw8jY}`?gyc;qd4<`E~QXL zG;%Vt3d950jpV5C7UrA~)65<;`Jk4K0*lLCP8My8m`hSV@3TMe9gB)+;>Xtcf-ySB zE30r63vMNBtd;Rbo0XF>?FgOgl1#a;R!j8kBeP}u z_yl=u-!WIDJhJnB@Hv=Q40%mYCHVwj`V?d>oIzMcGhNpR^ZfwibYpAb5D=wuL}=(N zRoSIDW78-CB<#`(RF%KgO>O$sq^`ioFomb#gk+>emUreT5w!iFH!1Z`O5W&%6fLDZyR>5Jg>&@p6^n+Ql2syOo$qVuD zG*=qXM(Ym!lqoAER&ECUpmpJ7Cl%5h1&ZR#SK`@8GGl)Si?Vsf_xHk$VS#agKuw&A zAq0s$^J--?kg`r@?}m`yk9#18QQbY4H=(nLuEEy1FGT=DjBYdvnJSDR0t)1ev@#7d zgge+81n9yTmSUOfoP{phqRoR-lPHK=Vj1r>v1SD)vAGx%4&2P)+Ylkr5DhKbZ{WG( zanCQ&6x?LLkx02Ad)Or+XE#K$&p9d$P##(Bf4kH{o%Rxl!q2ad#yl8!WTH!5p&dA* z-m~As_w6)5B6XA!ip;kwm(>jgX2}|Q3^1g(K`&U0s*st)9JGY7q?T1}Zv?89u33b} zG6$0%F7XSE;``MV?d%Z{jx#@n-)V~IIMmF|cET`t?hO`9O$az47z`~Ya2UG2m3hrN z0LmqRI1edM`-OIf-7rQj&6^9gNhMXc$QR*8`y01lpwa0>T-Cu3=g)Rk5cWI-GCE`^ zpmOT=RYA3MW?q;`=O^!1fvl_Ni3P+~)7}Ju!dMYWLyS1HQjlxRB>*%p23 z#VV!_;pmkqR>d~h-AQYeZ9e$JM`yVs36fPM^NWj|?9jCb$O9CZcEnA0Z z5$bo?j@m)|w_H1fE!KB9S8wQ!UGTjJwq3${tOpcbQBQlMn|AxYIwDw_ztH&d5~5;n za7>QEn%B){*nFZpS<0 z85u0j*G~lcJs@ksbaAMLli$K7F5s8HyHB4+lc=3^D`;+WRAAM&Y^{9oFbAKz7QLXf z*UCndC&P&Y9=UO`7~tge2@p@e8J1%~jGXtmHSr(QmJlF0&35%Q&O)DARSS=?4&r0P zk2C~1`hSIxsUSaxBx+LdX|pksxVk`FpgJHR z{AyzeKK_lRJ*y76VP)t{Z4P;{Mo4=rvO+=%&2XadD!#gr679YX+}V;aI@nwBWc`j& zGdXhE2oJ-2O9B~JPZp@FIp>&l+r(ww{Ckqsh$v^D)~_rq!eX_A2vu&t@#ilZ1~rG5 zRvvFA)GQ%#yk4YrQ}pk5p6$hTg#5$y!c`%^YP@7com47gHw%LnlL9(?9G_N*FDnGa`M!r0@1Zvk|HzSPM-Wi%6qP%I{T-|S|%$Z>KeOgPNP{tY}2f1F;0$C zq?FK1o1zn`)UZ*%8@QS?zp<%!@s$b8OTr%=*HOnnRGsLiO>GCSxq%ET@QDOW=mb?T zkE&)#yiv`MIn&`v#*djCacU7Ppd+FuS>U5E!)Jtd$kcg~@~H!c3QG(xQ>JQ&IzaVK zMh`yO>2TubUDb-F!~$v*gyR)TkR8_{)Mc!{KB9#@r>aC->XlRR^eM^Nnv4>>BNy2C2``Fj*)_*5Ptu5G-6h26Pj zfQl0~C*hn<4k)~Ho_+~)s&-u*X_5&ab#>Q3>7t0tzVTcUuvtg}9;>6oJhsGQhV5Qm zANG~f__Rr3cWTmgYosAhDEY$~^L&i448SPD@%x<4l`mT{xd=#H)~RSNq+(o3QTGWr zKDkJ9j+ACiO3SZuT6;6rdEbI8YyIdl-T*&P$AGY&*18DbY{WJSOXu0g2f?9x%y-eTo4jAW~YdFT3?n!*nP7y zW4c1a=zU92dFU$LIkxN;*u@I449;pLGrGZ&3*}?*jB|5g0wC&l4|i09fWQn?Rqa{U z#P3G(hB4?Z(LRkh(;hQH?RVT^I8+UWRH{4P3?Hdpn_1XPjnJF5Xqg5NOEo?my2-j& zPA7Q2hA_iIlY{I?R}xuuK<7zR1Mq!|UD=xjCc~aMgkRhH%O@Sl8o6I|t_P#XnZsM) zdD4If5D&D#AUP#& z#HZQon?0sSj-&S4Zxfw?VJn_5zDy70-Xl?f3`h0Pb;C`mUq)TktX+*7!t68@)m3Q~ zzp)2A8f;74`&+h4$5%x&2BNjt9O57rOxt& zoa%_~I72?9Gn6vaR_}k%A0@F$mKwq&;4S&`{qr_M}mPgbfv*O;^nnt+2f27AQ0%C01i$ z;8?L+b}o5d5@1q3rU|YrBA&N1x54BE`16R*%KGc%i<^RVO8BWeqa9IlhHBXxOtVe5 zr0#mj>cqIdXX1md9NI099pGZzJpW)4{i1g zbHzR9iEmYg@9xQLuCDn*7us^v_vUiP!QKA0Ft0nr!Tmsvi`ni=m{A~ILV`|pyhnZV z>H&JYn0b}(T{P%iz=Td=VvTam8A)4XL}!}tU^d$7%cu>^oo_&uddK_Ci(R^Gz=7R| zUUO55p}h`fC(i9=fPmlUcR2*yv`45lKfH3|cnwz&^ha(BOMt0D=2aX9W4_C>vU99N8q@ObC)=+yqRGS-&eVBOHlyjuIr*rwX1Zu2aq8VUExTu9D{8ja<2CKT&Se^&x}_1M*YjH@KBQ*R z(laVeJhn0|1O8N@3$D#O2-sZSI?cL$b?F6;W1vAU=}%!W_h6+`sN*CsW0{My;l(Ad z%ue$*uh2&G@`vw2hWoUJ%5!pvv|M}$SDNpkd*#u&efEwK$?&)%rth(H*ZFL{t8@4! zBVPepLOdkF{0H(y-_F)^zjIfc`|sNb&3;xSWq#qQY{y-+IW-^n$t-sf5bO!-KO?q- zMs_w|>9;jFbPi-%DUZx!Uq80_e6wPzk0R%7cYM@7k7BVgB*jtW#^H8{gx5>Cc|HNy{&jvn^ z;#jlvDpKuBzUkk+f92fxoG|x(y+1?e{ZLnwVX9iu$*QcFjx$wljV+>hxyzr7DYMpd zvenM;Rg5E^ipLT=7yMZ=mpBLKNXJW-iFRgr#07cNin#_E+Mak}L4vD{G~E)N_r?@@ zwmPAB{7slLshTlZ`Z__Z}tuDWh#6nwuI_6sOb{m zFTU147g}+4e490gh9jCv#K9#=z*goqI3WDfQW_%Nr`socM^PoWt@tH8;tHn(dT8izt3^HOCb@U(_ZNHXo;wmvGUZQx0um29Go)nR&cf+n+te zFLl;JX0wUi6L@8x*&-#9?0w<9 z^G9bW8u+<}lcFv?2QVm!<@x-e-=YW~kNz^>7?)tZQw0G668YO5ga4d}{=dok|B-aE zh7SMHgE2M_)(|Z`vY-V54LYx=`ax|Dh6vRPDpk757A_A#T|5EV`XRa3}K&U zIb&=oL$24ggui0(Bzp*mC{~7_^kn;~EA6Bk;Q#q?C=UesEINoEV7E9udKuzlGpuzB zE1haStj26d%ZUE5mTm}9)5>Lu%E}7U#LJi(qcP)vZmbN8K+A$?G4)Gn&p=5R4U`)L zhvS`$84_Ge>{zLAe8|VjgP90X&aPq>3~)uOWa7W&`rhXd*pxt{C2K(xb$!w}(P;Yu zQoR_FQQm&$Vbo(Ix3`9FznFT1&bx?B#g&mQ8YL@iHsf}=*C8O>#338*$YE>=1>1B3 zgeAlcf5sUNAK)vD);w}5V&8!UBJO%Q+=Cdq9~^r4?w6vCXTK*Ka4bqg$pQvZz&-c} zIbhP;BJy;2E2 zH6WDSysB^C zqN^s?uZ!legOcoAKw3ItlB;Hq+S&{iCN&9(v$c|Pf-ogc(9%$1&x03L`)AFC2LZ>L zTEH8#aae(?gEb}+XS3$6R5Y3JW7^56nONz89p4QXnsQLX6NQUUc-D{z23xfP;MP{Ms!r%~xd&0H zt=KT~s)Gt~7OSWBkVK|&PIFZn%QJNSBXfhYTF}x#Z4{TYfiAY0IsY-xa{0IurT~xN zqAf^1yhnlbmBw}Mh8ZyHAU~)pw|A_&?rVV40JUs&nw|!_s%3zfO*rVod4WY9HXo0U z-l9ErR3%EnVUwA9qfW<45>y3Y{T5vH8j!MDA5JD_?1}H)8@=de+&a<2GdYI9z7O0< zdyVd#5q=1fP<3TOe5Bis&18yCBI8ZE5sa%{#Q_GXvrUiTf@jUem!{mJ4vrGYAPm(K zl1H876vULKU4bnGHL2txx+fB2v2`0%kq*&v5%M*kfy?g6->GGgdN1WN(bE@DV7w5K z;`ss;;=YoECDl_C-z?;6txBT8kAv#fsAi#!PnqY~Wv5j+w2QU<3PqZ2wDSv4|;VaLz zd}(@XC_pzHjb`U-pwLxlAp>A%N8|}Op-(swg)gdUn@q`DoZ@rH&{y|l83OmnaqSop zuvf54hsMu$%cjCAb^}Snd{zzRn|6jjY+?=Q+%8D^BE?xo4((79z7p z@EcC6DC9ajW9lJ3p>>QsuvP+%d<|V9%O-yaUeXoym9EfiaVQ?*t#F{llhzqPxLBrN zFQqrDj3K*CD)9UK%f~VzI`W0&kGh-lw9(&ucW`qx_<%&UgbRPvlU{k_X4A3 zrM!^xU2;s6%?**D<}=6}P?=L?x7Kwmi?7rO!NZ`tbpq3_&N+pN)DhqGjPCCzTh2FI zFTbBo7=XyS{!eRP0aRBKtW6*g+}#Q8?i$?P-Q8V7Ah^2*4HDcnxCD214=%wiC@9Qr~7MKn$A*1Ckx97^VcuUb}ofoqtY1Eiv{GqaGHG7 zsN1h|?3BIcVSwUCo9sd(dsl`RLx9Z3D>4MXpMM&&!RC*1A2<;E)k#drsIt_P&0?YP zeba*+v!d)8Jw$z3=N^k!zs;nN38&5s*G19p-f6oo*;OoZ$TL10g{NY(8^a@wevR|| z{dKo2WOnbjab?2<1zFEHC^6$HJ>_l%)l70{H5Q4c63#x8xRVJpZQ;b)P<9_~WC@Wf zW0!n1x@WgBasvz1;|UU8iD+Dsj@m( z=nTH`O1Qx;!8uyH=uMp3T}o^vGe#JZ_zT{+ zLE@|p1$pJhS06&sn{L$wqByfs39kS^;@l_>)tY^{o%i5g!J)m$;DkWdE0uvZB-T=(=(7`qYssSBSWhZ2E z$|zI1x3|H}e+?Cf5#viC$Oanq(IOB`(oN){pV)+A_&P>c?iCvwxKoD>jxrGsmPYuA zu2Ydph8k-8ivR2kJ5@uT8or4?z(%%pVqvO9Q1!0IsAPk)PpeB z($YZh`$M%q&y*DB?t=%+J4w*z?SS4SMG75akp#V_6SL@9ND=7htAqg;JBD_Etr4Lg z`vlyQ9cPKV;?H|L(;H4R9LXjfbK-LcPs4Xk*^?~-MAGR?qd7Nk&z){w*R(HvyFJEu zgXfOU%cDJ9iG1pA_)04dEti4VB9GdLa)Hqh%cGwRIeYta(P||v2Cww;azmMZ;Z|5> zJoxCuW=hm*40*9+*r{%w{!DR;0<{R0ZB*qPagEEP@H8nk0%}~crLQ3 zB(5S$Aqjc|e7$o*yB$L&uEXXk-Hz8lI?P6{f#W`;oyEmc#3Jq!W-mX8*cRYNq6=t2 zXqeDcCtlIgq~F*hwhQ@%CX5$GM_BtXCj>ogh2-~8Aq1rW zNn@5gSVlRfNQ?G4XJVf*ht?0V6Gv2opvEz5oA7pqBL);8AiI1rSSi7YE}uKzG8V2- z2=;Pmkt%ufc%}?(AMe<8%pElyAHHiz9k}F0MPRAQj#BDjE5Qq4s=DFfBc5#+UT%k- zb}&NUWe|_n85syF-?>hv3+j(4!V4sg3pNpJkBwe?ueVE47#@nh$w4A-qIX2KY6}|A zWS;{leWz4+9V3-LUhYRuw#|;}UebCTuJ0HGyJd{}H9^tBH5O~KrGTvW^qmD|L0pKC zVf6~SrH{3SwzHT`8jbjC_YW&XmSx451-J-{Z|GH&@YOK1nj{qm80SZh;10k~_!KCzc~j^qW+4@Y?AEjNr3`7^^5ED=VcO@#W{)+xFqu1%EfiIu(Y&##}Ifkh~R zt*5>9>}DcOuiXjr29XHeHxwFxMmLl1!2IUL!ClRE*A3YY!X5+U?nYVTCqNN7NW}y$ zsatJ4W7}`N4w7#rYbHZ=^R_m)Q{4^5f%U9Xx|m`}IJ-z-E(XEnFvn%%6RPZFX&P>_ za}kpsvnM5ouQPahEVm@6)exw&nSZmRs~NeA%h;ENfiaa);Hl~@h`j*EL-(*nBkYr1 zcPD3}de{yO`B?$EblLEf7|tEVF3r;$k)>wVF$EZ#Xuqi&*xtoDFnE>1H ztg31HEJi(8xKhfur$G+Zh%O8)d!r3Xf7#FXvNb{{Ms;=nr ztpJbqwc)QrlN=cDu^yDf^G?5~k};eaD=p~XFq38v7LHkw6;K+Snn1aMXf-N3@M7d} z2B)0mY#~$Yte&-fKDn|)clU%lHVir*uR z*_o#^A157E3W-MOp=OUUs#Lv+-Mplujf0v~!>MGlvg5aPzQFQDsv1ly|oQL#1U>nxACs{D;l1gM|I=Q}yuE_?unKzY9id%WT{lQLl2hFDoS z_eBTT^SfY502F{=BBa)I%%{9fuV)XAu`+-a?8J=_PL#D1B67zuGkOL;CPZ0EQ^FXy zn>*@@DUCUINC&0OXMe3Jijy}L1E0ce7bC*fOZ>z*o-XC!cP1;Yw`P*xiYh@Igab;9 zITL{4Co;-{*kmn_ZV&~Dr(42p9v#r zn~70nxKfkOwHRn(1|t%PUH7mlG(ds?6G1~LyNqoL!6)M(c|~%q$eXa6X6f3NRiq(I zZ!IFJOP3%DSgX`k-v}qm2#hZvxk!lZwyC#r)4?(%8tJy#+CEE4Tk5wkyMi6PWvsf_ zfKuFA^o_`7*8%~qSAX>W0D#7SEpZ>0i#jp3t&|%KkY2@|#nvrwpiG%&1cK zQWZ?2C93}Mxbm=~&xdLT;zux>_vyu21$VErW5!Fs9jdU;-d ze&f|>pgaTPp6y#Q*M`;2Ao!iS&dFVCyLL7C~xU;{t(u`e4dEfxCH z@Nwj5-~%l=fZn~s-&hhxjly)NE$^hHphn+kalxuK)VPjLLYl=INhqppvtA3pXz%0_+Nnm3n0&Ul!|#hnCzt}@^00dyfe>Mj7ZU&|rO z<0`prvHC0sQp{Eu2tG;Gl~HJvJ73YW57l9krnFT$xw*LqKy$WQ-c$;lTa1#Mq0EhBK@*}e5i8F4XDM{Y~Y~j+0?)|{@3ZO`kpOolSUK$Zj96T7I*;_`%?Y; z5cN33z5X1G97k6;%$x{%kw3MN6>ymioOT5&C_E}WfZ`RG)?A)P$E?x(mER~K6EO#H zRyQ)3R_1-c$)r1YCbO78@5lFkKTnUs9DxE`ady%R?PG8av zwusX4nqPaBF| z(lxXLWCPqSJb=jp`otdN6r~ODrT*Aj#ux!iZt@6c{I{^|5-$D3L6@bvAk>u40B?{w zJlf1^xgZyF5%KEvt_E(I3-4NrmV{Gv^*Ru8?RmV9b`c|SwMIA9F*=}FImvx1sR`}y z+|CiNPWDLKa!FqbH1$KCuSTS3b>CegN)1(@fNEt00A5`Z?oof8R{GI&u!@ACL*;uB z&`)g69E1tNr1;At}PoCg7{q6BkC@=&cOTrw$Lf0roPsafOVpM}&>72y%Mq z*W{4MY4?TNdcEK@-Y@1i#W4j*t+%}LI=Xy0uiv62{62yA11gdk+Nr#`J)+}}G!FxA z@X*+d{T}Vipac(o63(%V>LIWz!3rUgJs}STL2M4{VBQISbH_DPm4jMB^dlh2-*021Pbz)((#RY<}-cMZMg88H<)WhUJ*GL6*`#-&{;a^)TP4FWyLP2?O#~3 zv%!G@J=<%=N`XyfqEoaEJl)s78MJp4iF40TS%J!jt(vP`f;%FdAJ2~q7*hV zOhW*?o4*w+#TTibx4OHw{H4U_os&w1?xJ`F=3*wp0)$nh08`Qu2*oSc@7%iyZTHBF z7AB1fJ=;Umrf2qqjy4sy{0$?{rjKpJ@A4aL)45pu;U&{!JVcGTn zZcQ)lre9CTD>j9#J1g^t9qp0LXSF+J%V4qM#)Jk{p4OAmu|Y~M?ICPY>X=YNhQxa9 zi&|wKf43)&DX(g3&>7eFV%__`9tyn3Q&=&j!pfGrJXn&qsX=Vzo20ziSoQNfwir!A zZ&}&L{Yn?^th_1PGG)$FcFauL14?DB!q?@&r9gmebn&quRYMOLVHL6F+blkXZ}8B< z6%119;CrP(5OJKvAmP&^ccHvd1Y?}1)D10-l z$_hCRFAfz$6KagKwI~R<@o}w>@!V>**D&ZWj(Qac#%+BB8?Ia>2I0Dd$5E8K$J{7R zt~mB(^9$cLaj%9BA4!T&bhko@J%!$xRj8vb2a`*t`K_vRh6~~}%2iw|;5Wo(_-bgO z=We=bR2cIMHI8t&Fnx)Sxbu!?B{P3l2D8oWfKypi9zLzYP;(Sj+tFGi;r}*?|5}Ih0 zK=+3}ZYuQ&ef~Ow|Fqkvz|}B4 zjQZIb;DI(}IGv80qaNSx)eesu<-)t(nO2QLgwM_dc2Qhl)P|L(;rSEfA@3c-HPnXI zuruh~(mdA>>!~m*y4XkpmT#c3wZ)j640sNckHg654LR5)I2S*RrFFnKaL+8pp!2Q} zUb?eCHLVg|P>%pXYnWo8zI!d)CUSl3SE zh$u)mg%&`Jgb>V1*j=0}4xaQ&=j_@nF@mkA+Va`KX?mf+j^Jw@2x5Fr`Gf@4;lYb?JD<2YhBJ{v*h|psI2)>KR}V_ z)AEgLcprXhP-#`Nq|Y8}h3Z0OST4*KTo45EurL8eT;Q~h@Um5c%l->rF85gN3@5og zJ#L`25r)PBXb~lbRvi0QjLNfJiAUpa3-@g(DLOAeM)%BSU=`89{CX8W)IVQ9CVNBQ zPrf~uITzDZ&UtaUPX*-GMe}j3P833kS)hhG8kH*q@2t(y;%gM1W-$XAJiDfvA#4{T z5L!P?|Ad7S_GwDoDMsc*EaXhRQPdk;G*=u#gzFAP$bz$PwhDR)GO~w#)s&T+^y|H6 zVJt`uO*@SQx_=u=nCN@n zC_Do5fu=3s&O$Whu20sgeA?2Yj^jzRbmPJ7nL;6xsNJQ~#p-RqG2u`gt;jN}D5Ug4 znoGL&1d>(=L1qQ|UM($7XuP$zsv*r&Ag0Y$@f%4)pfpL^dp4PFpQT{L_`9}xR^5&1dfjWxa4t={Mr@O7lK|KA zKkU@zjY5FbeJ~dFANVz#{+?gsf5Wik`!LLeFMR_)oA9f+Y?3b!ig$!DI6O&AP|iw& zqhcO@SJQLRO0nHS~X2X}TXVIy|IV&fI3)$R_dV z(TlFp=-aF{Tf%xStLb8Dwafy%&Qb@oEiHh9AlUwhi)2sD0=Pa!xLC5rxwb}7D9u9V`OV$$U1@XigH`;layGiZ>MTWQilJ8PlQ3vR zql23AeOuEP#Zu#H7d+v{oIo@5$Xo0QBaGRlrHD!9q=lbHmW;bh~?lBmV4+;y_P?FH(nIb5L4^X$e6zA_>2K*ZGZs z9~x`s6kO14Lr|o>#8hux(1oB>QhxCY9v|y#M}!+{3AyXLVnoR}$dVo9cD8}tc_0sC z+PxS(O{UZw?0%WU@ROTNoWZ@Q70Z9#L&HC1~T^+_n^BTw@M+7rC3%DKvo%#eHE z{M?YF&)XsAgPh-3&z87SGwubcPrqEhPtRPp+&DgfWhN~AVy3&iJC8mX+sVZKjuC}> zXCsa>E1yZP98ZvLnApN~1xLi95fEZpw zT>HY96GK@;)4Q*}yOObUF3y?`T+0H^MCiF#baGkTLB$a^^`7zE-rb9UaQ{)U43{AyYxBD^bg5+5W8)Q^yFy%tq zdp;;JX?We`%@xGruG%I>K!p!(-qgg!o#!grE3x$QZ= zfO)+|uOGpunR&TR9q5cIq+2Vt+%Z|NK54LiGV1X5_;blj2w_TtiGo5X`hj2x4_(RU zEL9|y*|f!^YysVadfhJKNhd@TFX)e6ipvLTG10gfLW~3>a9unkg>bQY1l^GxxPE%5 ztH{ix{O@gJ{et46Y2y-Z?~wJO%|{dcGA}SHZj92EBCy$W36^ zWNAYR>ggN@qw69kV;#x*s-T)H(0pv&f+`7$`Lfpc4>%`6!arTrvkGv^Jhg)9eJ zeHx7RkQNR0Yg1=%I}X@Dd<^Arw>)MDIW$RqR9#n!D(-dg8Pv$EGt-_;x&sLc z$-!~YWUtseiXScfLvnVj;;zjQxO%j8%ZGy;CCk#R3_pXoj_RY)32*g8QcFHrRbR~! zYbfe35~`6CQTeG>vYsnQP$jF3RH)UI1;AbzbD4xBrs4w5eC^53!9r#D`{3+K+F9Hw zcWAGK1Lm^M@Y(wcR%E6wnXq@G^jgERRQzY_>&Hg&=4O>PH0;O#UsO|P_`B7U*sU?W zSAraxALbDq^PD<*#zoLy`mvf8iRGfgt!Tq!ZCMZM+tJ5>L%1$G6bU3w(;JcJHynvo zrtTYQ%oFh=i%@Bt_+*#|cw0=baRi6oI_|BKd=6i2xUB!I{PsHd1f{vv`EXr$Q|@Rc zwLY*>>k?X{;qaIkMwk0gRr?LQbuRZ*=#tMMN`iE@IJPKM(Mk(Cw8tXiO3iDZ#g-sg zrz_Z~cg<5;Qmb6^QZPtW#39#=b^=!%q&WgRVy7CnaQ-MCucspFFOjY-(@)qjKc3!_ zNzQk)e}j8#hML^u%wgIBNv6j0Q+l%|kMU=Gw*jGyL%<>c(`ePLuxMsPwFp7ls zlwr8$dE7ry??MWN!_BCO>cIO8w{RwWvgwa1&$ULkQ|~$E>SLaTM0P>?LXpq$<>F@X zHPo4?MMEg}wfOWU!lKR|sKwHTDaM-QDrbX~ZTQ-&TQtuM0{Ba_l;yD|#)u;@&Gx0F z9!g7GW*Mo(57B*-(0q;k1fnVJdD{c)vhtj72i$?l`9kd%_(9ZHj01Hj>DHvh`!Mvm z)up&G6)`h>^XYl7P8!hw6T!@O%-LgQG0sOEDutx5t_xH1`;^wmF&jlGn+5Y4>N0vI zZ^xt%R&GCDc3AC7ef`q>`j4aAjm$hi4G;hTR_KT8-Hov1qh$;1{v{zG|B6yXQt-j* z_VKOAqmLmy{Mda=W^STOOGjmIuD`FQX1Bux`x?4gx6jUkc-#JSW%~*w7y)1M9PF`m zDqWi890KhJI4C9M`L>!m;)=ifSpWnITrQU_ zbWI0#z7-LJI*Pp~G$d;|9GfBVEK1GMaGmE?rP_kvX0C&ar_+RG^+Emqr%*5{OfTDI znL}WUXDeoelBj?O3^HcR&Kiu>|`Og%Ha; zy55lUicX=32xl5+TJo`i0$yP9F4CK%2(6HgEC-X3B*v-C`feLT*LPEeGawUQFhE3* zY0kfpC!-obH zRrdxJ{u#E5zy<;HSq|UxZ8#GL-MQX8;mhZrInkTPTWiLjjGQD5_QcrHZMa!-HA09Hi=IgOuD&vy(4r&Y zl?-|lAMmDw$`6!-Klz-Ltz{p#19;pv9Zo0abpH8#pr7Tb$}$>1sGwV93!B3#nEo6> zqsBRPHoWNyYJ#=_>LhMb`9>!32#6Kyjzg1i;E+A&4HZ~QSC zawrs0f(cxbOAzi5GXb@5IU0tl@C#@LDjURsmfRs7h1by=vr<9wmM@y9^Z3~=fS!A- z9(%mn($>0Otg&&UFo_3jwXbJqgv#>l(exQ<|Vtqu6aflP@hTUxHuKzno{7BH^5h0@Bt7e;Wmwd+0FG$?o zR@hr)KJcz15f8&C%SN^MGm322fxb{mJ**k+sVygWdMoWyLPv0hyPT zvC!OJfLfWh46U0p(h1Z?m+Mt9WrbFr5$nY_M~?Qx)%;V^=^^8oVgriD~xawA>b38ufHGbtH`M+^@~0C)PrI#yBG2)pxlm%p(NI z20y%spWa~CDS&9EDLZT{U?YhSxd5gP9mpN=5e}{&Yp|u)q8l$})W21vAOn;BOZNmh zG@1Ds`z&%yddK;tn&ym2Gqj&=aKx=z{7rRdzeZQ%@RGUx<|k$$8vzZky;muoy}C}p zYQy0WdWc9@@G0sC*RIx}V?ybiY|Dp}`{f1Qjo_qV;V4nBsSs!cw5S&MsiExp za_(}z?XGiwcjuJQ3n2!;003R|4>!`k;HT+me)wrIyHyrgE`P0&J{Jq(nc4hAN#cytU@{mV#1HGI8 z=y+QoJPhFbMr{@Hj2Xc+^@WY+Gfd!PxOzh{Ri&EY?L~+BBEyo&uO<_Rvr|Qa6$@q) zmg3H^pz?15_K58Xgh8+!Xrzlo6RG>7bUK{Toz51ABoPSEoX4qNZLaL(DEOD_s9eYZ z)Qqo)i~I0v-4;i%nvU*dyJ(huR<%cA9CQz#0ahQ9K)DqZ z$_o-WE6Nclyi8diBm9Y6k*O#vdBvGOAU{cpqh$M?I3uxKBg*IYf>PT|xqj>GnFC_p%|>>RIYfg| zROh~&fh9MJ9mqjey8;)HE<=7kwxauCLiMn0#`435fHe5RNsj4Wz^MKsw0RTqE>Ha4 zks?uSQhafo+(W`9A9wx+&jdt7RGk7MaX6$X>$$?kc*vh?ZBHX0k5cb0 z#K7q=J~b#w;CxnLI#dAgkhr(Vt752q!CHmc~@+#pGRpK0W3Q zZj^%<1#uGz*Tf{=^jkt`VPh8u)mMv>oT;*EnknrgM(>@*Sr?QojU2+de8}t!FVOlJ zoTnMM!VonvlxN6nAxWU6jNOW{Y>$KaqrSEP)a9>zYwbA?R7}Rv-eeDM0rrwb!5d=n z;#xCd1+<#P_aEeEsqb}f78vvSasOHzKYtw>apLwz8ogBDa?0t6G zyN*F7DR8{0s=+N|b1Ra+#<-rFC$f1BBiXjX&SEXulz`Bx43Z;i7-uCRjT1sJl?H|# zLKN=x5+M(tRg~l%t|0<_ZocCJwivJbt}7eDf`VW*pce;K`o}GrR5xT#RdwcR2CC~5 zX;kQD3r>r5n8rxYldL^e%D_YX)Pr}o#nZW7*rMtJT*T+BWkZ1;T&OqeScFvXr;kK= zDQd{u@_aLxy{;pk164sqnja{GOdfEDrTcL~^QyvZ#P}1ZYN|xCTq{*L9eE+otx-D( zNqb^)%uP{HyG)T^mC}b!^JJ*H}>)9^mWO44UM`@3VfgP2#t(CQbt^NJm69~r&iNT?X zKJnfOaw!Qis%~LQ(ffBjQ+?!;V`3r{BK^YsVm%_1WRv$FwR?8F03R)O98Bg?=dJ$E z+L%&Qgm(fxCMjAuDlsiS0by@7To?3@hnE(H$?p~J1-}9KuG%v|M1UX4F^eoRlzRdm zd_V6(yMG}9JO_9@{{J!}@k&xeP(V(eN<#3i_Xi3%z~7&qJ;u=apChrK%>aEg5u(;O~y!el{QZ(fpaeop1LC`{O@j;6K8EdiGBkPZ%Blyae9?cki!S*!@&6 zp!<#5BS6Vt1C-;J`d-&)W%-EJ@u?W$BEQM7`>h`9{TJtaB!&;@KZy~sur~jDQN+!b z#otradhcz4<&h{3s9zHGw?t4+rI-mPW*ptCzIksyY>%WI!u+z7zu`xGDkqs7BzE-v z+Xw(D|$^?d)|d?d|?v%-|}C!OcBrd{VuG# z!4_TjkY0ZgvW)txM(`K@(4XBQ7>|TNqW_e6_o=pGiZCte_cnwM@uTA5&mr)0pdV$v zk2=9T#je;kax%UD74iUoJJ$EVPIlGuGq_rHB6=u>D-rho4_@KddoXh#Js@11@-(vP%~KSu)FuUh#}1w3r_ zP5VfI5&y6KEI);R*o&I(5&W|7f9W6o6#rrC}2}bA|u8BYa8XK zG9LCoeC!?3Wq!9q>R;}t2mQDndq;kS-|ngS6#QXtmdA=Cs{L+*ucz1#dwD!I7z3UE z((C0Z{=<$Dq>nGG-f#2=c?$cm@c_vq*kFTSZ$9xCpY?za|MA_QZ1kU67(5m5kXfDl zkpMN5-{RQ+^+4Um?4N1c{}}`Q5k~euV*H?O|7RTHM>q>V#rbK_|B&`u;1TFc^Zz4S z_opHs61NIJ5(#bjf5$HVRO&-|KEX#)o9+LvC}Mv-0F`q47aG9F%0DD}d%QdZ{2b_C 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 literal 0 HcmV?d00001 diff --git a/java/Websphere/AccessEmployee.ear b/java/Websphere/AccessEmployee.ear new file mode 100644 index 0000000000000000000000000000000000000000..b01f9133d410662043996f4ab4042fa5f4e83038 GIT binary patch literal 178077 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

6Do6c7z|8WpVE6_?9*wQpL)DD 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 CvU~La literal 0 HcmV?d00001 diff --git a/java/Websphere/OptimisticLocking.war b/java/Websphere/OptimisticLocking.war new file mode 100644 index 0000000000000000000000000000000000000000..5918338b49a242d64dc0cee77a643a124d7b2478 GIT binary patch literal 104244 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 CmDhGj6AYnKgyA} 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 literal 0 HcmV?d00001 diff --git a/java/Websphere/README b/java/Websphere/README new file mode 100644 index 0000000..46bb55e --- /dev/null +++ b/java/Websphere/README @@ -0,0 +1,136 @@ +******************************************************************************* +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +******************************************************************************* +* +* README for J2EE Samples +* +* The /sqllib/samples/java/Websphere directory on UNIX and +* \sqllib\samples\java\Websphere directory on Windows contain this README file +* where is the location of DB2 v9.5 on your hard drive. +* The default location for is $HOME for UNIX +* and C:\Program Files\IBM for windows. +* +* The DB2 v9.5 sample code for J2EE is located in the following directory : +* /sqllib/samples/java/Websphere directory on Unix and +* \sqllib\samples\java\Websphere directory on Windows. +* +* This README is organized into DIRECTORY ROADMAP, GETTING J2EE SAMPLES UP +* AND RUNNING, J2EE SAMPLES DETAILS sections. +* +******************************************************************************* +* +* DIRECTORY ROADMAP +* +* Websphere/ : This directory contains a the J2EE samples as a *.war or *.ear file +* +* For more details on the content of these directories, please refer to the +* the README file in the respective *.war or *.ear file. +* +******************************************************************************** +* +* GETTING J2EE SAMPLES UP AND RUNNING +* +* SETUP: +* +* 1) Copy the files from corresponding directory to a working +* directory and ensure that directory has write permission. +* +* 2) Start the database manager with the following command: +* db2start +* +* 3) Create the sample database with the following command: +* db2sampl +* +* 4) Change directory (CD) to the directory containing the files +* copied in step 1. +* +* BUILD AND RUN: +* 1. Extract the sample and modify the connection details and add the JDBC driver. +* 2. Deploy the sample in your Web server or Application server. +* +******************************************************************************** +* +* DETAILS OF SAMPLES +* Usage Scenarios +* +* 1) Samples: AccessEmployee.ear +* +* Consider a user who needs to access the EMPLOYEE table by using Servlet +* and EJB component. +* +* +* 2) Samples: OptimisticLocking.war +* +* The application is written to demonstrate the DB2 Optimistic Locking feature. +* It describe that unlocked rows are unlikely to change before the update or delete operation. +* If the row does change, the update or delete will fail and the application logic handles such failures. +* +* +* 3) Samples: AIRLINE.war +* airline.db2 +* +* The application is written to demonstrate the Currently committed property. +* The cursor stability (CS) isolation level has been enhanced to allow for more concurrency. +* In the new implementation of CS, the behavior of a read operation waiting for a row to commit +* before returning a value is avoided, where possible. CS now returns the currently committed result, +* ignoring what might happen to an uncommitted operation. The overall result of this new behavior is a +* drastic reduction in lock wait and deadlock scenarios. +* +* +* SETUP +* +* I) Open DB2 command window and set up the airline database with the +* following command : +* +* db2 -tvf airline.db2 +* +* This will setup the database for the application and configure the required variables. +* +* II) Modify the CLASSPATH to include: +* +* \sqllib\java\db2jcc4.jar +* where is the location of DB2 9.7 on your hard drive. +* The default location for is C:\Program Files\IBM +* +* III) Deploy the application on WebSphere using the following steps : +* +* i) Open the administrative console +* ii) Browse for "Applications" on left navigation pane of the console +* iii) Click on "Install New Application" +* iv) Provide the "Local File System Full path"(Path of the .war file) +* v) Give the context root as "/AIRLINE" and click "Next" +* vi) Click "Next" in the "Select installation options window" +* vii) Select the checkbox of the AIRLINE application in "Map modules to server" window and click "Next" +* viii) Click on Finish in the �Summary" window +* ix) Click on "Save" after the application is installed +* x) Click on Enterprise Applications on the left navigation pane of the console +* xi) Select the checkbox of the AIRLINE application and click on start. +* +* RUNNING THE APPLICATION +* +* I) Point your web browser to the following URL to run the Currently committed Sample +* http://:/AIRLINE +* +* II) The Log In page will be displayed. +* Provide the username, password, machine name (or the IP of the machine) and the +* port on which DB2 is installed on the machine. +* +* +******************************************************************************** diff --git a/java/Websphere/airline.db2 b/java/Websphere/airline.db2 new file mode 100644 index 0000000..9b7225b --- /dev/null +++ b/java/Websphere/airline.db2 @@ -0,0 +1,68 @@ +db2start; +create db airline; + +connect to airline; + + +create table reservation_table (flight_id varchar(10) NOT NULL PRIMARY KEY, airlines varchar(20), departure time, arrival time, duration time, fare_type varchar(20), fare varchar(10), seats_available integer, source varchar(10), destination varchar(10), date date); + +create table passenger_details (firstname varchar(20), lastname varchar(20),emailid varchar(30), phoneno varchar(20), userid varchar(20),passwd varchar(20), address varchar(60), alt_emailid varchar(30), BIRTHDATE date, sex varchar(6), pincode varchar(10)); + +create table new_flights(FLIGHT_ID VARCHAR(10),AIRLINE VARCHAR(20),DEPARTURE TIME,ARRIVAL TIME,DURATION TIME,FARE_TYPE VARCHAR(20),FARE VARCHAR(10),SEATS INTEGER,SOURCE VARCHAR(10),DESTINATION VARCHAR(10),DATE DATE); + + +insert into reservation_table values('E1','Emirates','11:30:00','05:30:00','06:00:00','Refundable','$580',130,'Bangalore','Toronto',current date + 10 DAYS); +insert into reservation_table values('E2','Emirates','11:30:00','05:30:00','06:00:00','Refundable','$650',120,'Bangalore','London',current date + 10 DAYS); +insert into reservation_table values('AI1','AirIndia','10:00:00','20:00:00','10:00:00','Refundable','$1200',100,'Bangalore','Newyork',current date + 10 DAYS); +insert into reservation_table values('AI2','AirIndia','10:00:00','20:00:00','10:00:00','Refundable','$1200',100,'Bangalore','Delhi',current date + 10 DAYS); + +insert into reservation_table values('E3','Emirates','11:30:00','05:30:00','06:00:00','Refundable','$580',130,'Bangalore','Toronto',current date + 8 DAYS); +insert into reservation_table values('E4','Emirates','11:30:00','05:30:00','06:00:00','Refundable','$650',120,'Bangalore','London',current date + 8 DAYS); +insert into reservation_table values('AI4','AirIndia','10:00:00','20:00:00','10:00:00','Refundable','$1200',100,'Bangalore','Newyork',current date + 8 DAYS); +insert into reservation_table values('AI3','AirIndia','10:00:00','20:00:00','10:00:00','Refundable','$1200',100,'Bangalore','Delhi',current date + 8 DAYS); + +insert into reservation_table values('E5','Emirates','11:30:00','05:30:00','06:00:00','Refundable','$550',100,'London','Toronto',current date + 10 DAYS); +insert into reservation_table values('AI6','AirIndia','11:30:00','05:30:00','06:00:00','Refundable','$550',100,'London','Newyork',current date + 10 DAYS); +insert into reservation_table values('KF10','KingFisher','11:30:00','05:30:00','06:00:00','Refundable','$550',100,'London','Bangalore',current date + 10 DAYS); +insert into reservation_table values('KF9','KingFisher','11:30:00','05:30:00','06:00:00','Refundable','$550',100,'London','Delhi',current date + 10 DAYS); + +insert into reservation_table values('E6','Emirates','11:30:00','05:30:00','06:00:00','Refundable','$550',100,'London','Toronto',current date + 8 DAYS); +insert into reservation_table values('AI7','AirIndia','11:30:00','05:30:00','06:00:00','Refundable','$550',100,'London','Newyork',current date + 8 DAYS); +insert into reservation_table values('KF8','KingFisher','11:30:00','05:30:00','06:00:00','Refundable','$550',100,'London','Bangalore',current date + 8 DAYS); +insert into reservation_table values('KF7','KingFisher','11:30:00','05:30:00','06:00:00','Refundable','$550',100,'London','Delhi',current date + 8 DAYS); + +insert into reservation_table values('L1','Lufthansa','11:00:00','17:00:00','06:00:00','Non-Refundable','$600',100,'Newyork','Toronto',current date + 10 DAYS); +insert into reservation_table values('KF1','KingFisher','11:00:00','17:00:00','06:00:00','Non-Refundable','$600',100,'Newyork','London',current date + 10 DAYS); +insert into reservation_table values('AI8','AirIndia','11:00:00','17:00:00','06:00:00','Non-Refundable','$600',100,'Newyork','Bangalore',current date + 10 DAYS); +insert into reservation_table values('AI9','AirIndia','11:00:00','17:00:00','06:00:00','Non-Refundable','$600',100,'Newyork','Delhi',current date + 10 DAYS); + + +insert into reservation_table values('L2','Lufthansa','11:00:00','17:00:00','06:00:00','Non-Refundable','$600',100,'Newyork','Toronto',current date + 8 DAYS); +insert into reservation_table values('KF2','KingFisher','11:00:00','17:00:00','06:00:00','Non-Refundable','$600',100,'Newyork','London',current date + 8 DAYS); +insert into reservation_table values('AI10','AirIndia','11:00:00','17:00:00','06:00:00','Non-Refundable','$600',100,'Newyork','Bangalore',current date + 8 DAYS); +insert into reservation_table values('AI11','AirIndia','11:00:00','17:00:00','06:00:00','Non-Refundable','$600',100,'Newyork','Delhi',current date + 8 DAYS); + +insert into reservation_table values('KF3','KingFisher','09:00:00','17:00:00','08:00:00','Refundable','$1000',100,'Delhi','London',current date + 8 DAYS); +insert into reservation_table values('L3','Lufthansa','09:00:00','17:00:00','08:00:00','Refundable','$1000',100,'Delhi','Toronto',current date + 8 DAYS); +insert into reservation_table values('KF4','KingFisher','09:00:00','17:00:00','08:00:00','Refundable','$1000',100,'Delhi','Newyork',current date + 8 DAYS); +insert into reservation_table values('AI12','AirIndia','09:00:00','17:00:00','08:00:00','Refundable','$1000',100,'Delhi','Bangalore',current date + 8 DAYS); + +insert into reservation_table values('KF5','KingFisher','09:00:00','17:00:00','08:00:00','Refundable','$1000',100,'Delhi','London',current date + 10 DAYS); +insert into reservation_table values('L4','Lufthansa','09:00:00','17:00:00','08:00:00','Refundable','$1000',100,'Delhi','Toronto',current date + 10 DAYS); +insert into reservation_table values('KF6','KingFisher','09:00:00','17:00:00','08:00:00','Refundable','$1000',100,'Delhi','Newyork',current date + 10 DAYS); +insert into reservation_table values('AI13','AirIndia','09:00:00','17:00:00','08:00:00','Refundable','$1000',100,'Delhi','Bangalore',current date + 10 DAYS); + +insert into passenger_details values('joe','smith','joe_smith@in.ibm.com','9876545674','joesmi','commit','toronto','sm_joe@in.ibm.com','1980-10-7','male','456789'); + + +db2stop force; +db2start; + +connect to airline; + +update db cfg using cur_commit ON; +update db cfg using LOCKTIMEOUT 01; + +db2stop force; +db2start; +connect to airline; \ No newline at end of file diff --git a/java/jdbc/AdmCmdAutoCfg.java b/java/jdbc/AdmCmdAutoCfg.java new file mode 100644 index 0000000..d41ba1a --- /dev/null +++ b/java/jdbc/AdmCmdAutoCfg.java @@ -0,0 +1,153 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: AdmCmdAutoCfg.java +// +// SAMPLE: How to autoconfigure the database +// +// JAVA 2 CLASSES USED: +// CallableStatement +// ResultSet +// +// Classes used from Util.java are: +// Db +// JdbcException +// +//Compile: the utility file and the source file with: +// javac Util.java +//javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: AdmCmdAutoCfg.out (available in the online +// documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.*; // JDBC classes +import java.lang.*; +import java.util.*; +import java.sql.*; + +class AdmCmdAutoCfg +{ + + public static void main(String argv[]) + { + Connection con = null; + ResultSet rs = null; + Db db = null; + CallableStatement callStmt = null; + + try + { + db = new Db(argv); + + System.out.print("\nTHIS SAMPLE SHOWS HOW TO AUTOCONFIGURE"); + System.out.print(" A DATABASE USING ADMIN_CMD.\n"); + + // connect to the 'sample' database + db.connect(); + con = db.con; + + // prepare the CALL statement for ADMIN_CMD + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt = con.prepareCall(sql); + + // autoconfigure the database + String param = "AUTOCONFIGURE USING ISOLATION RS APPLY DB ONLY"; + + // set the input parameter + callStmt.setString(1, param); + + // call the stored procedure + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + callStmt.execute(); + + // get first result set + rs = callStmt.getResultSet(); + + // get the values and display them + while (rs.next()) + { + // retireving level + String level = rs.getString(1); + // retireving name + String name = rs.getString(2); + // retireving value + String value = rs.getString(3); + // retireving recommended value + String recommendedValue = rs.getString(4); + // retrieving datatype + String dataType = rs.getString(5); + + // displaying the resultset + System.out.println("\nLevel = " + level); + System.out.println("Name = " + name); + System.out.println("Value = " + value); + System.out.println("Recommended_value = " + recommendedValue); + System.out.println("Datatype = " + dataType); + } + + System.out.print("\nThe Autoconfiguration is done successfully\n"); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + // close the resultset + rs.close(); + + // close the callStmt + callStmt.close(); + + // roll back any changes to the database made by this sample + con.rollback(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception x) + { + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } // main +} // AdmCmdAutoCfg diff --git a/java/jdbc/AdmCmdContacts.java b/java/jdbc/AdmCmdContacts.java new file mode 100644 index 0000000..630bbac --- /dev/null +++ b/java/jdbc/AdmCmdContacts.java @@ -0,0 +1,282 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: AdmCmdContacts.java +// +// SAMPLE: How to add, update and drop contacts and contact groups +// +// Note: The Database Administration Server(DAS) should be running. +// +// JAVA 2 CLASSES USED: +// Statement +// CallableStatement +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// OUTPUT FILE: AdmCmdContacts.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.*; //JDBC classes +import java.lang.*; +import java.util.*; +import java.sql.*; + +class AdmCmdContacts +{ + + public static void main(String argv[]) + { + Connection con = null; + String param = null; + CallableStatement callStmt = null; + Db db = null; + + try + { + db = new Db(argv); + + System.out.print("\nTHIS SAMPLE SHOWS HOW TO:\n"); + System.out.print(" ADD, UPDATE AND DROP CONTACTS AND CONTACT GROUPS" + + " USING ADMIN_CMD.\n\n"); + + // connect to the 'sample' database + db.connect(); + con = db.con; + + // prepare the CALL statement for ADMIN_CMD + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt = con.prepareCall(sql); + + // add contact testuser1 of type email address testuser1@test.com + param = "ADD CONTACT testuser1 TYPE EMAIL ADDRESS testuser1@test.com"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.print("The contact is added successfully\n"); + + // add contact testuser2 of type email address testuser2@test.com + param = "ADD CONTACT testuser2 TYPE EMAIL ADDRESS testuser2@test.com"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.print("The contact is added successfully\n"); + + // add contact group gname1 containing contact testuser1 + param = "ADD CONTACTGROUP gname1 CONTACT testuser1"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.print("The contact group is added successfully.\n"); + + // update contact testuser1 changing address to address@test.com + param = "UPDATE CONTACT testuser1 USING ADDRESS address@test.com"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.print("The contact is updated successfully\n"); + + // update contact group gname1 by dropping the contact testuser2 + param = "UPDATE CONTACTGROUP gname1 ADD CONTACT testuser2"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.print("The contact group is updated successfully\n"); + + // get the list of contactgroups + + String str = ""; // used as intermediate string to prepare statement. + + // prepare the query + System.out.println(); + System.out.println( + " Prepare Statement:\n" + + " SELECT * FROM TABLE(SYSPROC.ADMIN_GET_CONTACTGROUPS())" + + " AS CONTACTGROUPS"); + + str = "SELECT * FROM TABLE(SYSPROC.ADMIN_GET_CONTACTGROUPS())" + + " AS CONTACTGROUPS"; + + PreparedStatement pstmt = con.prepareStatement( str ); + + System.out.println(); + System.out.println(" Execute prepared statement"); + ResultSet rs = pstmt.executeQuery(); + + System.out.println(); + System.out.println(" Results:\n" + + " NAME DESCRIPTION MEMBERNAME " + + " MEMBERTYPE\n" + + " -------- -------------- ------------- " + + "------------"); + + String name = ""; + String description = ""; + String mname = ""; + String mtype = ""; + + while (rs.next()) + { + name = rs.getString(1); + description = rs.getString(2); + mname = rs.getString(3); + mtype = rs.getString(4); + + System.out.println(" " + + Data.format(name, 14) + " " + + Data.format(description, 12) + " " + + Data.format(mname, 14) + " " + + Data.format(mtype, 14)); + } + rs.close(); + pstmt.close(); + + // get the list of contacts + + // prepare the query + System.out.println(); + System.out.println( + " Prepare Statement:\n" + + " SELECT * FROM table(SYSPROC.ADMIN_GET_CONTACTS()) AS CONTACTS"); + + str = "SELECT * FROM table(SYSPROC.ADMIN_GET_CONTACTS()) AS CONTACTS"; + pstmt = con.prepareStatement( str ); + + System.out.println(); + System.out.println(" Execute prepared statement"); + rs = pstmt.executeQuery(); + + System.out.println(); + System.out.println(" Results:\n" + + " NAME TYPE ADDRESS \n" + + " --------- -------- ----------------------"); + + String cname = ""; + String ctype = ""; + String address = ""; + + while (rs.next()) + { + cname = rs.getString(1); + ctype = rs.getString(2); + address = rs.getString(3); + + System.out.println(" " + + Data.format(cname, 14) + " " + + Data.format(ctype, 12) + " " + + Data.format(address, 18)); + } + rs.close(); + pstmt.close(); + + // drop contact group gname1 + param = "DROP CONTACTGROUP gname1"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.print("The contact group is dropped successfully\n"); + + // drop contact testuser1 + param = "DROP CONTACT testuser1"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.print("The contact is dropped successfully\n"); + + // drop contact testuser2 + param = "DROP CONTACT testuser2"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.print("The contact is dropped successfully\n"); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + // close the callStmt + callStmt.close(); + + // roll back any changes to the database made by this sample + con.rollback(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception x) + { + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } // main +} // AdmCmdContacts diff --git a/java/jdbc/AdmCmdDescribe.java b/java/jdbc/AdmCmdDescribe.java new file mode 100644 index 0000000..33fd40e --- /dev/null +++ b/java/jdbc/AdmCmdDescribe.java @@ -0,0 +1,217 @@ +//////////////////////////////////////////////////////////////////////////* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//////////////////////////////////////////////////////////////////////////* +// +// SOURCE FILE NAME: AdmCmdDescribe.java +// +// SAMPLE: How to do describe table and indexes using ADMIN_CMD +// +// SQL Statements USED: +// CALL +// SELECT +// CREATE INDEX +// DROP INDEX +// +// Classes used from Util.java are: +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +//Run: java [] +// or +// java [] +// +// OUTPUT FILE: AdmCmdDescribe.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//////////////////////////////////////////////////////////////////////////* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +///////////////////////////////////////////////////////////////////////////// + +import java.io.*; // JDBC classes +import java.lang.*; +import java.util.*; +import java.sql.*; + +class AdmCmdDescribe +{ + + public static void main(String argv[]) + { + Connection con = null; + + String colname = null; + String typeschema = null; + String typename = null; + int length; + int scale; + String nullable = null; + + String indschema = null; + String indname = null; + String unique_rule = null; + int colcount; + + Db db =null; + CallableStatement callStmt1 = null; + CallableStatement callStmt2 = null; + ResultSet rs1 = null; + ResultSet rs2 = null; + Statement stmt1 = null; + Statement stmt2 = null; + + try + { + db = new Db(argv); + + // connect to the 'sample' database + db.connect(); + con = db.con; + + System.out.print("\nHOW TO DESCRIBE TABLE AND INDEXES"); + System.out.println(" USING ADMIN_CMD"); + + stmt1 = con.createStatement(); + + System.out.print("\nExecuting CREATE INDEX INDEX1 ON "); + System.out.println("EMPLOYEE (LASTNAME ASC))"); + stmt1.executeUpdate("CREATE INDEX INDEX1 ON " + + "EMPLOYEE (LASTNAME ASC)"); + + // prepare the CALL statement for OUT_LANGUAGE + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + String param = "DESCRIBE TABLE EMPLOYEE"; + + // setting the imput parameter + callStmt1.setString(1, param); + + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + // executing export by calling ADMIN_CMD + callStmt1.execute(); + rs1 = callStmt1.getResultSet(); + + // retrieving the resultset + while (rs1.next()) + { + + // retrieving column name and displaying it + colname = rs1.getString(1); + System.out.println("\nColname = " + colname); + + // retrieving typeschema and displaying it + typeschema = rs1.getString(2); + System.out.println("Typeschema = " + typeschema); + + // retrieving typename and displaying it + typename = rs1.getString(3); + System.out.println("Typename = " + typename); + + // retrieving length and displaying it + length = rs1.getInt(4); + System.out.println("Length = " + length); + + // retrieving scale and displaying it + scale = rs1.getInt(5); + System.out.println("Scale = " + scale); + + // retrieving nullable and displaying it + nullable = rs1.getString(6); + System.out.println("Nullable = " + nullable); + + } + + callStmt2 = con.prepareCall(sql); + param = "DESCRIBE INDEXES FOR TABLE EMPLOYEE"; + + // setting the imput parameter + callStmt2.setString(1, param); + + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + // executing describe indexes using ADMIN_CMD + callStmt2.execute(); + rs2 = callStmt2.getResultSet(); + + // retrieving the resultset + while( rs2.next()) + { + // retrieving index schema and displaying it + indschema = rs2.getString(1); + System.out.println("\nIndschema = " + indschema); + + // retrieving index name and displaying it + indname = rs2.getString(2); + System.out.println("Indname = " + indname); + + // retrieving unique rule and displaying it + unique_rule = rs2.getString(3); + System.out.println("Unique_rule = " + unique_rule); + + // retrieving column count and displaying it + colcount = rs2.getInt(4); + System.out.println("Colcount = " + colcount); + + } + stmt2 = con.createStatement(); + System.out.println("\nExecuting DROP INDEX INDEX1"); + stmt2.executeUpdate("DROP INDEX INDEX1"); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + //closing the connections and resultset + callStmt1.close(); + callStmt2.close(); + stmt1.close(); + stmt2.close(); + rs1.close(); + rs2.close(); + + // roll back any changes to the database made by this sample + con.rollback(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception x) + { + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } // main +} // AdmCmdDescribe diff --git a/java/jdbc/AdmCmdExport.java b/java/jdbc/AdmCmdExport.java new file mode 100644 index 0000000..43ce1c6 --- /dev/null +++ b/java/jdbc/AdmCmdExport.java @@ -0,0 +1,195 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: AdmCmdExport.java +// +// SAMPLE: How to perform export using ADMIN_CMD. +// +// This sample should be run using the following steps: +// 1.Compile the program with the following command: +// javac AdmCmdExport.java +// +// 2.The sample should be run using the following command +// java AdmCmdExport +// The fenced user id must be able to create or overwrite files in +// the target export directory specified.This directory must +// be a full path on the server. The path must include '\' or '/' +// in the end according to the platform. The file for export must +// exist before the sample is run. +// +// SQL Statements USED: +// CALL +// SELECT +// +// Class used from Util.java are: +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +//Run: java [] +// or +// java [] +// +// OUTPUT FILE: AdmCmdExport.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** + +import java.io.*; +import java.lang.*; +import java.util.*; +import java.sql.*; + +class AdmCmdExport +{ + + public static void main(String argv[]) + { + Connection con = null; + + int rows_exported; + String msg_retrieval = null; + String msg_removal = null; + String sqlcode = null; + String msg = null; + + CallableStatement callStmt1 = null; + ResultSet rs1 = null; + PreparedStatement stmt1 = null; + ResultSet rs2 = null; + CallableStatement callStmt2 = null; + + if (argv.length < 1) + { + System.out.println("\n Usage : java AdmCmdExport "); + } + else + { + try + { + // initialize DB2Driver and establish database connection. + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + System.out.println("HOW TO PERFORM EXPORT USING ADMIN_CMD.\n"); + // prepare the CALL statement for OUT_LANGUAGE + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + String param = "export to "+ argv[0] + "org_ex.ixf "; + param = param + "of ixf messages on server select * from org" ; + + // set the imput parameter + callStmt1.setString(1, param); + System.out.println("CALL ADMIN_CMD('" + param + "')"); + + // execute export by calling ADMIN_CMD + callStmt1.execute(); + rs1 = callStmt1.getResultSet(); + // retrieve the resultset + if( rs1.next()) + { + // the numbers of rows exported + rows_exported = rs1.getInt(1); + + // retrieve the select stmt for message retrival + // containing SYSPROC.ADMIN_GET_MSGS + msg_retrieval = rs1.getString(2); + + // retrive the stmt for message cleanup + // containing CALL of SYSPROC.ADMIN_REMOVE_MSGS + msg_removal = rs1.getString(3); + + // display the output + System.out.println("Total number of rows exported : " + rows_exported); + System.out.println("SQL for retrieving the messages: " + msg_retrieval); + System.out.println("SQL for removing the messages : " + msg_removal); + } + + stmt1 = con.prepareStatement(msg_retrieval); + System.out.println("\n" + "Executing " + msg_retrieval); + + // message retrivel + rs2 = stmt1.executeQuery(); + + // retrieve the resultset + while(rs2.next()) + { + // retrieve the sqlcode + sqlcode = rs2.getString(1); + + // retrieve the error message + msg = rs2.getString(2); + System.out.println("Sqlcode : " +sqlcode); + System.out.println("Msg : " +msg); + } + + System.out.println("\nExecuting " + msg_removal); + callStmt2 = con.prepareCall(msg_removal); + + // executing the message retrivel + callStmt2.execute(); + } + catch(Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + // close the statements + callStmt1.close(); + callStmt2.close(); + stmt1.close(); + + // close the resultsets + rs1.close(); + rs2.close(); + + // roll back any changes to the database made by this sample + con.rollback(); + + // close the connection + con.close(); + } + catch (Exception x) + { + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } + } // main +} // AdmCmdExport diff --git a/java/jdbc/AdmCmdImport.java b/java/jdbc/AdmCmdImport.java new file mode 100644 index 0000000..c20b1f2 --- /dev/null +++ b/java/jdbc/AdmCmdImport.java @@ -0,0 +1,230 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: AdmCmdImport.java +// +// +// SAMPLE: How to do export using ADMIN_CMD() +// This sample should be run using the following steps: +// 1.Compile the program with the following command: +// javac AdmCmdImport.java +// +// 2.The sample should be run using the following command +// java AdmCmdImport +// The fenced user id must be able read the file specified +// for import.This directory must be a full path on the server. +// The path must include '\' or '/' in the end according to the +// platform. +// +// SQL Statements USED: +// CALL +// SELECT +// +// Classes used from Util.java are: +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +//Run: java [] +// or +// java [] +// +// OUTPUT FILE: AdmCmdImport.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//************************************************************************* + +import java.io.*; //JDBC classes +import java.lang.*; +import java.util.*; +import java.sql.*; + +class AdmCmdImport +{ + + public static void main(String argv[]) + { + Connection con = null; + CallableStatement callStmt1 = null; + CallableStatement callStmt2 = null; + ResultSet rs1 = null; + ResultSet rs2 = null; + PreparedStatement stmt1 = null; + Statement stmt2 = null; + + int rows_read; + int rows_skipped; + int rows_loaded; + int rows_rejected; + int rows_deleted; + int rows_committed; + + String msg_retrieval = null; + String msg_removal = null; + String sqlcode = null; + String msg = null; + + if (argv.length < 1) + { + System.out.println("\n Usage : java AdmCmdImport "); + } + else + { + try + { + // Initialize DB2Driver and establish database connection. + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + System.out.println("HOW TO DO IMPORT USING ADMIN_CMD.\n"); + // prepare the CALL statement for OUT_LANGUAGE + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // argv[0] is the path for the file to be imported + String param = "IMPORT FROM " + argv[0] + "org_ex.ixf OF IXF MESSAGES "; + param = param + "ON SERVER CREATE INTO ORG_IMPORT" ; + + // setting the imput parameter + callStmt1.setString(1, param); + System.out.println("CALL ADMIN_CMD('" + param + "')"); + + // executing import by calling ADMIN_CMD + callStmt1.execute(); + rs1 = callStmt1.getResultSet(); + + // retrieving the resultset + if( rs1.next()) + { + // retrieve the no of rows read + rows_read = rs1.getInt(1); + // retrieve the no of rows skipped + rows_skipped = rs1.getInt(2); + // retrieve the no of rows loaded + rows_loaded = rs1.getInt(3); + // retrieve the no of rows rejected + rows_rejected = rs1.getInt(4); + // retrieve the no of rows deleted + rows_deleted = rs1.getInt(5); + // retrieve the no of rows committed + rows_committed = rs1.getInt(6); + + // retrieve the select stmt for message retrival + // containing SYSPROC.ADMIN_GET_MSGS + msg_retrieval = rs1.getString(7); + + // retrive the stmt for message cleanup + // containing CALL of SYSPROC.ADMIN_REMOVE_MSGS + msg_removal = rs1.getString(8); + + // Displaying the resultset + System.out.print("\nTotal number of rows read : "); + System.out.println(rows_read); + System.out.print("Total number of rows skipped : "); + System.out.println( rows_skipped); + System.out.print("Total number of rows loaded : "); + System.out.println(rows_loaded); + System.out.print("Total number of rows rejected : "); + System.out.println(rows_rejected); + System.out.print("Total number of rows deleted : "); + System.out.println(rows_deleted); + System.out.print("Total number of rows committed : "); + System.out.println(rows_read); + System.out.print("SQL for retrieving the messages: "); + System.out.println(msg_retrieval); + System.out.print("SQL for removing the messages : "); + System.out.println(msg_removal); + } + + stmt1 = con.prepareStatement(msg_retrieval); + System.out.println("\n" + "Executing " + msg_retrieval); + + // message retrivel + rs2 = stmt1.executeQuery(); + + // retrieving the resultset + while(rs2.next()) + { + // retrieving the sqlcode + sqlcode = rs2.getString(1); + + //retrieving the error message + msg = rs2.getString(2); + + System.out.println("Sqlcode : " +sqlcode); + System.out.println("Msg : " +msg); + } + + System.out.println("\n Executing " + msg_removal); + callStmt2 = con.prepareCall(msg_removal); + + // executing the message retrivel + callStmt2.execute(); + + System.out.println("\n Executing DROP TABLE ORG_IMPORT"); + stmt2 = con.createStatement(); + stmt2.executeUpdate("DROP TABLE ORG_IMPORT"); + } + catch(Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + //closing the statements and resultset + callStmt1.close(); + callStmt2.close(); + stmt1.close(); + stmt2.close(); + rs1.close(); + rs2.close(); + + // roll back any changes to the database made by this sample + con.rollback(); + + // closing the connection + con.close(); + } + catch (Exception x) + { + System.out.print(x); + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } + } // main +} // AdmCmdImport diff --git a/java/jdbc/AdmCmdOnlineBackup.java b/java/jdbc/AdmCmdOnlineBackup.java new file mode 100644 index 0000000..483b080 --- /dev/null +++ b/java/jdbc/AdmCmdOnlineBackup.java @@ -0,0 +1,158 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: AdmCmdOnlineBackup.java +// +// SAMPLE: Use the stored procedure ADMIN_CMD to do +// Online Backup +// +// The sample should be run using the following steps: +// 1. Create the "sample" database using db2sampl command +// +// 2. Set the DB CFG parameter LOGARCHMETH1 to LOGRETAIN +// +// 3. Set the DB CFG parameter LOGARCHMETH2 to OFF +// +// 4. Do an offline BACKUP of SAMPLE database +// +// 5. Compile the program with the following command: +// javac AdmCmdOnlineBackup.java +// +// 6. Run this sample with the following command: +// java AdmCmdOnlineBackup +// The path being given for backup should be an absolute path. +// +// Note: User needs either SYSADM, SYSCTRL or SYSMAINT authorization to set +// the DB CFG parameters & for backing up the database. +// +// JAVA 2 CLASSES USED: +// CallableStatement +// ResultSet +// +// Classes used from Util.java are: +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +//Run: java [] +// or +// java [] +// +// OUTPUT FILE: AdmCmdOnlineBackup.out (available in the online +// documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class AdmCmdOnlineBackup +{ + public static void main(String argv[]) + { + + System.out.print("THIS SAMPLE SHOWS HOW TO DO ONLINE BACKUP "); + System.out.println("USING ADMIN_CMD."); + Connection con = null; + CallableStatement callStmt = null; + ResultSet rs = null; + + if (argv.length < 1) + { + System.out.print("\n Usage: java AdmCmdOnlineBackup \n"); + } + else + { + try + { + // initialize DB2Driver and establish database connection. + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + // prepare the CALL statement for ADMIN_CMD + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt = con.prepareCall(sql); + + // execute database backup to the specified path + String param = "BACKUP DB SAMPLE TO " + argv[0].trim(); + + // set the input parameter + callStmt.setString(1, param); + + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + // call the stored procedure + callStmt.execute(); + + // get the result set + rs = callStmt.getResultSet(); + + if (rs.next()) + { + // getting the time taken for the database backup + String backupTime = rs.getString(1); + System.out.print("\nTimestamp for the backup image is = "); + System.out.println(backupTime); + } + + System.out.println("\nOnline backup completed successfully"); + } + catch(Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + // close the resultset and callStmt + rs.close(); + callStmt.close(); + + // roll back any changes to the database made by this sample + con.rollback(); + + // closing the connection + con.close(); + } + catch (Exception x) + { + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } // else + } // main +} // AdmCmdOnlineBackup diff --git a/java/jdbc/AdmCmdQuiesce.java b/java/jdbc/AdmCmdQuiesce.java new file mode 100644 index 0000000..6898258 --- /dev/null +++ b/java/jdbc/AdmCmdQuiesce.java @@ -0,0 +1,152 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: AdmCmdQuiesce.java +// +// SAMPLE: How to quiesce tablespace and database using ADMIN_CMD +// +// JAVA 2 CLASSES USED: +// CallableStatement +// +// Classes used from Util.java are: +// Db +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +//Run: java [] +// or +// java [] +// +// OUTPUT FILE: AdmCmdQuiesce.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.*; // JDBC classes +import java.lang.*; +import java.util.*; +import java.sql.*; + +class AdmCmdQuiesce +{ + + public static void main(String argv[]) + { + Connection con = null; + + try + { + Db db = new Db(argv); + + System.out.print("\nTHIS SAMPLE SHOW TO QUIESCE TABLESPACES"); + System.out.print("AND DATABASE USING ADMIN_CMD.\n"); + + // connect to the 'sample' database + db.connect(); + con = db.con; + + // prepare the CALL statement for ADMIN_CMD + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + CallableStatement callStmt = con.prepareCall(sql); + + // quiesce tablespaces for empoyee table + String param = "QUIESCE TABLESPACES FOR TABLE EMPLOYEE EXCLUSIVE"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + + System.out.print("The quiesce tablespaces for employee "); + System.out.print("table done successfully\n"); + + // quiesce reset of tablespaces of employee table + param = "QUIESCE TABLESPACES FOR TABLE EMPLOYEE RESET"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + + System.out.print("The quiesce reset of tablespaces "); + System.out.print("done successfully\n"); + + // quiesce database + param = "QUIESCE DATABASE IMMEDIATE"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.println("The quiesce database done successfully."); + + // unquiesce database + param = "UNQUIESCE DB"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.println("The unquiesce database done successfully."); + + // close the callStmt + callStmt.close(); + + // rollback changes + con.rollback(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + try + { + con.rollback(); + con.close(); + } + catch (Exception x) + { } + + e.printStackTrace(); + } + } // main +} // AdmCmdQuiesce diff --git a/java/jdbc/AdmCmdUpdateCfg.java b/java/jdbc/AdmCmdUpdateCfg.java new file mode 100644 index 0000000..a9f448c --- /dev/null +++ b/java/jdbc/AdmCmdUpdateCfg.java @@ -0,0 +1,160 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: AdmCmdUpdateCfg.java +// +// SAMPLE: How to update and reset the Database configuration and Database +// Manager Configuration Parameters +// +// JAVA 2 CLASS USED: +// CallableStatement +// +// Class used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +//Run: java [] +// or +// java [] +// +// OUTPUT FILE: AdmCmdUpdateCfg.out (available in the online +// documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.*; +import java.lang.*; +import java.util.*; +import java.sql.*; + +class AdmCmdUpdateCfg +{ + + public static void main(String argv[]) + { + Connection con = null; + Db db = null; + CallableStatement callStmt = null; + try + { + db = new Db(argv); + + System.out.print("\nTHIS SAMPLE SHOWS HOW TO UPDATE AND RESET THE"); + System.out.print(" DB CFGAND DBM CFG PARAMETERS USING ADMIN_CMD.\n"); + + // connect to the 'sample' database + db.connect(); + con = db.con; + + // prepare the CALL statement for ADMIN_CMD + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt = con.prepareCall(sql); + + // update the Database configuration Parameter dbheap to 1500 + String param = "UPDATE DATABASE CONFIGURATION USING DBHEAP 1500"; + + // set the input parameter + callStmt.setString(1, param); + + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + // call the stored procedure + callStmt.execute(); + + System.out.print("The DB CFG parameter is updated successfully.\n"); + + // update the Database Manager Configuration + // Parameter aslheapsz to 1000 + param = "UPDATE DATABASE MANAGER CONFIGURATION using ASLHEAPSZ 1000"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + + System.out.print("The DBM CFG parameter is updated successfully.\n"); + + // reset the DB CFG parameters for SAMPLE + param = "RESET DB CFG FOR SAMPLE"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + System.out.print("The DB CFG parameters for SAMPLE DB are"); + System.out.print(" resetted successfully.\n"); + + // reset the DBM CFG parameters + param = "RESET DBM CFG"; + + // set the input parameter + callStmt.setString(1, param); + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + + // call the stored procedure + callStmt.execute(); + + System.out.print("The DBM CFG parameters are resetted successfully\n"); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + // close the callStmt + callStmt.close(); + + // roll back any changes to the database made by this sample + con.rollback(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception x) + { + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } // main +} // AdmCmdUpdateCfg diff --git a/java/jdbc/Applt.html b/java/jdbc/Applt.html new file mode 100644 index 0000000..cc358ba --- /dev/null +++ b/java/jdbc/Applt.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + DB2 SQLJ Sample Applet + + + +

DB2 SQLJ Sample Applet

+
+ + + + + + +
+ + + diff --git a/java/jdbc/Applt.java b/java/jdbc/Applt.java new file mode 100644 index 0000000..7ee7c12 --- /dev/null +++ b/java/jdbc/Applt.java @@ -0,0 +1,175 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Applt.java +// +// SAMPLE: A Java applet that use JDBC JCC driver to access a database // +// +// This sample shows how to write a Java Applet that uses the +// JDBC Type 4 driver to access a DB2 database. +// +// This sample uses JDBC Type 4 driver to connect to +// the "sample" database. Run this sample using the +// following steps: +// 1. Create and populate the "sample" database with the following +// command: db2sampl +// +// 2. Customize Applt.html with your server, port, user ID, and +// password. Refer to Applt.html for details. +// +// 3. Compile the program with the following command: +// javac Applt.java +// +// Alternatively, you can compile the program with the following +// command if you have a compatible make/nmake program on +// your system: +// make/nmake Applt +// +// 4. Ensure that your working directory is accessible by your web +// browser. If it is not, copy Applt.class and Applt.html into +// a directory that is accessible. +// +// 5. Copy sqllib\java\db2jcc.jar on +// Windows or sqllib/java/db2jcc.jar on UNIX, into the same +// directory as Applt.class and Applt.html. +// +// 6. To run this sample, start your web browser (which must support +// Java 1.3) and load Applt.html on your client machine. +// You can view it locally with the following command: +// appletviewer Applt.html +// +// +// SQL Statements USED: +// SELECT +// UPDATE +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import java.awt.*; +import java.applet.Applet; + +public class Applt extends Applet +{ + Connection con; + + public void init() + { + try + { + // get parameter values from the html page + String server = getParameter("server"); + String port = getParameter("port"); + + // construct the URL (sample is the database name) + String url = "jdbc:db2://"+server+":"+port+"/sample"; + + String userid = getParameter("userid"); + String password = getParameter("password"); + + // use driverType=4 + + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database with userid and password + con = DriverManager.getConnection(url, userid, password); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public void paint(Graphics g) + { + try + { + // retrieve data from database + g.drawString( + "First, let's retrieve some data from the database...", 10, 10); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM employee"); + g.drawString("Received results:", 10, 25); + + // display the result set + // rs.next() returns false when there are no more rows + int y = 50; + int i = 0; + while (rs.next() && (i < 2)) + { + i++; + String a= rs.getString(1); + String str = rs.getString(2); + String oneLine = " empno= " + a + " firstname= " + str; + g.drawString(oneLine, 20, y); + y = y + 15; + } + stmt.close(); + + // update the database + g.drawString("Now, update the database...", 10, 100); + stmt = con.createStatement(); + int rowsUpdated = stmt.executeUpdate( + "UPDATE employee SET firstnme = 'SHILI' WHERE empno = '000010'"); + + // display the number of rows updated + String msg = "Updated " + rowsUpdated; + + if (1 == rowsUpdated) + { + msg = msg +" row."; + } + else + { + msg = msg +" rows."; + } + y = y + 40; + g.drawString(msg, 20, y); + + stmt.close(); + + // rollback the update + y = y + 40; + g.drawString("Now, rollback the update...", 10, y); + con.rollback(); + y = y + 15; + g.drawString("Rollback done.", 10, y); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} // Applt + diff --git a/java/jdbc/Array_Stack.java b/java/jdbc/Array_Stack.java new file mode 100644 index 0000000..9c213a9 --- /dev/null +++ b/java/jdbc/Array_Stack.java @@ -0,0 +1,148 @@ +//**************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//**************************************************************************** +// +// SAMPLE FILE NAME: array_stack.java +// +// PURPOSE: To demonstrate the new ARRAY type and functions CARDINALITY, +// TRIM_ARRAY and UNNEST. +// +// USAGE SCENARIO: The Sample will show use of new ARRAY type in +// implementation of Stack using stored procedures. A Stack follows last in +// first out strategy to insert and retrieve values. This sample implements +// methods to push, pop and select the top value from the Stack. Stacks can +// be used to store logs for different operations of an application. These +// logs can later be written to disk or destroyed when the application is +// closed. Stacks can also be used to store intermediate results while solving +// complex mathematical expressions. +// +// PREREQUISITE: Call the script stack_functions.db2 to register the +// procedures required for stack operations. +// +// db2 -td@ -vf stack_functions.db2 +// +// EXECUTION: javac Array_Stack.java +// java Array_Stack +// +// INPUTS: NONE +// +// OUTPUT: Creation of object of Array type ,int_stack, in database. +// Stack values are displayed along with the values returned by pop +// and top methods. +// +// OUTPUT FILE: Array_Stack.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// CALL +// +//*************************************************************************** +// For more information about the command line processor (CLP) scripts, +// see the README file. +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, building, and running DB2 +// applications, visit the DB2 application development website: +// http://www.software.ibm.com/data/db2/udb/ad +// +//************************************************************************** +// +// SAMPLE DESCRIPTION +// +//************************************************************************** +// 1. Call the "use_stack" store procedure. +//************************************************************************* +import java.sql.*; + +public class Array_Stack +{ + public static void main(String argv[]) + { + + int val1,val2; + Integer[] stack=new Integer[3]; + String url = "jdbc:db2:sample"; + int percentage=10; + com.ibm.db2.jcc.DB2Connection con = null; + ResultSet rs; + try + { + + // connect to the db + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + // connect to the 'sample' database + con = (com.ibm.db2.jcc.DB2Connection) DriverManager.getConnection( url ); +//***************************************************************************** +// +// 1. Call the "use_stack" store procedure. +// +//***************************************************************************** + + // prepare the call statement + String sql = "CALL use_stack(?, ?, ?)"; + CallableStatement callStmt = con.prepareCall(sql); + + // Create an ARRAY type + stack[0]=new Integer(1); + stack[1]=new Integer(2); + stack[2]=new Integer(3); + java.sql.Array stackArray=con.createArrayOf("INTEGER",stack); + + // set IN parameters + callStmt.setArray(1,stackArray ); + + // Register OUT parameter + callStmt.registerOutParameter(2, java.sql.Types.INTEGER); + callStmt.registerOutParameter(3, java.sql.Types.INTEGER); + + // call the procedure + callStmt.execute(); + + // Retrive the OUT parameter + val1=callStmt.getInt(2); + val2=callStmt.getInt(3); + + // Retrieve the result set + rs=callStmt.getResultSet(); + System.out.println("Stack Contents"); + while(rs.next()) + { + System.out.println(rs.getInt(1)); + } + System.out.println("Result of the POP operation : " +val1); + System.out.println("Result of the TOP operation : " +val2); + + // cleanup + callStmt.close(); + con.close(); + } + catch (Exception e) + { + try + { + con.rollback(); + con.close(); + } + catch (Exception x) + { } + + e.printStackTrace(); + } + } // end main +} + diff --git a/java/jdbc/Arrays_Sqlpl.java b/java/jdbc/Arrays_Sqlpl.java new file mode 100644 index 0000000..383b64c --- /dev/null +++ b/java/jdbc/Arrays_Sqlpl.java @@ -0,0 +1,163 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// SAMPLE FILE NAME: Arrays_Sqlpl.java +// +// PURPOSE: To demonstrate the new ARRAY type and functions UNNEST and +// ARRAY_AGG. +// +// USAGE SCENARIO: Scenario is based on the employee data in sample database. +// The management has selected best projects based on the projects performance +// in the current year and decided to give the employees of these projects a +// performance bonus. The bonus will be a specific percentage of employee +// salary. +// +// An array of varchar is used to store the selected project names. +// +// A stored procedure is implemented to calculate the bonus. The stored +// procedure takes this array and percentage value as input. +// +// PREREQUISITE: Run the script bonus_calculate.db2 using the following +// command +// db2 -td@ -vf bonus_calculate.db2 +// This script do the following +// +// 1. Create the ARRAY types. +// 2. Create the table "bonus_temp". +// 3. Create a stored procedure to calculate the bonus. +// 3.1 Select the ID and corresponding bonus values in +// corresponding ARRAY type "employees" and "bonus" respectively +// using aggregate function ARRAY_AGG. +// 3.2 Use UNNEST function to select the ARRAY elements from ARRAY +// variables and insert the same in "bonus_temp" table. +// +// EXECUTION: javac Arrays_Sqlpl.java +// java Arrays_Sqlpl +// +// INPUTS: NONE +// +// OUTPUT: The employee IDs and the corresponding bonus will be calculated and +// stored in a table. An employee can work for multiple projects so multiple +// entries are possible for the same employee id in this table. +// +// OUTPUT FILE: Arrays_Sqlpl.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// CREATE TABLE +// SELECT +// DROP +// CALL +// +//***************************************************************************** +// For more information about the command line processor (CLP) scripts, +// see the README file. +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, building, and running DB2 +// applications, visit the DB2 application development website: +// http://www.software.ibm.com/data/db2/udb/ad +// +//***************************************************************************** +// +// SAMPLE DESCRIPTION +// +//***************************************************************************** +// 1. Call the stored procedure to calculate the bonus. Input to this +// stored procedure will be the ARRAY of all the projects which are +// applicable for the bonus. +// 2. Select the data from the table "bonus_temp". +//***************************************************************************** + +import java.sql.*; + +public class Arrays_Sqlpl +{ + public static void main(String argv[]) + { + String[] projects=new String[10]; + String url = "jdbc:db2:sample"; + int percentage=10; + com.ibm.db2.jcc.DB2Connection con = null; + + try + { + + // connect to the db + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + // connect to the 'sample' database + con = (com.ibm.db2.jcc.DB2Connection) DriverManager.getConnection( url ); + Statement stmt=con.createStatement(); + +//***************************************************************************** +// +// 1. Call the stored procedure to calculate the bonus. The input to this +// stored procedure will be the ARRAY of all the projects which are +// applicable for bonus. +//***************************************************************************** + + // Prepare the call statement + String sql = "CALL bonus_calculate(?, ?)"; + CallableStatement callStmt = con.prepareCall(sql); + + // Create an SQL Array + projects[0] = "AD3111"; + projects[1] = "IF1000"; + projects[2] = "MA2111"; + java.sql.Array projectArray=con.createArrayOf("VARCHAR",projects); + + // set IN parameters + callStmt.setArray(1, projectArray); + callStmt.setInt(2,percentage); + + // call the procedure + callStmt.execute(); + +//***************************************************************************** +// +// 2. Select the data from the table "bonus_temp". +// +//***************************************************************************** + + String selectStmt = "SELECT * FROM bonus_temp"; + ResultSet rs = stmt.executeQuery(selectStmt); + while(rs.next()) + { + System.out.println("Employee ID :"+rs.getString(1)); + System.out.println("Bonus :"+rs.getDouble(2)); + } + + // cleanup + callStmt.close(); + con.close(); + } + catch (Exception e) + { + try + { + con.rollback(); + con.close(); + } + catch (Exception x) + { } + + e.printStackTrace(); + } + } // end main +} // end Arrays_Sqlpl + diff --git a/java/jdbc/Cgtt.java b/java/jdbc/Cgtt.java new file mode 100644 index 0000000..e7ce8ac --- /dev/null +++ b/java/jdbc/Cgtt.java @@ -0,0 +1,346 @@ +//----------------------------------------------------------------------------- +// (c) Copyright IBM Corp. 2008 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//----------------------------------------------------------------------------- +// +// SOURCE FILE NAME: Cgtt.java +// +// SAMPLE: +// The sample demonstrates the following: +// i) Use of Created Temporary table (CGTT) to store intermediate +// results. +// ii) Use of Created Temporary table with Procedures, Functions, Triggers +// and Views. +// +// PREREQUISITE: +// 1) Sample database is setup on the machine. +// 2) Valid system authorization IDs and password. +// bob with "bob12345" +// joe with "joe12345" +// 3) Execute 'CreateCGTT.db2' script. This script creates all database +// objects required for the executing this sample and GRANTS required +// privileges to bob an joe. +// +// +// USAGE SCENARIO: +// The scenario deals with the employee tax computation process. +// At the end of a financial year, the payroll department computes tax +// payable by all the employees. The sample demonstrates the use of +// created temporary table to store intermediate results during the tax +// calculation process. The database contains employee, and payroll tables. +// The employee table contains employee details and the payroll table +// contains details of employee salary and the total tax payable by the +// employee based on his income (salary + bonus) in a finnancial year. +// +// Each employee gets tax exemption for salary upto 100,000 +// the proof for exemption is submitted at the end of the financial +// year. At the beginning of financial year the tax payable by an employee +// is calculated based on the employees income and the 100,000 exemption +// limit. At the end of the year after all the employees of a department +// have submitted their tax proofs, the tax calculation process for the +// department is trigered. The tax process updates the payroll table with +// the total tax and the balance tax payable. An Income Tax(IT) statement +// is also generated for each employee of the department. +// +// A TRIGGER is invoked after tax proofs is submitted by all +// the employee of a department. The trigger populates the created temporary +// table with the details of the employee and his income (salary + any bonus) +// details and calls a procedure to calculate the tax. All the intermediate +// results of tax calculation are updated in the CGTT. After the tax calculation +// is complete another procedure updates the payrool table with the tax data +// from the created temporary table. A function generates the IT sheet for +// all the employees. +// +// SAMPLE EXECUTION: +// +// 1) Execute 'CreateCGTT.db2' to create required database objects using +// command : +// db2 -td@ -vf CreateCGTT.db2 +// 2) Compile and Execute this sample using commands : +// i) javac Cgtt.java +// ii) java Cgtt.java +// 3) Execute 'DropCGTT.db2' to drop all the database objects created by the +// sample : +// db2 -td@ -vf DropCGTT.db2 +// +// SQL STATEMENTS USED: +// 1) CREATE GLOBAL TEMPORARY TABLE +// 2) CREATE INDEX +// 3) CREATE VIEW +// 4) CREATE TRIGGER +// 5) CREATE PROCEDURE +// 6) CREATE FUNCTION +// 7) CALL +// 8) RUNSTATS +// 9) TRUNCATE TABLE +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +//----------------------------------------------------------------------------- +// The sample has seven major steps: +// +// ************************************************************************* // +// Step1 to Step 5 creates all the database objects required for the // +// execution of the sample. // +// Execute 'CreateCGTT.db2' script to create the required database // +// objects. // +// To execute 'CreateCGTT.db2' issue the command : // +// db2 -td@ -vf CreateCGTT.db2 // +// ************************************************************************* // +// Step1: Create table 'payroll' and populate it. +// Step2: Create the following objects: +// - Create a CGTT 'tax_cal'. +// - View 'ViewOnCgtt' based on 'tax_cal'. +// - Index 'IndexOnCgtt' based on 'tax_cal'. +// Step3: Create three procedures and a function +// 1) tax_compute : Calculates the tax payable by an +// employee and returns the value to the +// CALLER. +// 2) initial_tax_compute: Calculates the tax payable by an +// employee initially with a tax +// exemption of 100,000. This procedure +// calls the function 'tax_compute' to +// do the calculation. +// 3) final_tax_compute : Calculates the tax payable by an +// employee based on his or her total +// income (salary + any bonus) and the +// tax proofs he or she submits. This +// procedure calls the function +// 'tax_compute' to do the calculation. +// 4) update : Updates the created temporary table +// 'tax_cal' with the final results, To +// update the 'payroll' table to reflect +// the created temporary table. +// Step4: Create a function 'printITSheet' to print the IT sheet for the +// employees, using the data in the created temporary table 'tax_cal' +// through the view 'ViewOnCgtt'. +// Step5: Create a Trigger 'tax_update' on 'Payroll' table to start the +// tax calculation process. +// +// ************************************************************************* // +// Step6 - calculation of tax to be paid by the employees of two // +// departments 'D11' and 'D21' is done by this sample 'Cgtt.java'. // +// ************************************************************************* // +// Step6: Start the tax computation process for two departments. +// +// ************************************************************************* // +// Step7 cleans up all the database objects created by 'CreateCGTT.db2'// +// Execute 'DropCGTT.db2' script to drop all the database objects // +// // +// To execute 'DropCGTT.db2' issue the command : // +// db2 -td@ -vf DropCGTT.db2 // +// ************************************************************************* // +// Step7: Run the Clean up scripts. +//----------------------------------------------------------------------------- + +import java.sql.*; + +class Cgtt +{ + static Db db; + public static void main(String argv[]) + { + try + { + Connection con1 = null, con2 = null, con3 = null; + String user1 = "joe"; + String password1 = "joe12345"; + String server = argv[0]; + String port=argv[1]; + + + // connect to sample database + con1 = ConHandler(user1,password1,server,port); + con1.setAutoCommit(false); + CalTax(con1,"D11",user1); + + String user2 = "bob"; + String password2 = "bob12345"; + con2 = ConHandler(user2,password2,server,port); + con2.setAutoCommit(false); + CalTax(con2,"D21",user2); + db.disconnect(); + } + catch (Exception e) + { + System.out.println("Error Msg: "+ e.getMessage()); + } + } + + + + public static Connection ConHandler(String user, String password, String serverAdd, String port) + { + Connection con = null; + String args[]=new String[4]; + args[1]=port; + args[0]=serverAdd; + args[2]=user; + args[3]=password; + try + { + db=new Db(args); + } + catch (Exception e) + { + System.out.println(" Error loading DB2 Driver...\n"); + System.out.println(e); + System.exit(1); + } + + try + { + con = db.connect(); + con.setAutoCommit(false); + } + catch (Exception e) + { + System.out.println("Error while Connecting to sample database."); + System.err.println(e) ; + System.exit(1); + } + return con; + } + + + static void CalTax(Connection con, String deptnum, String user) + { + try + { + System.out.print("\n-----------------------------------------------------"+ + "----------------------------------------------------------------------\n"); + System.out.print("Employee of the company '"+user+"' calculates "+ + "the tax for department '"+deptnum+"'...\n"); + System.out.print("'"+user+"' updates the 'payroll' table as per "+ + "the tax proof submitted by the employees of "+ + "department '"+deptnum+"'...\n"); + System.out.print("As per the scenario, all employees of '"+deptnum+"' submit "+ + "tax proofs for '50000'...\n"); + System.out.print("\n------------------------------------------------------"+ + "----------------------------------------------------------------------\n\n"); + + String st1 = "UPDATE cgtt.payroll SET tax_proof = 50000 "+ + "WHERE deptno = '"+deptnum+"'"; + + + System.out.print("\n'"+user+"' triggers the process of tax "+ + "calculation by updating the 'calculate_tax' to one "+ + "for all employees of \n department '"+deptnum+"' after all the "+ + "employees of the department submit the tax proof\n"); + String st2 = "UPDATE cgtt.payroll SET calculate_tax = 1 "+ + "WHERE deptno = '"+deptnum+"'"; + + + System.out.print("Once tax calculation is complete, '"+user+"' "+ + "set the 'calculate_tax' column back to zero\n"); + String stn = "UPDATE cgtt.payroll SET calculate_tax = 0 "; + + + System.out.println("\nUPDATE payroll SET tax_proof = 50000 "+ + "WHERE deptno = '"+deptnum+"'\n "); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate(st1); + + + System.out.println("\nUPDATE payroll SET calculate_tax = 1 "+ + "WHERE deptno = '"+deptnum+"'\n \n"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate(st2); + + + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate(stn); + + Process(con); + PrintITReport(con); + con.commit(); + } + catch(Exception e) + { + String Message = e.getMessage(); + System.out.println(Message); + } + } + + + static void Process(Connection con) + { + try + { + java.sql.CallableStatement cstmt; + String Proc = "CALL cgtt.update()"; + cstmt = con.prepareCall(Proc); + cstmt.execute(); + } + catch(Exception e) + { + String Message = e.getMessage(); + System.out.println(Message); + } + } + + static void PrintITReport(Connection con) + { + try + { + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM "+ + "TABLE(cgtt.printITSheet()) as ITSheet"); + + ResultSetMetaData rsm = rs.getMetaData(); + int columnCount = rsm.getColumnCount(); + int i=1; + while(i <= columnCount ) + { + System.out.print(rsm.getColumnName(i)+"\t "); + i++; + } + + System.out.print("\n-----------------------------------------------------"+ + "----------------------------------------------------------------------\n"); + while(rs.next()){ + + int j=1; + while(j <= columnCount ) + { + System.out.print(rs.getString(rsm.getColumnName(j))+"\t "); + j++; + } + System.out.print("\n"); + } + rs.close(); + stmt.close(); + System.out.print("\n-----------------------------------------------------"+ + "----------------------------------------------------------------------\n"); + } + catch(Exception e) + { + String Message = e.getMessage(); + System.out.println(Message); + } + } + +} diff --git a/java/jdbc/CreateCGTT.db2 b/java/jdbc/CreateCGTT.db2 new file mode 100644 index 0000000..f85d5d6 --- /dev/null +++ b/java/jdbc/CreateCGTT.db2 @@ -0,0 +1,425 @@ +------------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +------------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: CreateCGTT.db2 +-- +-- SAMPLE: +-- The sample demonstrates the following: +-- i) Use of Created Temporary table (CGTT) to store intermediate +-- results. +-- ii) Use of Created Temporary table with Procedures, Functions, Triggers and Views. +-- +-- PREREQUISITE: +-- 1)Sample database is setup on the machine. +-- +-- Note: Use following command to execute the sample: +-- db2 -td@ -vf CreateCGTT.db2 +-- +-- SQL STATEMENTS USED: +-- 1) CREATE GLOBAL TEMPORARY TABLE +-- 2) CREATE INDEX +-- 3) CREATE VIEW +-- 4) CREATE TRIGGER +-- 5) CREATE PROCEDURE +-- 6) CREATE FUNCTION +-- 7) CALL +-- 8) RUNSTATS +-- +------------------------------------------------------------------------------- + +-- Connect to the sample database + +CONNECT TO sample@ + +-- GRANT privileges on 'employee' table to Bob and Joe +GRANT SELECT, INSERT, UPDATE ON TABLE employee TO USER joe@ +GRANT SELECT, INSERT, UPDATE ON TABLE employee TO USER bob@ + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- Step1: Create table 'payroll' and populate it. -- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +-- Create tablespaces 'TbspacePayroll' & 'TbspaceCgtt'. +-- Table 'Payroll' will be placed in tablespace 'TbspacePayroll' and +-- 'cgtt.tax_cal' will be placed in tablespace 'TbspaceCgtt' + +CREATE BUFFERPOOL BufForSample IMMEDIATE PAGESIZE 4k@ +CREATE USER TEMPORARY TABLESPACE TbspaceCgtt PAGESIZE 4k + BUFFERPOOL BufForSample@ +CREATE REGULAR TABLESPACE TbspacePayroll PAGESIZE 4k + BUFFERPOOL BufForSample@ + + + +-- Create 'payroll' table to store details about employees income and tax. + +CREATE TABLE cgtt.payroll (empid CHARACTER(6) REFERENCES employee(empno), + salaryPA DECFLOAT, + tax_payable DECFLOAT, + tax_exempted DECFLOAT, + tax_proof DECFLOAT, + tax_to_be_paid DECFLOAT, + deptno CHARACTER(3), + calculate_tax INT) IN TbspacePayroll@ + +-- Insert employee details into 'payroll' table from the employee table of +-- the sample database + +INSERT INTO cgtt.payroll(empid, deptno, salaryPA) +(SELECT empno,workdept, (salary * 12) AS salary FROM employee)@ + +-- Initially, the tax exemption for all the employees is 100,000. Update the +-- 'payroll' table to set the tax_exempted column. + +UPDATE cgtt.payroll SET tax_exempted = 100000@ + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-- Step 2: Create the following objects -- +-- - Created temporary table 'tax_cal'. -- +-- - View 'ViewOnCgtt' based on 'tax_cal'. -- +-- - Index 'IndexOnCgtt' based on 'tax_cal' -- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- Create Temporary table (CGTT) to store the intermediate results -- +-- while calculating the tax_payable by an employee based on the tax proof. -- +-- For ease of demonstration, set tax proof submitted by all the employees to -- +-- 50,000. -- +-- Create CGTT 'cgtt.tax_cal' as join of 'employee' and 'payroll' table. -- +-------------------------------------------------------------------------------- + +CREATE GLOBAL TEMPORARY TABLE cgtt.tax_cal AS + (SELECT e.empno, e.firstnme, e.lastname, e.birthdate, e.bonus, e.comm, + p.salarypa, + p.tax_payable, p.tax_exempted, p.tax_proof, p.tax_to_be_paid,p.deptno + FROM employee AS e, cgtt.payroll AS p + WHERE e.empno = p.empid) + DEFINITION ONLY ON COMMIT PRESERVE ROWS + IN TbspaceCgtt@ + +-- Create INDEX 'IndexOnCgtt' based on 'tax_cal'. +CREATE INDEX cgtt.indexOnId ON cgtt.tax_cal(empno) ALLOW REVERSE SCANS@ + +-- Create View 'ViewOnCgtt' based on 'tax_cal', to print the IT sheet +CREATE VIEW cgtt.ViewOnCgtt AS + SELECT empno, firstnme, lastname, birthdate, deptno,bonus, comm, salarypa, + tax_to_be_paid + FROM cgtt.tax_cal@ + + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- Step3: Create three procedures and a function -- +-- 1) tax_compute : Calculates the tax payable by an -- +-- employee and returns the value to -- +-- the CALLER. -- +-- 2) initial_tax_compute: Calculates the tax payable by an -- +-- employee initially with a tax -- +-- exemption of 100,000. This -- +-- procedure calls the function -- +-- 'tax_compute' to do the calculation.- +-- 3) final_tax_compute : Calculates the tax payable by an -- +-- employee based on his or her total -- +-- income (salary + any bonus) and the-- +-- tax proof she or she submits. This -- +-- procedure calls the function -- +-- 'tax_compute' to do the calculation.- +-- 4) update : Updates the created temporary table-- +-- 'tax_cal' with the final results, -- +-- To update the 'payroll' table to -- +-- reflect the created temporary table.- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +-- Create function 'tax_compute' to calculate the tax_payable by an employee. +-- Tax is calculated as follows : +-- 100,000 - No tax +-- upto 500,000 - 10 percent tax +-- upto 1,000,000 - 20 percent tax +-- Above 1,000,000 - 30 percent tax +-- Any extra bonus - 30 percent tax on bonus +-- For exemption of tax of 100,000 employee has to submit tax proofs. If not, +-- employee will be exempted only for the amount, for which he submits proofs. + +CREATE FUNCTION cgtt.tax_compute(salarypa DECFLOAT, + exempted DECFLOAT,awarded_pay DECFLOAT) +SPECIFIC common_calculator +RETURNS DECFLOAT +NO EXTERNAL ACTION +DETERMINISTIC +BEGIN + DECLARE payable_tax DECFLOAT; + SET payable_tax = salarypa - exempted; + + IF payable_tax <= 500000 THEN + SET payable_tax = payable_tax * 0.10; + ELSEIF payable_tax > 500000 AND payable_tax <= 1000000 THEN + SET payable_tax = payable_tax * 0.20; + ELSEIF payable_tax > 1000000 THEN + SET payable_tax = payable_tax * 0.30; + END IF; + + SET payable_tax = payable_tax + (awarded_pay * 0.30); + RETURN payable_tax; +END@ + + +-- Create procedure 'tax_pay' to calculate the tax payable by the employees. +-- For a finnancial year a tax exemption of +-- 100,000 is given to all the employees. +-- This procedure calls the function 'tax_compute' to calculate +-- tax. + +CREATE PROCEDURE cgtt.initial_tax_compute() +SPECIFIC initialTax +LANGUAGE SQL +BEGIN + DECLARE id CHARACTER(6); + DECLARE at_end SMALLINT DEFAULT 0; + DECLARE salary DECFLOAT; + DECLARE payable_tax DECFLOAT; + DECLARE not_found CONDITION for SQLSTATE '02000'; + + DECLARE IterateOverEmpRecord CURSOR WITH HOLD FOR SELECT empid,salaryPA FROM cgtt.payroll; + DECLARE CONTINUE HANDLER for not_found SET at_end = 1; + + OPEN IterateOverEmpRecord; + + ins_loop: LOOP + FETCH IterateOverEmpRecord INTO id,salary; + + IF at_end = 1 THEN + LEAVE ins_loop; + ELSE + + UPDATE cgtt.payroll SET tax_payable = cgtt.tax_compute(salary,100000,0) WHERE empid = id; + COMMIT; + ITERATE ins_loop; + END IF; + END LOOP; + + CLOSE IterateOverEmpRecord; +END@ + +-- Create procedure 'update' to update the CGTT 'cgtt.tax_cal' with the tax +-- payable by an employee, calculated by the procedure 'final_tax_compute'. + +CREATE PROCEDURE cgtt.update() +SPECIFIC updater +LANGUAGE SQL +BEGIN + DECLARE at_end SMALLINT DEFAULT 0; + DECLARE id CHARACTER(6); + DECLARE tax_left DECFLOAT; + DECLARE tax_p DECFLOAT; + DECLARE not_found CONDITION FOR SQLSTATE '02000'; + + DECLARE UpdateCGTT CURSOR WITH HOLD FOR + SELECT empno,tax_to_be_paid,tax_payable + FROM cgtt.tax_cal; + DECLARE UpdatePayroll CURSOR WITH HOLD FOR + SELECT empno,tax_to_be_paid,tax_payable + FROM cgtt.tax_cal; + DECLARE CONTINUE HANDLER for not_found SET at_end = 1; + + OPEN UpdateCGTT; + + up_loop: LOOP + FETCH UpdateCGTT INTO id,tax_left,tax_p; + + IF at_end = 1 THEN + LEAVE up_loop; + ELSE + UPDATE cgtt.tax_cal SET tax_payable = tax_left, + tax_to_be_paid = tax_left - tax_p + WHERE empno = id; + ITERATE up_loop; + END IF; + END LOOP; + + CLOSE UpdateCGTT; + + SET at_end = 0; + OPEN UpdatePayroll; + + update_payroll: LOOP + FETCH UpdatePayroll INTO id,tax_left,tax_p; + + IF at_end = 1 THEN + LEAVE update_payroll; + ELSE + UPDATE cgtt.payroll SET tax_payable = tax_p, + tax_to_be_paid = tax_left + WHERE empid = id; + ITERATE update_payroll; + END IF; + END LOOP; + + CLOSE UpdatePayroll; + + +END@ + +-- Create procedure 'final_tax_compute' to select employee records from the +-- created temporary table 'cgtt.tax_cal' and call the function 'tax_compute' +-- to calculate the tax. + +CREATE PROCEDURE cgtt.final_tax_compute() +SPECIFIC finalTax +LANGUAGE SQL +BEGIN + DECLARE id CHARACTER(6); + DECLARE at_end SMALLINT DEFAULT 0; + DECLARE salary DECFLOAT; + DECLARE exempted DECFLOAT; + DECLARE proof DECFLOAT; + DECLARE awarded_pay DECFLOAT; + DECLARE bonus DECFLOAT; + DECLARE comm DECFLOAT; + DECLARE not_found CONDITION for SQLSTATE '02000'; + + DECLARE IterateOverEmpRecord CURSOR WITH HOLD FOR + SELECT empno,bonus,comm,salaryPA,tax_exempted,tax_proof FROM cgtt.tax_cal; + DECLARE CONTINUE HANDLER for not_found SET at_end = 1; + + OPEN IterateOverEmpRecord; + + ins_loop: LOOP + FETCH IterateOverEmpRecord INTO id, bonus, comm, salary, exempted, proof; + + IF at_end = 1 THEN + LEAVE ins_loop; + ELSE + IF exempted > proof THEN + SET exempted = proof; + END IF; + SET awarded_pay = bonus + comm; + + UPDATE cgtt.tax_cal SET tax_to_be_paid = cgtt.tax_compute(salary,exempted,awarded_pay) WHERE empno = id; + ITERATE ins_loop; + END IF; + END LOOP; + + CLOSE IterateOverEmpRecord; + +END@ + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- Step4: Create a function 'printITSheet' to print IT sheet for the -- +-- employees, using data in the created temporary table -- +-- 'cgtt.tax_cal' through the view 'ViewOnCgtt'. -- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +CREATE FUNCTION cgtt.printITSheet() +SPECIFIC ITSheet +RETURNS TABLE (empno CHARACTER(6), + firstnme VARCHAR(12), + lastname VARCHAR(15), + birthdate DATE, + bonus DECFLOAT, + comm DECFLOAT, + salarypa DECFLOAT, + tax_to_be_paid DECFLOAT) +LANGUAGE SQL +NO EXTERNAL ACTION +READS SQL DATA +RETURN + SELECT empno, firstnme, lastname, birthdate, bonus, comm, salarypa, tax_to_be_paid + FROM cgtt.ViewOnCgtt@ + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-- Step 5: Create Trigger 'tax_update' on 'Payroll' table to start the tax -- +-- calculation process. -- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- The trigger is invoked on update of calculate_tax column of payroll table. -- +-- The trigger populates the created temporary table 'tax_cal' and calls the -- +-- procedure 'final_tax_compute' to start tax computation process. -- +-------------------------------------------------------------------------------- + +CREATE TRIGGER cgtt.tax_update AFTER UPDATE OF calculate_tax ON cgtt.payroll +REFERENCING NEW TABLE AS new +FOR EACH STATEMENT +BEGIN ATOMIC + + INSERT INTO cgtt.tax_cal + (empno, firstnme, lastname, birthdate, bonus, comm, salarypa, tax_payable, + tax_exempted, tax_to_be_paid, tax_proof, deptno) + (SELECT e.empno, e.firstnme, e.lastname, e.birthdate, e.bonus, e.comm, + p.salarypa, p.tax_payable, p.tax_exempted, p.tax_to_be_paid, + p.tax_proof, p.deptno + FROM employee AS e, cgtt.payroll AS p + WHERE e.empno = p.empid AND p.tax_exempted > 0 AND p.deptno = + (SELECT DISTINCT deptno FROM cgtt.payroll WHERE calculate_tax = 1)); + + CALL cgtt.final_tax_compute(); +END@ + + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- Compute the tax initially to be paid by the employees -- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +-- Call the procedure 'tax_pay' to calculate the tax_payable +-- by an employee depending on his income and update the +-- 'payroll' table +CALL cgtt.initial_tax_compute()@ + +-- Execute RUNSTATS command to update the created temporary table 'cgtt.tax_cal' +-- to update statistics +RUNSTATS ON TABLE cgtt.tax_cal FOR indexes cgtt.IndexOnId@ + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- GRANT privileges to Bob and Joe on required database objects -- +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +-- GRANT privileges on 'cgtt.payroll' table to Bob and Joe +GRANT SELECT, INSERT, UPDATE ON TABLE cgtt.payroll TO USER joe@ +GRANT SELECT, INSERT, UPDATE ON TABLE cgtt.payroll TO USER bob@ + +-- GRANT privileges on 'cgtt.update' procedure to Bob and Joe +GRANT EXECUTE ON PROCEDURE cgtt.update TO USER joe@ +GRANT EXECUTE ON PROCEDURE cgtt.update TO USER bob@ + +-- GRANT privileges on 'cgtt.printITsheet' function to Bob and Joe +GRANT EXECUTE ON FUNCTION cgtt.printITsheet TO USER joe@ +GRANT EXECUTE ON FUNCTION cgtt.printITsheet TO USER bob@ + + + + + + + + diff --git a/java/jdbc/CreateEmployee.java b/java/jdbc/CreateEmployee.java new file mode 100644 index 0000000..3108369 --- /dev/null +++ b/java/jdbc/CreateEmployee.java @@ -0,0 +1,508 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: CreateEmployee.java +// +// SAMPLE: Create an employee record +// +// SQL Statements USED: +// INSERT +// +// Classes used from Util.java are: +// Db +// SqljException +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.* ; + +public class CreateEmployee +{ + // Empty Constructor for use in other programs + public CreateEmployee() + { + } + + public static void main(String[] args) + { + System.out.println(); + System.out.println("THIS SAMPLE CREATES A NEW EMPLOYEE RECORD."); + + Connection conn = null ; + Db db = null ; + // Use the db Class to get a connection + try + { + db = new Db(args); + db.connect(); + conn = db.con; + System.out.println("..............................................."); + } + catch(ClassNotFoundException cle) + { + System.out.println(" Driver class not found, please check the PATH and" + + " CLASSPATH system variables to ensure they are correct"); + } + catch(SQLException sqle) + { + System.out.println(" Could not open connection"); + sqle.printStackTrace(); + } + catch(Exception ne) + { + System.out.println(" Unexpected Error"); + ne.printStackTrace(); + } + //If a connection was properly obtained use it to get a new Employee + if(conn != null) + { + try + { + // Use the getEmployee method from below to create a new Employee + // with user input + Employee emp = getEmployee(); + // Use the Statement Object to Insert the new Employee into the + // Employee table + Statement st = conn.createStatement(); + System.out.println(" USE THE SQL STATEMENT\n INSERT"); + System.out.println(" TO INSERT DATA INTO A TABLE"); + System.out.println(" INSERT INTO EMPLOYEE VALUES('" + emp.getEmployeeNumber() + + "','" + emp.getFirstName() + + "','" + emp.getMiddleInitial() + + "','" + emp.getLastName() + + "','" + emp.getWorkDepartment() + + "','" + emp.getPhoneNumber() + + "','" + emp.getHireDate() + + "','" + emp.getJob() + + "'," + emp.getEducationLevel() + + ",'" + emp.getSex() + + "','" + emp.getBirthDate() + + "'," + emp.getSalary() + + "," + emp.getBonus() + + "," + emp.getCommission() + + ")"); + st.execute("INSERT INTO EMPLOYEE VALUES('" + emp.getEmployeeNumber() + + "','" + emp.getFirstName() + + "','" + emp.getMiddleInitial() + + "','" + emp.getLastName() + + "','" + emp.getWorkDepartment() + + "','" + emp.getPhoneNumber() + + "','" + emp.getHireDate() + + "','" + emp.getJob() + + "'," + emp.getEducationLevel() + + ",'" + emp.getSex() + + "','" + emp.getBirthDate() + + "'," + emp.getSalary() + + "," + emp.getBonus() + + "," + emp.getCommission() + + ")"); + // Close the Statement object + conn.commit(); + st.close(); + System.out.println(" Created new employee successfully"); + //System.out.println(" Rolling Back transactions"); + // Rollback all changes to the database so it is clean for other samples + //conn.rollback(); + //System.out.println(" Transaction Rolled Back"); + + } + catch(SQLException sqle) + { + System.out.println("Error while inserting new Employee"); + sqle.printStackTrace(); + } + /* + Use the finally clause to close connections, this ensures that they + are closed before the code exits. + */ + finally{ + System.out.println("..............................................."); + // Check if the Connection equals null (is valid) + if(conn!=null) + { + try + { + // Close the connection object, and disconnect using the db class + conn.close(); + db.disconnect(); + } + catch(Exception sqle) + { + System.out.println("Error closing connection"); + sqle.printStackTrace(); + } + } + } + } + else + { + System.out.println("Retry using correct format"); + } + } + + /* + getEmployee method takes user input and creates a new Employee object + using the Employee class + */ + private static Employee getEmployee() + { + // Create a new default Employee object + Employee emp = new Employee(); + try + { + // Fill all the Employee Class fields with user input + String info = null; + System.out.println("Enter new Employee Number (6 Characters):"); + if((info = getUserInput()) != null) + { + emp.setEmployeeNumber(info); + } + System.out.println("Enter Employee's First Name (12 Characters):"); + if((info = getUserInput()) != null) + { + emp.setFirstName(info); + } + System.out.println("Enter Employee's Middle Initial (1 Character):"); + if((info = getUserInput()) != null) + { + emp.setMiddleInitial(info); + } + System.out.println("Enter Employee's Last Name (15 Characters):"); + if((info = getUserInput()) != null) + { + emp.setLastName(info); + } + System.out.println("Enter Employee's Work Department (3 Characters):"); + if((info = getUserInput()) != null) + { + emp.setWorkDepartment(info); + } + System.out.println("Enter Employee's Phone Number (4 digits):"); + if((info = getUserInput()) != null) + { + emp.setPhoneNumber(info); + } + System.out.println("Enter Employee's Job (8 Characters):"); + if((info = getUserInput()) != null) + { + emp.setJob(info); + } + System.out.println("Enter Employee's Sex (M/F):"); + if((info = getUserInput()) != null) + { + emp.setSex(info); + } + System.out.println("Enter Employee's BirthDate (YYYY-MM-DD):"); + if((info = getUserInput()) != null) + { + emp.setBirthDate(info); + } + System.out.println("Enter Employee's HireDate (YYYY-MM-DD):"); + if((info = getUserInput()) != null) + { + emp.setHireDate(info); + } + System.out.println("Enter Employee's Education Level (1->20):"); + if((info = getUserInput()) != null) + { + emp.setEducationLevel(info); + } + System.out.println("Enter Employee's Salary (#######.##):"); + if((info = getUserInput()) != null) + { + emp.setSalary(info); + } + System.out.println("Enter Employee's Bonus (#######.##):"); + if((info = getUserInput()) != null) + { + emp.setBonus(info); + } + System.out.println("Enter Employee's Commission (#######.##):"); + if((info = getUserInput()) != null) + { + emp.setCommission(info); + } + } + catch(Exception e) + { + System.out.println("Error getting departments"); + e.printStackTrace(); + } + return emp; + } + + /* + getUserInput takes the user input from the keyboard and returns a + String representation to be used in creation of the new Employee + */ + private static String getUserInput() + { + char ch = '1'; + String str = "" ; + int l = 0; + try{ + while((ch=(char)System.in.read())!= '\n') + { + if (ch != '\r') + str += ch; + } + if(str.length()>0) + { + return str; + } + return null; + } + catch(Exception e) + { + System.out.println("Error reading input"); + e.printStackTrace(); + return null ; + } + } +} + +/* + Employee Class is used as a Bean class to store all information + about a single Employee from the Employee Table in the Sample Database. + + Each private member represents a field in the Employee Table, and + some have default values. Above we fill each field with user input using + the setter methods of the Employee Class. Next we INSERT the information + into the database with the help of the getter methods in the Employee + Class +*/ +class Employee +{ + private String employeeNumber = null ; + private String firstName = null ; + private String middleInitial = null ; + private String lastName = null ; + private String workDepartment = null ; + private String phoneNumber = null ; + private String job = null ; + private String sex = null ; + + private Date hireDate = null ; + private Date birthDate = null ; + + private int educationLevel = 0 ; + + private double salary = 0.0 ; + private double bonus = 0.0 ; + private double commission = 0.0 ; + + private Connection conn = null ; + private Statement stmt = null ; + private ResultSet rs = null ; + + public Employee(){ + long hdt = 991111111 ; + long bdt = 711111111 ; + employeeNumber = "000500" ; // Change this incase of Primary Key + firstName = "New" ; + middleInitial = "T" ; + lastName = "Employee" ; + workDepartment = "TST" ; + phoneNumber = "5555" ; + hireDate = new Date(hdt) ; // Change to use today's date as default + job = "Tester" ; + educationLevel = 0 ; + sex = "M" ; + birthDate = new Date(bdt) ; // Change to make 25 years old + salary = 0.00 ; + bonus = 0.00 ; + commission = 0.00 ; + } + + public void setEmployeeNumber(String empNo){ + employeeNumber = empNo ; + } + + public void setFirstName(String fName){ + firstName = fName ; + } + + public void setMiddleInitial(String mInitial){ + middleInitial = mInitial ; + } + + public void setLastName(String lName){ + lastName = lName ; + } + + public void setWorkDepartment(String wDept){ + workDepartment = wDept ; + } + + public void setPhoneNumber(String phoneNum){ + phoneNumber = phoneNum ; + } + + public void setHireDate(Date hdt){ + hireDate = hdt ; + } + + /************************************************* + * Input: String hdt: date in format "yyyy-mm-dd" + */ + public void setHireDate(String hdt) + { + hireDate = Date.valueOf(hdt); + } + + public void setJob(String jb){ + job = jb ; + } + + public void setEducationLevel(int edLvl){ + educationLevel = edLvl ; + } + + public void setEducationLevel(String edLvl) + { + Integer edl = new Integer(edLvl); + educationLevel = edl.intValue(); + } + + public void setSex(String sx){ + sex = sx ; + } + + public void setBirthDate(Date bdt){ + birthDate = bdt ; + } + + /************************************************* + * Input: String bdt: date in format "yyyy-mm-dd" + */ + public void setBirthDate(String bdt) + { + birthDate = Date.valueOf(bdt); + + } + + public void setSalary(double sal) + { + salary = sal ; + } + + public void setSalary(String sal) + { + Double dbl = new Double(sal); + salary = dbl.doubleValue(); + } + + public void setBonus(double bns) + { + bonus = bns ; + } + + public void setBonus(String bns) + { + Double dbl = new Double(bns); + bonus = dbl.doubleValue(); + } + + public void setCommission(double comm) + { + commission = comm ; + } + + public void setCommission(String comm) + { + Double dbl = new Double(comm); + commission = dbl.doubleValue(); + } + + public String getEmployeeNumber(){ + return employeeNumber ; + } + + public String getFirstName(){ + return firstName ; + } + + public String getMiddleInitial(){ + return middleInitial ; + } + + public String getLastName(){ + return lastName ; + } + + public String getWorkDepartment(){ + return workDepartment ; + } + + public String getPhoneNumber(){ + return phoneNumber ; + } + + public Date getHireDate(){ + return hireDate ; + } + + public String getJob(){ + return job ; + } + + public int getEducationLevel(){ + return educationLevel ; + } + + public String getSex(){ + return sex ; + } + + public Date getBirthDate(){ + return birthDate ; + } + + public double getSalary(){ + return salary ; + } + + public double getBonus(){ + return bonus ; + } + + public double getCommission(){ + return commission ; + } +} diff --git a/java/jdbc/CreateGTF.db2 b/java/jdbc/CreateGTF.db2 new file mode 100644 index 0000000..a9efad8 --- /dev/null +++ b/java/jdbc/CreateGTF.db2 @@ -0,0 +1,92 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2010 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: CreateGTF.db2 +-- +-- SAMPLE: How to catalog the UDFs contained in UDFcsvReader.java +-- +-- To run this script from the CLP, perform the following steps: +-- 1. issue the command "db2 -tvf CreateGTF.db2" +---------------------------------------------------------------------------- +CONNECT TO sample; + +CREATE FUNCTION CSVREAD(VARCHAR(255)) +RETURNS GENERIC TABLE +EXTERNAL NAME 'UDFcsvReader!csvReadString' +LANGUAGE JAVA +SPECIFIC csvReadString +PARAMETER STYLE DB2GENERAL +VARIANT +FENCED THREADSAFE +NOT NULL CALL +NO SQL +NO EXTERNAL ACTION +NO SCRATCHPAD +NO FINAL CALL +DISALLOW PARALLEL +NO DBINFO; + +CREATE FUNCTION CSVREAD(VARCHAR(255), VARCHAR(255)) +RETURNS GENERIC TABLE +EXTERNAL NAME 'UDFcsvReader!csvRead' +LANGUAGE JAVA +SPECIFIC csvRead +PARAMETER STYLE DB2GENERAL +VARIANT +FENCED THREADSAFE +NOT NULL CALL +NO SQL +NO EXTERNAL ACTION +NO SCRATCHPAD +NO FINAL CALL +DISALLOW PARALLEL +NO DBINFO; + +CREATE FUNCTION HTTPCSVREAD(VARCHAR(255), INTEGER, VARCHAR(255)) +RETURNS GENERIC TABLE +EXTERNAL NAME 'UDFcsvReader!httpCsvReadString' +LANGUAGE JAVA +SPECIFIC httpCsvReadString +PARAMETER STYLE DB2GENERAL +VARIANT +FENCED THREADSAFE +NOT NULL CALL +NO SQL +NO EXTERNAL ACTION +NO SCRATCHPAD +NO FINAL CALL +DISALLOW PARALLEL +NO DBINFO; + +CREATE FUNCTION HADOOPCSVREAD(VARCHAR(255), INTEGER, VARCHAR(255)) +RETURNS GENERIC TABLE +EXTERNAL NAME 'UDFcsvReader!hadoopCsvReadString' +LANGUAGE JAVA +SPECIFIC hadoopCsvReadString +PARAMETER STYLE DB2GENERAL +VARIANT +FENCED THREADSAFE +NOT NULL CALL +NO SQL +NO EXTERNAL ACTION +NO SCRATCHPAD +NO FINAL CALL +DISALLOW PARALLEL +NO DBINFO; diff --git a/java/jdbc/DB2EvmonChangeHistory.xsl b/java/jdbc/DB2EvmonChangeHistory.xsl new file mode 100755 index 0000000..ef9bb3a --- /dev/null +++ b/java/jdbc/DB2EvmonChangeHistory.xsl @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ------------------------------------------------------ + Event ID : + + + Event Type : + + + Event Timestamp : + + + Member : + + + Release : + + + ------------------------------------------------------- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Event Summary + ============= + + Application ID : + + + Application Name : + + + Application Handle : + + + Backup Timestamp : + + + Client Acctng : + + + Client Application Name : + + + Client Host Name : + + + Client PID : + + + Client Platform : + + + Client Port Number : + + + Client Protocol : + + + Client Wrkstnname : + + + Coord Member : + + + Session Authid : + + + System Authid : + + + Utility Invocation ID : + + + Utility Type : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Database Config Change Details + ============================== + + CFG Name : + + + CFG Value : + + + CFG Value Flags : + + + CFG Old Value : + + + CFG Old Value Flags : + + + Collection Type : + + + Deferred : + + + + + + + + + + + DDL Statement Change Details + ============================ + + Partition Key : + + + Global Transaction ID : + + + Local Transaction ID : + + + Save Point ID : + + + UOW ID : + + + DDL Classification : + + + Statement Text : + + + + + + + + + + + Evmon Start Change Details + ========================== + + DB2 Start Time : + + + DB Connect Time : + + + + + + + + + + + Register Variable Change Details + ================================ + + Register Variable Collection Type : + + + Register Variable Level : + + + Register Variable Name : + + + Register Variable Old Value : + + + Register Variable Value : + + + + + + + + + + + TXN Completion Change Details + ============================= + + Global Transaction ID : + + + Local Transaction ID : + + + Save Point ID : + + + TXN Completion Status : + + + UOW ID : + + + + + + + + + + + Utility Start Change Details + ============================ + + Number of TBSP : + + + Object Name : + + + Object Schema : + + + Object Type : + + + TBSP Names : + + + Utility Detail : + + + Utility Invocation ID : + + + Utility Invoker Type : + + + Utility Operation Type : + + + Utility Priority : + + + Utility Start Type : + + + Utility Type : + + + + + + + + + + + Utility Location Change Details + =============================== + + Device Type : + + + Location : + + + Location Type : + + + Utility Invocation ID : + + + Utility Type : + + + + + + + + + + + Utility Stop Change Details + =========================== + + Sqlcabc : + + + Sqlcaid : + + + Sqlerrd1 : + + + Sqlerrd2 : + + + Sqlerrd3 : + + + Sqlerrd4 : + + + Sqlerrd5 : + + + Sqlerrd6 : + + + Sqlerrm : + + + Sqlstate : + + + Sqlwarn : + + + Start Event ID : + + + Start Event Timestamp : + + + Utility Invocation ID : + + + Utility Stop Type : + + + Utility Type : + + + + + + + + + + + Utility Phase Change Details + ============================ + + Object Name : + + + Object Schema : + + + Object Type : + + + Phase Start Event ID : + + + Phase Start Event Timestamp : + + + Utility Invocation ID : + + + Utility Phase Detail : + + + Utility Phase Type : + + + Utility Type : + + + + + diff --git a/java/jdbc/DB2EvmonLocking.xsl b/java/jdbc/DB2EvmonLocking.xsl new file mode 100755 index 0000000..ea9513c --- /dev/null +++ b/java/jdbc/DB2EvmonLocking.xsl @@ -0,0 +1,1169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ------------------------------------------------------- + Event ID : + + + Event Type : + + + Event Timestamp : + + + Partition of detection : + + + ------------------------------------------------------- + + + + + + + + + + + + + + + + + Filename: + + + + + + + + + + + + + + + + + + + Participant No + + requesting lock + + ---------------------------------- + Lock Name : 0x + + + Lock wait start time : + + + Lock wait end time : + + + Lock Type : + + + Lock Specifics : + + + Lock Attributes : + + + Lock mode requested : + + + Lock mode held : + + + + Current Lock mode : + + + + Lock Count : + + + Lock Hold Count : + + + Lock rrIID : + + + Lock Status : + + + Lock release flags : + + + Tablespace TID : + + + Tablespace Name : + + + Table FID : + + + Table Schema : + + + Table Name : + + + + + + Participant No + + requesting threshold ticket + + --------------------------------------------- + Threshold Name : + + + Threshold Id : + + + Queued agents : + + + Queue start time : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unable to obtain Lock Holder information during the occurence of the lock event. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Current Activities of Participant No + + + ---------------------------------------- + + + + + + + + + Activities not available + + + + + + Past Activities of Participant No + + + ------------------------------------- + + + + + + + + + + + + Activities not available + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Activity ID : + + + Uow ID : + + + Package Name : + + + Package Schema : + + + Package Version : + + + Package Token : + + + Package Sectno : + + + Reopt value : + + + Incremental Bind : + + + Eff isolation : + + + Eff degree : + + + Actual degree : + + + Eff locktimeout : + + + Stmt first use : + + + + + + + + + + Stmt last use : + + + + + + + + + + Stmt unicode : + + + Stmt query ID : + + + Stmt nesting level : + + + Stmt invocation ID : + + + Stmt source ID : + + + Stmt pkgcache ID : + + + Stmt type : + + + Stmt operation : + + + Stmt no : + + + Stmt text : + + + + + + + + + + + + + + + + + + + + + + + + Type : + + + Data : + + + Reopt : + + + Null : + + + + + + + + + + + + Deadlock Graph + -------------- + Total number of deadlock participants : + + + Participant that was rolled back : + + + Type of deadlock : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/jdbc/DB2EvmonPkgCache.xsl b/java/jdbc/DB2EvmonPkgCache.xsl new file mode 100755 index 0000000..66a0628 --- /dev/null +++ b/java/jdbc/DB2EvmonPkgCache.xsl @@ -0,0 +1,1041 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ------------------------------------------------------- + Event ID : + + + Event Type : + + + Event Timestamp : + + + Member : + + + Release : + + + ------------------------------------------------------- + + + + + + Package Cache Details + --------------------- + Section Type : + + + Insert Timestamp : + + + Executable ID : + + + Package Schema : + + + Package Name : + + + Package Version ID : + + + Section Number : + + + Stmt No : + + + Num Routines : + + + Semantic Env Id : + + + Stmt Id : + + + Plan ID : + + + Prep Warning : + + + Prep Warning Reason : + + + Effective Isolation : + + + Number Of Executions : + + + Number Of Executions With Metrics : + + + Prep Time : + + + Last Metrics Update : + + + Executions By Coordinator : + + + Executions By Coordinator With Metrics : + + + Statement Type : + + + Query Cost Estimate : + + + Statement Package Cache ID : + + + Statement Text : + + + Compilation Environment : + + + Section Environment : + + + Routine Identifier : + + + Query Data Tag List : + + + Total Stats Fabrication Time : + + + Total Stats Fabrications : + + + Total Synchronous Runstats Time : + + + Total Synchronous Runstats : + + + Active Hash Group Bys Top : + + + Active Hash Joins Top : + + + Active OLAP Functions Top : + + + Active Partial Early Aggregations Top : + + + Active Partial Early Distincts Top : + + + Active Sort Consumers Top : + + + Active Sorts Top : + + + Active Columnar Vector Consumers Top : + + + Sort Consumer Heap Top : + + + Sort Consumer Shared Heap Top : + + + Sort Heap Top : + + + Sort Shared Heap Top : + + + Estimated Sort Shared Heap Top : + + + Estimated Sort Consumers Top : + + + Estimated Runtime : + + + Agents Top : + + + Last Exec Error SQLCODE : + + + Last Exec Error SQLERRMC : + + + Last Exec Error Timestamp : + + + Last Exec Warning SQLCODE : + + + Last Exec Warning SQLERRMC : + + + Last Exec Warning Timestamp : + + + Number Executions with Error : + + + Number Executions with Warning : + + + Statement Comments : + + + + + + + Max Coordinator Stmt Exec Timestamp : + + + Max Coordinator Stmt Exec Time : + + + + + + + + + + + Metrics + ------------------- + WLM_QUEUE_TIME_TOTAL : + + + WLM_QUEUE_ASSIGNMENTS_TOTAL : + + + FCM_TQ_RECV_WAIT_TIME : + + + FCM_MESSAGE_RECV_WAIT_TIME : + + + FCM_TQ_SEND_WAIT_TIME : + + + FCM_MESSAGE_SEND_WAIT_TIME : + + + LOCK_WAIT_TIME : + + + LOCK_WAIT_TIME_GLOBAL : + + + LOCK_WAITS : + + + LOCK_WAITS_GLOBAL : + + + DIRECT_READ_TIME : + + + DIRECT_READ_REQS : + + + DIRECT_WRITE_TIME : + + + DIRECT_WRITE_REQS : + + + LOG_BUFFER_WAIT_TIME : + + + NUM_LOG_BUFFER_FULL : + + + LOG_DISK_WAIT_TIME : + + + LOG_DISK_WAITS_TOTAL : + + + POOL_WRITE_TIME : + + + POOL_READ_TIME : + + + AUDIT_FILE_WRITE_WAIT_TIME : + + + AUDIT_FILE_WRITES_TOTAL : + + + AUDIT_SUBSYSTEM_WAIT_TIME : + + + AUDIT_SUBSYSTEM_WAITS_TOTAL : + + + DIAGLOG_WRITE_WAIT_TIME : + + + DIAGLOG_WRITES_TOTAL : + + + FCM_SEND_WAIT_TIME : + + + FCM_RECV_WAIT_TIME : + + + TOTAL_ACT_WAIT_TIME : + + + TOTAL_SECTION_SORT_PROC_TIME : + + + TOTAL_SECTION_SORTS : + + + TOTAL_SECTION_SORT_TIME : + + + TOTAL_ACT_TIME : + + + TOTAL_ROUTINE_TIME : + + + STMT_EXEC_TIME : + + + COORD_STMT_EXEC_TIME : + + + TOTAL_ROUTINE_NON_SECTION_PROC_TIME : + + + TOTAL_ROUTINE_NON_SECTION_TIME : + + + TOTAL_SECTION_PROC_TIME : + + + TOTAL_SECTION_TIME : + + + TOTAL_ROUTINE_USER_CODE_PROC_TIME : + + + TOTAL_ROUTINE_USER_CODE_TIME : + + + ROWS_READ : + + + ROWS_MODIFIED : + + + POOL_DATA_L_READS : + + + POOL_INDEX_L_READS : + + + POOL_TEMP_DATA_L_READS : + + + POOL_TEMP_INDEX_L_READS : + + + POOL_XDA_L_READS : + + + POOL_TEMP_XDA_L_READS : + + + TOTAL_CPU_TIME : + + + POOL_DATA_P_READS : + + + POOL_TEMP_DATA_P_READS : + + + POOL_XDA_P_READS : + + + POOL_TEMP_XDA_P_READS : + + + POOL_INDEX_P_READS : + + + POOL_TEMP_INDEX_P_READS : + + + POOL_DATA_GBP_L_READS : + + + POOL_DATA_GBP_P_READS : + + + POOL_DATA_LBP_PAGES_FOUND : + + + POOL_DATA_GBP_INDEP_PAGES_FOUND_IN_LBP : + + + POOL_DATA_GBP_INVALID_PAGES : + + + POOL_INDEX_GBP_L_READS : + + + POOL_INDEX_GBP_P_READS : + + + POOL_INDEX_LBP_PAGES_FOUND : + + + POOL_INDEX_GBP_INDEP_PAGES_FOUND_IN_LBP : + + + POOL_INDEX_GBP_INVALID_PAGES : + + + POOL_XDA_GBP_L_READS : + + + POOL_XDA_GBP_P_READS : + + + POOL_XDA_LBP_PAGES_FOUND : + + + POOL_XDA_GBP_INDEP_PAGES_FOUND_IN_LBP : + + + POOL_XDA_GBP_INVALID_PAGES : + + + POOL_DATA_WRITES : + + + POOL_XDA_WRITES : + + + POOL_INDEX_WRITES : + + + DIRECT_READS : + + + DIRECT_WRITES : + + + ROWS_RETURNED : + + + DEADLOCKS : + + + LOCK_TIMEOUTS : + + + LOCK_TIMEOUTS_GLOBAL : + + + LOCK_ESCALS : + + + LOCK_ESCALS_MAXLOCKS : + + + LOCK_ESCALS_LOCKLIST : + + + LOCK_ESCALS_GLOBAL : + + + FCM_SENDS_TOTAL : + + + FCM_RECVS_TOTAL : + + + FCM_SEND_VOLUME : + + + FCM_RECV_VOLUME : + + + FCM_MESSAGE_SENDS_TOTAL : + + + FCM_MESSAGE_RECVS_TOTAL : + + + FCM_MESSAGE_SEND_VOLUME : + + + FCM_MESSAGE_RECV_VOLUME : + + + FCM_TQ_SENDS_TOTAL : + + + FCM_TQ_RECVS_TOTAL : + + + FCM_TQ_SEND_VOLUME : + + + FCM_TQ_RECV_VOLUME : + + + TQ_TOT_SEND_SPILLS : + + + POST_THRESHOLD_SORTS : + + + POST_SHRTHRESHOLD_SORTS : + + + SORT_OVERFLOWS : + + + AUDIT_EVENTS_TOTAL : + + + TOTAL_SORTS : + + + THRESH_VIOLATIONS : + + + NUM_LW_THRESH_EXCEEDED : + + + TOTAL_ROUTINE_INVOCATIONS : + + + TOTAL_EXTENDED_LATCH_WAIT_TIME : + + + TOTAL_EXTENDED_LATCH_WAITS : + + + TOTAL_DISP_RUN_QUEUE_TIME : + + RECLAIM_WAIT_TIME : + + + SPACEMAPPAGE_RECLAIM_WAIT_TIME : + + + CF_WAIT_TIME : + + + CF_WAITS : + + + TOTAL_PEDS : + + + DISABLED_PEDS : + + + POST_THRESHOLD_PEDS : + + + TOTAL_PEAS : + + + POST_THRESHOLD_PEAS : + + + TQ_SORT_HEAP_REQUESTS : + + + TQ_SORT_HEAP_REJECTIONS : + + + POOL_QUEUED_ASYNC_DATA_REQS : + + + POOL_QUEUED_ASYNC_INDEX_REQS : + + + POOL_QUEUED_ASYNC_XDA_REQS : + + + POOL_QUEUED_ASYNC_TEMP_DATA_REQS : + + + POOL_QUEUED_ASYNC_TEMP_INDEX_REQS : + + + POOL_QUEUED_ASYNC_TEMP_XDA_REQS : + + + POOL_QUEUED_ASYNC_OTHER_REQS : + + + POOL_QUEUED_ASYNC_DATA_PAGES : + + + POOL_QUEUED_ASYNC_INDEX_PAGES : + + + POOL_QUEUED_ASYNC_XDA_PAGES : + + + POOL_QUEUED_ASYNC_TEMP_DATA_PAGES : + + + POOL_QUEUED_ASYNC_TEMP_INDEX_PAGES : + + + POOL_QUEUED_ASYNC_TEMP_XDA_PAGES : + + + POOL_FAILED_ASYNC_DATA_REQS : + + + POOL_FAILED_ASYNC_INDEX_REQS : + + + POOL_FAILED_ASYNC_XDA_REQS : + + + POOL_FAILED_ASYNC_TEMP_DATA_REQS : + + + POOL_FAILED_ASYNC_TEMP_INDEX_REQS : + + + POOL_FAILED_ASYNC_TEMP_XDA_REQS : + + + POOL_FAILED_ASYNC_OTHER_REQS : + + + PREFETCH_WAIT_TIME : + + + PREFETCH_WAITS : + + + FCM_TQ_RECV_WAITS_TOTAL : + + + FCM_MESSAGE_RECV_WAITS_TOTAL : + + + FCM_TQ_SEND_WAITS_TOTAL : + + + FCM_MESSAGE_SEND_WAITS_TOTAL : + + + FCM_SEND_WAITS_TOTAL : + + + FCM_RECV_WAITS_TOTAL : + + + IDA_SEND_WAIT_TIME : + + + IDA_SENDS_TOTAL : + + + IDA_SEND_VOLUME : + + + IDA_RECV_WAIT_TIME : + + + IDA_RECVS_TOTAL : + + + IDA_RECV_VOLUME : + + + ROWS_DELETED : + + + ROWS_INSERTED : + + + ROWS_UPDATED : + + + TOTAL_HASH_JOINS : + + + TOTAL_HASH_LOOPS : + + + HASH_JOIN_OVERFLOWS : + + + HASH_JOIN_SMALL_OVERFLOWS : + + + POST_SHRTHRESHOLD_HASH_JOINS : + + + TOTAL_OLAP_FUNCS : + + + OLAP_FUNC_OVERFLOWS : + + + INT_ROWS_DELETED : + + + INT_ROWS_INSERTED : + + + INT_ROWS_UPDATED : + + + POOL_COL_L_READS : + + + POOL_TEMP_COL_L_READS : + + + POOL_COL_P_READS : + + + POOL_TEMP_COL_P_READS : + + + POOL_COL_LBP_PAGES_FOUND : + + + POOL_COL_WRITES : + + + POOL_COL_GBP_L_READS : + + + POOL_COL_GBP_P_READS : + + + POOL_COL_GBP_INVALID_PAGES : + + + POOL_COL_GBP_INDEP_PAGES_FOUND_IN_LBP : + + + POOL_QUEUED_ASYNC_COL_REQS : + + + POOL_QUEUED_ASYNC_TEMP_COL_REQS : + + + POOL_QUEUED_ASYNC_COL_PAGES : + + + POOL_QUEUED_ASYNC_TEMP_COL_PAGES : + + + POOL_FAILED_ASYNC_COL_REQS : + + + POOL_FAILED_ASYNC_TEMP_COL_REQS : + + + TOTAL_COL_TIME : + + + TOTAL_COL_PROC_TIME : + + + TOTAL_COL_EXECUTIONS : + + + POST_THRESHOLD_HASH_JOINS : + + + POOL_DATA_CACHING_TIER_L_READS : + + + POOL_INDEX_CACHING_TIER_L_READS : + + + POOL_XDA_CACHING_TIER_L_READS : + + + POOL_COL_CACHING_TIER_L_READS : + + + POOL_DATA_CACHING_TIER_PAGE_WRITES : + + + POOL_INDEX_CACHING_TIER_PAGE_WRITES : + + + POOL_XDA_CACHING_TIER_PAGE_WRITES : + + + POOL_COL_CACHING_TIER_PAGE_WRITES : + + + POOL_DATA_CACHING_TIER_PAGE_UPDATES : + + + POOL_INDEX_CACHING_TIER_PAGE_UPDATES : + + + POOL_XDA_CACHING_TIER_PAGE_UPDATES : + + + POOL_COL_CACHING_TIER_PAGE_UPDATES : + + + POOL_CACHING_TIER_PAGE_READ_TIME : + + + POOL_CACHING_TIER_PAGE_WRITE_TIME : + + + POOL_DATA_CACHING_TIER_PAGES_FOUND : + + + POOL_INDEX_CACHING_TIER_PAGES_FOUND : + + + POOL_XDA_CACHING_TIER_PAGES_FOUND : + + + POOL_COL_CACHING_TIER_PAGES_FOUND : + + + POOL_DATA_CACHING_TIER_GBP_INVALID_PAGES : + + + POOL_INDEX_CACHING_TIER_GBP_INVALID_PAGES : + + + POOL_XDA_CACHING_TIER_GBP_INVALID_PAGES : + + + POOL_COL_CACHING_TIER_GBP_INVALID_PAGES : + + + POOL_DATA_CACHING_TIER_GBP_INDEP_PAGES_FOUND : + + + POOL_INDEX_CACHING_TIER_GBP_INDEP_PAGES_FOUND : + + + POOL_XDA_CACHING_TIER_GBP_INDEP_PAGES_FOUND : + + + POOL_COL_CACHING_TIER_GBP_INDEP_PAGES_FOUND : + + + TOTAL_HASH_GRPBYS : + + + HASH_GRPBY_OVERFLOWS : + + + POST_THRESHOLD_HASH_GRPBYS : + + + POST_THRESHOLD_OLAP_FUNCS : + + + POST_THRESHOLD_COL_VECTOR_CONSUMERS : + + + TOTAL_COL_VECTOR_CONSUMERS : + + + TOTAL_COL_VECTOR_CONSUMER_OVERFLOWS : + + + ADM_OVERFLOWS: + + + ADM_BYPASS_ACT_TOTAL: + + + TOTAL_INDEX_BUILD_TIME : + + + TOTAL_INDEX_BUILD_PROC_TIME : + + + TOTAL_INDEXES_BUILT : + + + TOTAL_COL_SYNOPSIS_TIME : + + + TOTAL_COL_SYNOPSIS_PROC_TIME : + + + TOTAL_COL_SYNOPSIS_EXECUTIONS : + + + COL_SYNOPSIS_ROWS_INSERTED : + + + LOB_PREFETCH_WAIT_TIME : + + + LOB_PREFETCH_REQS : + + + FED_ROWS_DELETED : + + + FED_ROWS_INSERTED : + + + FED_ROWS_UPDATED : + + + FED_ROWS_READ : + + + FED_WAIT_TIME : + + + FED_WAITS_TOTAL : + + + + + + + + + + + + + + + + + + Type : + + + Data : + + + Reopt : + + + Null : + + + + + diff --git a/java/jdbc/DB2EvmonUOW.xsl b/java/jdbc/DB2EvmonUOW.xsl new file mode 100755 index 0000000..7feab70 --- /dev/null +++ b/java/jdbc/DB2EvmonUOW.xsl @@ -0,0 +1,1479 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ------------------------------------------------------- + Event ID : + + + Event Type : + + + Event Timestamp : + + + Member : + + + Release : + + + Monitoring interval ID : + + + ------------------------------------------------------- + + + + + + Database Level Details + ---------------------- + Database Member Activation Time : + + + Coordinator Member : + + + + + + + + Connection Level Details + ------------------------ + Application ID : + + + Application Handle : + + + Application Name : + + + Session Authorization ID : + + + System Authorization ID : + + + Connection Timestamp : + + + Client Process ID : + + + Client Platform : + + + Client Product ID : + + + Client Protocol : + + + Client Hostname : + + + Client Port Number : + + + Member Subset Identifier : + + + + + + + UOW Level Details + ------------------------ + Start Time : + + + Stop Time : + + + Completion Status : + + + Intra-parallel State : + + + UOW ID : + + + Workoad Occurrence ID : + + + Workload Name : + + + Workoad ID : + + + Service Superclass Name : + + + Service Subclass Name : + + + Service Class ID : + + + Client Userid : + + + Client Workstation Name : + + + Client Application Name : + + + Client Accounting String : + + + Local Transaction ID : + + + Global Transaction ID : + + + Log Space Used : + + + Active Hash Group Bys Top : + + + Active Hash Joins Top : + + + Active OLAP Functions Top : + + + Active Partial Early Aggregations Top : + + + Active Partial Early Distincts Top : + + + Active Sort Consumers Top : + + + Active Sorts Top : + + + Active Columnar Vector Consumers Top : + + + Sort Consumer Heap Top : + + + Sort Consumer Shared Heap Top : + + + Sort Heap Top : + + + Sort Shared Heap Top : + + + + + + + + + UOW Metrics + ------------------------ + TOTAL_CPU_TIME : + + + TOTAL_WAIT_TIME : + + + ACT_ABORTED_TOTAL : + + + ACT_COMPLETED_TOTAL : + + + ACT_REJECTED_TOTAL : + + + AGENT_WAIT_TIME : + + + AGENT_WAITS_TOTAL : + + + APP_RQSTS_COMPLETED_TOTAL : + + + AUDIT_EVENTS_TOTAL : + + + AUDIT_SUBSYSTEM_WAIT_TIME : + + + AUDIT_SUBSYSTEM_WAITS_TOTAL : + + + AUDIT_FILE_WRITE_WAIT_TIME : + + + AUDIT_FILE_WRITES_TOTAL : + + + POOL_DATA_L_READS : + + + POOL_INDEX_L_READS : + + + POOL_TEMP_DATA_L_READS : + + + POOL_TEMP_INDEX_L_READS : + + + POOL_TEMP_XDA_L_READS : + + + POOL_XDA_L_READS : + + + POOL_DATA_P_READS : + + + POOL_INDEX_P_READS : + + + POOL_TEMP_DATA_P_READS : + + + POOL_TEMP_INDEX_P_READS : + + + POOL_TEMP_XDA_P_READS : + + + POOL_XDA_P_READS : + + + POOL_DATA_GBP_L_READS : + + + POOL_DATA_GPB_P_READS : + + + POOL_DATA_LBP_PAGES_FOUND : + + + POOL_DATA_GBP_INDEP_PAGES_FOUND_IN_LBP : + + + POOL_DATA_GBP_INVALID_PAGES : + + + POOL_INDEX_GBP_L_READS : + + + POOL_INDEX_GPB_P_READS : + + + POOL_INDEX_LBP_PAGES_FOUND : + + + POOL_INDEX_GBP_INDEP_PAGES_FOUND_IN_LBP : + + + POOL_INDEX_GBP_INVALID_PAGES : + + + POOL_XDA_GBP_L_READS : + + + POOL_XDA_GPB_P_READS : + + + POOL_XDA_LBP_PAGES_FOUND : + + + POOL_XDA_GBP_INDEP_PAGES_FOUND_IN_LBP : + + + POOL_XDA_GBP_INVALID_PAGES : + + + POOL_DATA_WRITES : + + + POOL_INDEX_WRITES : + + + POOL_XDA_WRITES : + + + POOL_READ_TIME : + + + POOL_WRITE_TIME : + + + CLIENT_IDLE_WAIT_TIME : + + + DEADLOCKS : + + + DIAGLOG_WRITES_TOTAL : + + + DIAGLOG_WRITE_WAIT_TIME : + + + DIRECT_READS : + + + DIRECT_READ_TIME : + + + DIRECT_WRITES : + + + DIRECT_WRITE_TIME : + + + DIRECT_READ_REQS : + + + DIRECT_WRITE_REQS : + + + FCM_RECV_VOLUME : + + + FCM_RECVS_TOTAL : + + + FCM_SEND_VOLUME : + + + FCM_SENDS_TOTAL : + + + FCM_RECV_WAIT_TIME : + + + FCM_SEND_WAIT_TIME : + + + FCM_MESSAGE_RECV_VOLUME : + + + FCM_MESSAGE_RECVS_TOTAL : + + + FCM_MESSAGE_RECV_WAIT_TIME : + + + FCM_MESSAGE_SEND_VOLUME : + + + FCM_MESSAGE_SENDS_TOTAL : + + + FCM_MESSAGE_SEND_WAIT_TIME : + + + FCM_TQ_RECV_WAIT_TIME : + + + FCM_TQ_RECVS_TOTAL : + + + FCM_TQ_RECV_VOLUME : + + + FCM_TQ_SEND_WAIT_TIME : + + + FCM_TQ_SENDS_TOTAL : + + + FCM_TQ_SEND_VOLUME : + + + TQ_TOT_SEND_SPILLS : + + + IPC_RECV_VOLUME : + + + IPC_RECV_WAIT_TIME : + + + IPC_RECVS_TOTAL : + + + IPC_SEND_VOLUME : + + + IPC_SEND_WAIT_TIME : + + + IPC_SENDS_TOTAL : + + + LOCK_ESCALS : + + + LOCK_ESCALS_MAXLOCKS : + + + LOCK_ESCALS_LOCKLIST : + + + LOCK_ESCALS_GLOBAL : + + + LOCK_TIMEOUTS : + + + LOCK_TIMEOUTS_GLOBAL : + + + LOCK_WAIT_TIME : + + + LOCK_WAIT_TIME_GLOBAL : + + + LOCK_WAITS : + + + LOCK_WAITS_GLOBAL : + + + POOL_DATA_GBP_P_READS : + + + POOL_INDEX_GBP_P_READS : + + + LOG_BUFFER_WAIT_TIME : + + + NUM_LOG_BUFFER_FULL : + + + LOG_DISK_WAIT_TIME : + + + LOG_DISK_WAITS_TOTAL : + + + RQSTS_COMPLETED_TOTAL : + + + ROWS_MODIFIED : + + + ROWS_READ : + + + ROWS_RETURNED : + + + TCPIP_RECV_VOLUME : + + + TCPIP_SEND_VOLUME : + + + TCPIP_RECV_WAIT_TIME : + + + TCPIP_RECVS_TOTAL : + + + TCPIP_SEND_WAIT_TIME : + + + TCPIP_SENDS_TOTAL : + + + TOTAL_APP_RQST_TIME : + + + TOTAL_RQST_TIME : + + + WLM_QUEUE_TIME_TOTAL : + + + WLM_QUEUE_ASSIGNMENTS_TOTAL : + + + TOTAL_ROUTINE_TIME : + + + TOTAL_COMPILE_PROC_TIME : + + + TOTAL_COMPILE_TIME : + + + TOTAL_COMPILATIONS : + + + TOTAL_IMPLICIT_COMPILE_PROC_TIME : + + + TOTAL_IMPLICIT_COMPILE_TIME : + + + TOTAL_IMPLICIT_COMPILATIONS : + + + TOTAL_RUNSTATS_PROC_TIME : + + + TOTAL_RUNSTATS_TIME : + + + TOTAL_RUNSTATS : + + + TOTAL_REORG_PROC_TIME : + + + TOTAL_REORG_TIME : + + + TOTAL_REORGS : + + + TOTAL_LOAD_PROC_TIME : + + + TOTAL_LOAD_TIME : + + + TOTAL_LOADS : + + + TOTAL_SECTION_PROC_TIME : + + + TOTAL_SECTION_TIME : + + + TOTAL_APP_SECTION_EXECUTIONS : + + + TOTAL_COMMIT_PROC_TIME : + + + TOTAL_COMMIT_TIME : + + + TOTAL_APP_COMMITS : + + + TOTAL_ROLLBACK_PROC_TIME : + + + TOTAL_ROLLBACK_TIME : + + + TOTAL_APP_ROLLBACKS : + + + TOTAL_ROUTINE_USER_CODE_PROC_TIME : + + + TOTAL_ROUTINE_USER_CODE_TIME : + + + THRESH_VIOLATIONS : + + + NUM_LW_THRESH_EXCEEDED : + + + TOTAL_ROUTINE_INVOCATIONS : + + + INT_COMMITS : + + + INT_ROLLBACKS : + + + CAT_CACHE_INSERTS : + + + CAT_CACHE_LOOKUPS : + + + PKG_CACHE_INSERTS : + + + PKG_CACHE_LOOKUPS : + + + ACT_RQSTS_TOTAL : + + + RECLAIM_WAIT_TIME : + + + SPACEMAPPAGE_RECLAIM_WAIT_TIME : + + + CF_WAIT_TIME : + + + CF_WAITS : + + + EVMON_WAIT_TIME : + + + EVMON_WAITS_TOTAL : + + + TOTAL_STATS_FABRICATION_PROC_TIME : + + + TOTAL_STATS_FABRICATION_TIME : + + + TOTAL_STATS_FABRICATIONS : + + + TOTAL_SYNC_RUNSTATS_PROC_TIME : + + + TOTAL_SYNC_RUNSTATS_TIME : + + + TOTAL_SYNC_RUNSTATS : + + + TOTAL_EXTENDED_LATCH_WAIT_TIME : + + + TOTAL_EXTENDED_LATCH_WAITS : + + + TOTAL_DISP_RUN_QUEUE_TIME : + + + POOL_QUEUED_ASYNC_DATA_REQS : + + + POOL_QUEUED_ASYNC_INDEX_REQS : + + + POOL_QUEUED_ASYNC_XDA_REQS : + + + POOL_QUEUED_ASYNC_TEMP_DATA_REQS : + + + POOL_QUEUED_ASYNC_TEMP_INDEX_REQS : + + + POOL_QUEUED_ASYNC_TEMP_XDA_REQS : + + + POOL_QUEUED_ASYNC_OTHER_REQS : + + + POOL_QUEUED_ASYNC_DATA_PAGES : + + + POOL_QUEUED_ASYNC_INDEX_PAGES : + + + POOL_QUEUED_ASYNC_XDA_PAGES : + + + POOL_QUEUED_ASYNC_TEMP_DATA_PAGES : + + + POOL_QUEUED_ASYNC_TEMP_INDEX_PAGES : + + + POOL_QUEUED_ASYNC_TEMP_XDA_PAGES : + + + POOL_FAILED_ASYNC_DATA_REQS : + + + POOL_FAILED_ASYNC_INDEX_REQS : + + + POOL_FAILED_ASYNC_XDA_REQS : + + + POOL_FAILED_ASYNC_TEMP_DATA_REQS : + + + POOL_FAILED_ASYNC_TEMP_INDEX_REQS : + + + POOL_FAILED_ASYNC_TEMP_XDA_REQS : + + + POOL_FAILED_ASYNC_OTHER_REQS : + + + + APP_ACT_COMPLETED_TOTAL : + + + APP_ACT_ABORTED_TOTAL : + + + APP_ACT_REJECTED_TOTAL : + + + TOTAL_PEDS : + + + DISABLED_PEDS : + + + POST_THRESHOLD_PEDS : + + + TOTAL_PEAS : + + + POST_THRESHOLD_PEAS : + + + TQ_SORT_HEAP_REQUESTS : + + + TQ_SORT_HEAP_REJECTIONS : + + + TOTAL_CONNECT_REQUEST_TIME : + + + TOTAL_CONNECT_REQUEST_PROC_TIME : + + + TOTAL_CONNECT_REQUESTS : + + + TOTAL_CONNECT_AUTHENTICATION_TIME : + + + TOTAL_CONNECT_AUTHENTICATION_PROC_TIME : + + + TOTAL_CONNECT_AUTHENTICATIONS : + + + PREFETCH_WAIT_TIME : + + + PREFETCH_WAITS : + + + COMM_EXIT_WAIT_TIME : + + + COMM_EXIT_WAITS : + + + FCM_TQ_RECV_WAITS_TOTAL : + + + FCM_MESSAGE_RECV_WAITS_TOTAL : + + + FCM_TQ_SEND_WAITS_TOTAL : + + + FCM_MESSAGE_SEND_WAITS_TOTAL : + + + FCM_SEND_WAITS_TOTAL : + + + FCM_RECV_WAITS_TOTAL : + + + IDA_SEND_WAIT_TIME : + + + IDA_SENDS_TOTAL : + + + IDA_SEND_VOLUME : + + + IDA_RECV_WAIT_TIME : + + + IDA_RECVS_TOTAL : + + + IDA_RECV_VOLUME : + + + ROWS_DELETED : + + + ROWS_INSERTED : + + + ROWS_UPDATED : + + + TOTAL_HASH_JOINS : + + + TOTAL_HASH_LOOPS : + + + HASH_JOIN_OVERFLOWS : + + + HASH_JOIN_SMALL_OVERFLOWS : + + + POST_SHRTHRESHOLD_HASH_JOINS : + + + TOTAL_OLAP_FUNCS : + + + OLAP_FUNC_OVERFLOWS : + + + DYNAMIC_SQL_STMTS : + + + STATIC_SQL_STMTS : + + + FAILED_SQL_STMTS : + + + SELECT_SQL_STMTS : + + + UID_SQL_STMTS : + + + DDL_SQL_STMTS : + + + MERGE_SQL_STMTS : + + + XQUERY_STMTS : + + + IMPLICIT_REBINDS : + + + BINDS_PRECOMPLIES : + + + INT_ROWS_DELETED : + + + INT_ROWS_INSERTED : + + + INT_ROWS_UPDATED : + + + CALL_SQL_STMTS : + + + POOL_COL_L_READS : + + + POOL_TEMP_COL_L_READS : + + + POOL_COL_P_READS : + + + POOL_TEMP_COL_P_READS : + + + POOL_COL_LBP_PAGES_FOUND : + + + POOL_COL_WRITES : + + + POOL_COL_GBP_L_READS : + + + POOL_COL_GBP_P_READS : + + + POOL_COL_GBP_INVALID_PAGES : + + + POOL_COL_GBP_INDEP_PAGES_FOUND_IN_LBP : + + + POOL_QUEUED_ASYNC_COL_REQS : + + + POOL_QUEUED_ASYNC_TEMP_COL_REQS : + + + POOL_QUEUED_ASYNC_COL_PAGES : + + + POOL_QUEUED_ASYNC_TEMP_COL_PAGES : + + + POOL_FAILED_ASYNC_COL_REQS : + + + POOL_FAILED_ASYNC_TEMP_COL_REQS : + + + TOTAL_COL_TIME : + + + TOTAL_COL_PROC_TIME : + + + TOTAL_COL_EXECUTIONS : + + + POST_THRESHOLD_HASH_JOINS : + + + POOL_DATA_CACHING_TIER_L_READS : + + + POOL_INDEX_CACHING_TIER_L_READS : + + + POOL_XDA_CACHING_TIER_L_READS : + + + POOL_COL_CACHING_TIER_L_READS : + + + POOL_DATA_CACHING_TIER_PAGE_WRITES : + + + POOL_INDEX_CACHING_TIER_PAGE_WRITES : + + + POOL_XDA_CACHING_TIER_PAGE_WRITES : + + + POOL_COL_CACHING_TIER_PAGE_WRITES : + + + POOL_DATA_CACHING_TIER_PAGE_UPDATES : + + + POOL_INDEX_CACHING_TIER_PAGE_UPDATES : + + + POOL_XDA_CACHING_TIER_PAGE_UPDATES : + + + POOL_COL_CACHING_TIER_PAGE_UPDATES : + + + POOL_CACHING_TIER_PAGE_READ_TIME : + + + POOL_CACHING_TIER_PAGE_WRITE_TIME : + + + POOL_DATA_CACHING_TIER_PAGES_FOUND : + + + POOL_INDEX_CACHING_TIER_PAGES_FOUND : + + + POOL_XDA_CACHING_TIER_PAGES_FOUND : + + + POOL_COL_CACHING_TIER_PAGES_FOUND : + + + POOL_DATA_CACHING_TIER_GBP_INVALID_PAGES : + + + POOL_INDEX_CACHING_TIER_GBP_INVALID_PAGES : + + + POOL_XDA_CACHING_TIER_GBP_INVALID_PAGES : + + + POOL_COL_CACHING_TIER_GBP_INVALID_PAGES : + + + POOL_DATA_CACHING_TIER_GBP_INDEP_PAGES_FOUND : + + + POOL_INDEX_CACHING_TIER_GBP_INDEP_PAGES_FOUND : + + + POOL_XDA_CACHING_TIER_GBP_INDEP_PAGES_FOUND : + + + POOL_COL_CACHING_TIER_GBP_INDEP_PAGES_FOUND : + + + TOTAL_HASH_GRPBYS : + + + HASH_GRPBY_OVERFLOWS : + + + POST_THRESHOLD_HASH_GRPBYS : + + + POST_THRESHOLD_OLAP_FUNCS : + + + POST_THRESHOLD_COL_VECTOR_CONSUMERS : + + + TOTAL_COL_VECTOR_CONSUMERS : + + + ADM_OVERFLOWS : + + + ADM_BYPASS_ACT_TOTAL : + + + TOTAL_BACKUP_TIME : + + + TOTAL_BACKUP_PROC_TIME : + + + TOTAL_BACKUPS : + + + TOTAL_INDEX_BUILD_TIME : + + + TOTAL_INDEX_BUILD_PROC_TIME : + + + TOTAL_INDEXES_BUILT : + + + COL_VECTOR_CONSUMER_OVERFLOWS : + + + TOTAL_COL_SYNOPSIS_TIME : + + + TOTAL_COL_SYNOPSIS_PROC_TIME : + + + TOTAL_COL_SYNOPSIS_EXECUTIONS : + + + COL_SYNOPSIS_ROWS_INSERTED : + + + APPL_SECTION_INSERTS : + + + APPL_SECTION_LOOKUPS : + + + LOB_PREFETCH_WAIT_TIME : + + + LOB_PREFETCH_REQS : + + + FED_ROWS_DELETED : + + + FED_ROWS_INSERTED : + + + FED_ROWS_UPDATED : + + + FED_ROWS_READ : + + + FED_WAIT_TIME : + + + FED_WAITS_TOTAL : + + + + + + + + + + Package List + ------------------------ + Package List Size : + + + Package List Exceeded : + + + + + + PACKAGE_ID NESTING_LEVEL ROUTINE_ID INVOCATION_ID PACKAGE_ELAPSED_TIME + -------------------- ------------- ----------- -------------------- -------------------- + + + + + + + + + + + + + Executable List + ------------------------ + Executable List Size : + + + Executable List Truncated : + + + + + + EXECUTABLE_ID NUM_EXECUTIONS ROWS_READ TOTAL_CPU_TIME TOTAL_ACT_TIME TOTAL_ACT_WAIT_TIME LOCK_WAIT_TIME LOCK_WAITS TOTAL_SORTS POST_THRESHOLD_SORTS POST_SHRTHRESHOLD_SORTS SORT_OVERFLOWS + ---------------------------------------------------------------- -------------- ----------- --------------- --------------- ------------------- -------------- ---------- ----------- -------------------- ----------------------- -------------- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/jdbc/DB2LockReportHTML.xsl b/java/jdbc/DB2LockReportHTML.xsl new file mode 100755 index 0000000..b75d8e3 --- /dev/null +++ b/java/jdbc/DB2LockReportHTML.xsl @@ -0,0 +1,499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DB2 Lock Event Report + + + + + + + +

DB2 Lock Event Report

+ +

+ This generated report consists of a summary of lock events captured + followed by the details of each event. To find details for a specific + event,search this file using entry=# where '#' is the value in the entry + column for the specific event. +

+ + + + + + + + + + + + + + + + + + +
Database Name:
Instance Name:
Event Monitor:
Raw table:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Entry '#'TimestampTypeLockTypeParticipantsReqModeHeldModeRequestorHolder
+ + + + 2
+ +
+ + + + + + +
+
+ + + + + + + + + + + + + +
Event ID:
Event Timestamp:
Event Type:
+ + + + +

Lock Details

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lock Name:
Lock Type:
Lock Specifics:
Lock Attributes:
Lock Count:
Lock Hold Count:
Lock rrIID:
Lock Status:
Cursor Bitamp:
Tablespace FID:
Tablespace Name:
Table TID:
Table Name:
+ +
+ + + Unable to obtain Lock Holder information during the occurence of the lock event. +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RequestorHolder
Application Handle:[ + - + ][ + - + ]
Application ID:
Application Name:
Authentication ID:
Requesting Agent ID:
Coordinating Agent ID:
Application Status:
Lock timeout:
Workload ID:
Workload Name:
Service subclass ID:
Service subclass:
Current Request: + () + + () +
Lock Mode: + () + + () +
Lock Mode: + +
Tpmon userid: + +
Tpmon workstation: + +
Tpmon application: + +
Tpmon account string: + +
+ + + + +

Lock Requestor Current Activities

+ + + + + + + + + Current Activities not available. + + + +

Lock Requestor Past Activities

+ + + Past Activities wrapped: + +
+
+ + + +
+ + Past Activities not available. + +
+ +

Lock Owner Current Activities

+ + + + + + + + Current Activities not available. + + + +

Lock Owner Past Activities

+ + + Past Activities wrapped: + +
+
+ + + +
+ + Past Activities not available. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Activity ID:
Uow ID:
Package Name:
Package Schema:
Package Version:
Package Token:
Package SectNo:
Reopt value:
Incremental bind:
Eff locktimeout
Eff isolation
Eff degree
Stmt unicode
Stmt type
Stmt operation
Stmt text
+
+
+ + + + + Inputvar : + Type() + + Value() + + + + + + + + + + Reoptvar : + Type() + + Value() + + + + + + + diff --git a/java/jdbc/DbAuth.java b/java/jdbc/DbAuth.java new file mode 100644 index 0000000..ab319b4 --- /dev/null +++ b/java/jdbc/DbAuth.java @@ -0,0 +1,224 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DbAuth.java +// +// SAMPLE: Grant, display or revoke privileges on database +// +// SQL Statements USED: +// GRANT (Database Authorities) +// SELECT +// REVOKE (Database Authorities) +// COMMIT +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DbAuth.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class DbAuth +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.print("THIS SAMPLE SHOWS HOW TO GRANT/DISPLAY/REVOKE "); + System.out.println("AUTHORITIES ON DATABASE."); + + // connect to the 'sample' database + db.connect(); + + grant(db.con); + display(db.con); + revoke(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // This function shows how to grant user authorities on database + static void grant(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " GRANT (Database Authorities)\n" + + " COMMIT\n" + + "TO GRANT AUTHORITIES AT DATABASE LEVEL.\n"); + + try + { + System.out.println( + " GRANT CONNECT, CREATETAB, BINDADD\n" + + " ON DATABASE\n" + + " TO USER user1"); + Statement stmt = con.createStatement(); + + stmt.execute("GRANT CONNECT, CREATETAB, BINDADD " + + " ON DATABASE" + + " TO USER user1"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // grant + + // helping function: This function displays the authorities for a + // user on a database + static void display(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " SELECT\n" + + "TO DISPLAY AUTHORITIES FOR ANY USER AT DATABASE LEVEL.\n"); + + System.out.println( + " SELECT granteetype, dbadmauth, createtabauth,\n" + + " bindaddauth, connectauth, nofenceauth,\n" + + " implschemaauth, loadauth\n" + + " FROM syscat.dbauth\n" + + " WHERE grantee = 'USER1'\n"); + + + // retrieve and display the result from the SELECT statement + try + { + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT granteetype, dbadmauth, createtabauth, "+ + " bindaddauth, connectauth, nofenceauth, "+ + " implschemaauth, loadauth "+ + " FROM syscat.dbauth " + + " WHERE grantee = 'USER1'"); + + boolean result = rs.next(); + + String granteetype = rs.getString(1); + String dbadmauth = rs.getString(2); + String createtabauth = rs.getString(3); + String bindaddauth = rs.getString(4); + String connectauth = rs.getString(5); + String nofenceauth = rs.getString(6); + String implschemaauth = rs.getString(7); + String loadauth = rs.getString(8); + + rs.close(); + stmt.close(); + + System.out.println( + " Grantee Type = " + granteetype + "\n" + + " DBADM auth. = " + dbadmauth + "\n" + + " CREATETAB auth. = " + createtabauth + "\n" + + " BINDADD auth. = " + bindaddauth + "\n" + + " CONNECT auth. = " + connectauth + "\n" + + " NO_FENCE auth. = " + nofenceauth + "\n" + + " IMPL_SCHEMA auth. = " + implschemaauth + "\n" + + " LOAD auth. = " + loadauth); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // display + + // This function shows how to revoke user authorities on a database + static void revoke(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " REVOKE (Database Authorities)\n" + + " COMMIT\n" + + "TO REVOKE AUTHORITIES AT DATABASE LEVEL."); + + try + { + System.out.println(); + System.out.println( + " REVOKE CONNECT, CREATETAB, BINDADD\n" + + " ON DATABASE\n" + + " FROM USER user1"); + Statement stmt = con.createStatement(); + + stmt.execute("REVOKE CONNECT, CREATETAB, BINDADD " + + " ON DATABASE " + + " FROM USER user1"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // revoke +} // DbAuth + diff --git a/java/jdbc/DbConn.java b/java/jdbc/DbConn.java new file mode 100644 index 0000000..ec4b428 --- /dev/null +++ b/java/jdbc/DbConn.java @@ -0,0 +1,89 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DbConn.java +// +// SAMPLE: How to connect to or disconnect from a database +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DbConn.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; + +class DbConn +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS " + + "HOW TO CONNECT TO/DISCONNECT FROM DATABASES."); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE JAVA 2 CLASSES:\n" + + " Connection\n" + + " DriverManager\n" + + "TO CONNECT TO/DISCONNECT FROM A DATABASE."); + + // connect to the 'sample' database + db.connect(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main +} // DbConn + diff --git a/java/jdbc/DbInfo.java b/java/jdbc/DbInfo.java new file mode 100644 index 0000000..01730f2 --- /dev/null +++ b/java/jdbc/DbInfo.java @@ -0,0 +1,144 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DbInfo.java +// +// SAMPLE: How to get/set info in a database +// +// JAVA 2 CLASSES USED: +// DatabaseMetaData +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DbInfo.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class DbInfo +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO GET/SET INFO ABOUT DATABASES."); + + // connect database + db.connect(); + + // Get information in a database + infoGet(db.con); + db.con.commit(); + + // disconnect database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // main + + static void infoGet(Connection con) + { + System.out.println(); + System.out.println( + "--------------------------------------------------------\n" + + "USE THE JAVA APIs:\n" + + " DatabaseMetaData.getSchemas()\n" + + " ResultSet.getMetaData()\n" + + " DatabaseMetaData.getURL()\n" + + " DatabaseMetaData.isReadOnly()\n" + + " DatabaseMetaData.supportsPositionedDelete()\n" + + "TO GET INFORMATION AT THE DATABASE LEVEL."); + + try + { + DatabaseMetaData dbMetaData = con.getMetaData(); + + System.out.println(); + System.out.println(" Information of The current database:\n"); + + // Get the schema names available in this database + ResultSet rs = dbMetaData.getSchemas(); + System.out.println(" Schema names: "); + String schemaName; + + while (rs.next()) + { + schemaName = rs.getString(1); + System.out.println(" " + schemaName); + } + rs.close(); + System.out.println(); + + // Get the URL for this database + String url = dbMetaData.getURL(); + System.out.println(" Database URL: " + url); + + // Is the database in read-only mode? + boolean isReadOnly = dbMetaData.isReadOnly(); + System.out.println(); + System.out.println(" Database is Read-only: " + isReadOnly); + + // Is positional DELETE supported? + boolean isPosDelete = dbMetaData.supportsPositionedDelete(); + System.out.println(); + System.out.println(" Positioned DELETE supported: " + isPosDelete); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // infoGet +} // DbInfo + diff --git a/java/jdbc/DbMCon.java b/java/jdbc/DbMCon.java new file mode 100644 index 0000000..37ce531 --- /dev/null +++ b/java/jdbc/DbMCon.java @@ -0,0 +1,246 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DbMCon.java +// +// SAMPLE: How to use multiple databases +// +// NOTE: +// This sample program requires a second database +// that has to be created as follows: +// - locally: +// db2 create db sample2 +// - remotely: +// db2 attach to node_name +// db2 create db sample2 +// db2 detach +// db2 catalog db sample2 as sample2 at node node_name +// +// In case another name is used for the second database, +// it can be specified in the command line arguments as +// follows: +// java DbMCon "" "dbAlias2 [userid2 passwd2]" +// +// The second database can be dropped as follows: +// - locally: +// db2 drop db sample2 +// - remotely: +// db2 attach to node_name +// db2 drop db sample2 +// db2 detach +// db2 uncatalog db sample2 +// +// SQL Statements USED: +// CREATE TABLE +// DROP TABLE +// COMMIT +// +// Classes used from Util.java are: +// Db +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DbMCon.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class DbMCon +{ + public static void main(String argv[]) + { + Db db1 = new Db(); + Db db2 = new Db(); + + try + { + setup( argv, db1, db2 ); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO USE MULTIPLE DATABASES."); + + System.out.println("------------------------------------------------"); + db1.connect(); + createTable( db1.con ); + dropTable( db1.con ); + db1.disconnect(); + System.out.println("------------------------------------------------"); + + db2.connect(); + createTable( db2.con ); + dropTable( db2.con ); + db2.disconnect(); + System.out.println("------------------------------------------------"); + } + catch (Exception e) + { + System.out.println(e); + } + } // main + + + private static void setup( String argv[], Db db1, Db db2 ) throws Exception + { + if( argv.length > 11 || + ( argv.length == 1 && + ( argv[0].equals( "?" ) || + argv[0].equals( "-?" ) || + argv[0].equals( "/?" ) || + argv[0].equalsIgnoreCase( "-h" ) || + argv[0].equalsIgnoreCase( "/h" ) || + argv[0].equalsIgnoreCase( "-help" ) || + argv[0].equalsIgnoreCase( "/help" ) ) ) ) + { + throwUsageException(); + } + + // Initialize default database names + db1.alias = "sample"; + db1.server = ""; + db1.portNumber = -1; + db1.userId = ""; + db1.password = ""; + + db2.alias = "sample2"; + db2.server = ""; + db2.portNumber = -1; + db2.userId = ""; + db2.password = ""; + + switch (argv.length) { + case 0: // Use type 2 driver + break; + + case 1: + db1.alias = argv[0]; + break; + + case 2: + // Use type 2 driver with userid/password specified + db1.userId = argv[0]; + db1.password = argv[1]; + break; + + case 3: + // Use type 2 driver with dbname/userid/password specified + db1.alias = argv[0]; + db1.userId = argv[1]; + db1.password = argv[2]; + break; + + case 11: + // Universal type 4 driver + + db1.alias = argv[1]; + db1.server = argv[2]; + db1.portNumber = Integer.valueOf( argv[3] ).intValue(); + db1.userId = argv[4]; + db1.password = argv[5]; + + db2.alias = argv[6]; + db2.server = argv[7]; + db2.portNumber = Integer.valueOf( argv[8] ).intValue(); + db2.userId = argv[9]; + db2.password = argv[10]; + break; + + default: //throw exception + throwUsageException(); + break; + } + + } // setup + + private static void throwUsageException() throws Exception + { + throw new Exception( + "\n" + + "Usage: prog_name [\"connection 1 information\" [\"connection 2 information\"]]\n" + + "\n" + + " where \"connection N information\" is:\n" + + "\n" + + " [dbAlias] [userId passwd] (use JDBC Universal type 2 driver)\n" + + " -u4 [dbAlias] server portNum userId passwd (use JDBC Universal type 4 driver)\n" + + "\n" + + " dbAlias defaults to 'sample' for connection 1 and 'sample2' for connection 2" ); + } + + public static void createTable( Connection con ) + { + System.out.println(); + System.out.println( + " CREATE TABLE books(title VARCHAR(21), price DECIMAL(7, 2))\n"); + + try + { + Statement stmt = con.createStatement(); + stmt.executeUpdate("CREATE TABLE books(title VARCHAR(21), " + + " price DECIMAL(7, 2))"); + stmt.close(); + + System.out.println(" COMMIT\n"); + con.commit(); + } + catch (Exception e) + { + System.out.println(e); + } + } // createTable + + public static void dropTable( Connection con ) + { + System.out.println(" DROP TABLE books\n"); + + try + { + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE books"); + stmt.close(); + + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + System.out.println(e); + } + } // dropTable +} // DbMCon diff --git a/java/jdbc/DbNative.java b/java/jdbc/DbNative.java new file mode 100644 index 0000000..24a2223 --- /dev/null +++ b/java/jdbc/DbNative.java @@ -0,0 +1,117 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DbNative.java +// +// SAMPLE: Converts an SQL statement into the system's native SQL grammar +// +// SQL Statements USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Connection +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DbNative.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class DbNative +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CONVERT A GIVEN SQL STATEMENT INTO \n" + + "THE SYSTEM'S NATIVE SQL GRAMMAR. "); + + // connect to the 'sample' database + db.connect(); + + String stmt = "SELECT * FROM employee WHERE hiredate={d '1994-03-29'}"; + String odbcEscapeClause = "{d '1994-03-29'}"; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE API Function:\n" + + " Connection.nativeSQL()\n" + + "TO CONVERT AN SQL STATEMENT INTO THE SYSTEM'S NATIVE SQL GRAMMAR"); + + System.out.println(); + System.out.println( + " Translate the statement\n\n" + + " " + stmt + "\n\n" + + " that contains the ODBC escape clause" + odbcEscapeClause + "\n" + + " into the system's native SQL grammar:\n"); + + // The Java 2 method Connection.nativeSQL() converts the given SQL + // statement into the system's native SQL grammar. + String nativeSql = db.con.nativeSQL(stmt); + if (nativeSql == null) + { + System.out.println("Invalid ODBC statement\n"); + } + else + { + System.out.println(" " + nativeSql); + } + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // main +} // DbNative + diff --git a/java/jdbc/DbRsHold.java b/java/jdbc/DbRsHold.java new file mode 100644 index 0000000..e4d7821 --- /dev/null +++ b/java/jdbc/DbRsHold.java @@ -0,0 +1,426 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DbRsHold.java +// +// SAMPLE: How to use result set cursor holdability in Universal JDBC driver. +// The Universal JDBC driver implements the result set cursor holdability +// APIS specified in JDBC3. To compile this sample, you need JDK1.4 +// or above; To run this sample, you need JRE1.4 or above. +// +// SQL Statements Used: +// SELECT +// UPDATE +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DbRsHold.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.*; +import java.lang.*; +import java.util.*; +import java.sql.*; +import javax.sql.*; + +public class DbRsHold +{ + // The SQL statements used in this sample + static final String sqlQuery = "SELECT empno, firstnme, lastname, salary " + + " FROM employee WHERE workdept='A00'"; + static final String sqlUpdt = "SELECT empno, firstnme, lastname, salary\n" + + " FROM employee WHERE workdept='A00'" + + " FOR UPDATE of salary"; + static double salaryInc = 0.0; + + public static void main(String[] args) + { + if( args.length > 5 || + ( args.length == 1 && + ( args[0].equals( "?" ) || + args[0].equals( "-?" ) || + args[0].equals( "/?" ) || + args[0].equalsIgnoreCase( "-h" ) || + args[0].equalsIgnoreCase( "/h" ) || + args[0].equalsIgnoreCase( "-help" ) || + args[0].equalsIgnoreCase( "/help" ) ) ) ) + { + System.out.println( + "Usage: prog_name -u2 [dbAlias] [userId passwd] " + + "(use universal JDBC type 2 driver)\n" + + " prog_name [dbAlias] server portNum userId passwd " + + "(use universal JDBC type 4 driver)"); + System.exit(0); + } + + // Check the JRE version. JRE1.4 or above is required + String jreVersion = System.getProperty("java.version"); + StringTokenizer token = new StringTokenizer(jreVersion, "."); + String simpVersion = jreVersion; + + if(token.hasMoreTokens()) + simpVersion = token.nextToken(); + if(token.hasMoreTokens()) + simpVersion = simpVersion + "." + token.nextToken(); + + float fVersion = (new Float(simpVersion)).floatValue(); + if(fVersion < (float)1.4) + { + System.out.println("To run this sample by using the Universal JDBC" + + " driver, you need JRE1.4 or above"); + System.exit(0); + } + + holdabilityOfUniversalDriver(args); + + } //main + + static void holdabilityOfUniversalDriver(String[] args) + { + // Db class is used to connect to the database + // Variable conn is the connection that shows cursor holdability changes + // Variable connDd is the connection that displays data in the table + Db db = null; + Db dbDd = null; + Connection conn = null; + Connection connDd = null; + + try + { + db = new Db(args); + conn = db.connect(); + dbDd = new Db(args); + connDd = dbDd.connect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + // Print different types of result set cursor holdability + System.out.println( + "-----------------------------------------------------------------\n" + + "ResultSet.HOLD_CURSORS_OVER_COMMIT = " + + ResultSet.HOLD_CURSORS_OVER_COMMIT); + System.out.println( + "ResultSet.CLOSE_CURSORS_AT_COMMIT = " + + ResultSet.CLOSE_CURSORS_AT_COMMIT + "\n"); + + // Set cursor holdability at connection level: HOLD_CURSORS_OVER_COMMIT + System.out.println( + "-----------------------------------------------------------------\n" + + "Set cursor holdability at connection level: " + + "HOLD_CURSORS_OVER_COMMIT\n"); + salaryInc = 2000.00; + setHoldabilityAtConnection(conn, + ResultSet.HOLD_CURSORS_OVER_COMMIT, + connDd); + + // Set cursor holdability at connection level: CLOSE_CURSORS_AT_COMMIT + // SQLException is expected since the cursor will be closed at commit + System.out.println( + "-----------------------------------------------------------------\n" + + "Set cursor holdability at connection level: " + + "CLOSE_CURSORS_AT_COMMIT\n" + + "'Result set closed' ERROR IS EXPECTED AFTER THE FIRST COMMIT\n"); + setHoldabilityAtConnection(conn, + ResultSet.CLOSE_CURSORS_AT_COMMIT, + connDd); + + // Set cursor holdability at statement level: HOLD_CURSORS_OVER_COMMIT + System.out.println( + "-----------------------------------------------------------------\n" + + "Set cursor holdability at statement level: " + + "HOLD_CURSORS_OVER_COMMIT"); + salaryInc = -2000.0; + setHoldabilityAtStatement(conn, + ResultSet.HOLD_CURSORS_OVER_COMMIT, + connDd); + + // Set cursor holdability at statement level: CLOSE_CURSORS_AT_COMMIT + // SQLException is expected since the cursor will be closed at commit + System.out.println( + "-----------------------------------------------------------------\n" + + "Set cursor holdability at statement level: " + + "CLOSE_CURSORS_AT_COMMIT\n" + + "'Result set closed' ERROR IS EXPECTED AFTER THE FIRST COMMIT\n"); + setHoldabilityAtStatement(conn, + ResultSet.CLOSE_CURSORS_AT_COMMIT, + connDd); + + System.out.println( + "-----------------------------------------------------------------"); + + try + { + db.disconnect(); + dbDd.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + } // holdabilityOfUniversalDriver + + // This method shows how to set cursor holdability at the connection level + static void setHoldabilityAtConnection(Connection conn, + int holdability, + Connection connDd) + { + ResultSet rs = null; + + try + { + // Set cursor holdability at the connection level + conn.setHoldability(holdability); + + // Print the cursor holdability of the connection + System.out.println("Connection.getHoldability = " + + conn.getHoldability()); + + // Print the database MetaData supports for cursor holdability + DatabaseMetaData dbMeta = conn.getMetaData(); + System.out.println("DatabaseMetaData.getResultSetHoldability = " + + dbMeta.getResultSetHoldability()); + System.out.println(" Supports HOLD_CURSORS_OVER_COMMIT = " + + dbMeta.supportsResultSetHoldability( + ResultSet.HOLD_CURSORS_OVER_COMMIT)); + System.out.println(" Supports CLOSE_CURSORS_AT_COMMIT = " + + dbMeta.supportsResultSetHoldability( + ResultSet.CLOSE_CURSORS_AT_COMMIT)); + + // Create a statement with the holdability from the connection + Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, + ResultSet.CONCUR_UPDATABLE); + + // Print the cursor holdability of the statement, + // which should be same as the connection's + System.out.println("Statement.getResultSetHoldability = " + + stmt.getResultSetHoldability() + "\n"); + + // Execute the query and obtain the result set + rs = stmt.executeQuery(sqlQuery); + + // Update rows in the result set and commit one by one + updateData(conn, rs, connDd); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + if (rs != null) + rs.close(); + } + catch(Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } + + } // setHoldabilityAtConnection + + // This method shows how to set cursor holdability at the statement level + static void setHoldabilityAtStatement(Connection conn, + int holdability, + Connection connDd) + { + ResultSet rs = null; + + try + { + // Print the cursor holdability of the connection + System.out.println("Connection.getHoldability = " + + conn.getHoldability()); + + // Print the database MetaData supports for cursor holdability + DatabaseMetaData dbMeta = conn.getMetaData(); + System.out.println("DatabaseMetaData.getResultSetHoldability = " + + dbMeta.getResultSetHoldability()); + System.out.println(" Supports HOLD_CURSORS_OVER_COMMIT = " + + dbMeta.supportsResultSetHoldability( + ResultSet.HOLD_CURSORS_OVER_COMMIT)); + System.out.println(" Supports CLOSE_CURSORS_AT_COMMIT = " + + dbMeta.supportsResultSetHoldability( + ResultSet.CLOSE_CURSORS_AT_COMMIT)); + + // Set cursor holdability at the statement level + // which can override the connection's + PreparedStatement prepStmt = conn.prepareStatement(sqlQuery, + ResultSet.TYPE_SCROLL_SENSITIVE, + ResultSet.CONCUR_UPDATABLE, + holdability); + + // Print the cursor holdability of the statement, + // which can be different from the connection's + System.out.println("Statement.getResultSetHoldability = " + + (prepStmt).getResultSetHoldability() + + "\n"); + + // Execute the query and obtain the result set + rs = prepStmt.executeQuery(); + + // Update rows in the result set and commit one by one + updateData(conn, rs, connDd); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + if (rs != null) + rs.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } + + } // setHoldabilityAtStatement + + // This method updates the rows in the result set and commit one by one. + // Depending on the result set cursor holdability, the cursor is open or + // closed each commits. + static void updateData(Connection conn, + ResultSet rs, + Connection connDd) + { + try + { + System.out.println("Original data:"); + displayData(connDd); + int num = 1; + + while (rs.next()) + { + System.out.println("UPDATE salary: row " + num); + float salary = rs.getFloat("SALARY"); + rs.updateFloat("SALARY", (float)(salary + salaryInc)); + rs.updateRow(); + + // If cursor holdability is HOLD_CURSORS_OVER_COMMIT, + // the cursor is still open after commit; + // If cursor holdability is CLOSE_CURSORS_AT_COMMIT, + // the cursor is closed after commit. + System.out.println("COMMIT updates: row " + num); + conn.commit(); + + displayData(connDd); + num ++; + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + } // updateData + + // This method is a helping method. It displays the content + // in the EMPLOYEE table and reflects the data updates. + static void displayData(Connection connDd) + { + ResultSet rs = null; + + try + { + // Create a prepared statement to execute the query + PreparedStatement prepStmt = connDd.prepareStatement(sqlQuery, + ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY); + + // Execute the query and obtain the result set + rs = prepStmt.executeQuery(); + + // Print the content of the result set + System.out.println( + " EMPNO NAME SALARY\n" + + " ------ ------------------- ----------"); + while (rs.next()) + System.out.println(" " + Data.format(rs.getString("EMPNO"), 7) + + Data.format(rs.getString("FIRSTNME") + " " + + rs.getString("LASTNAME"), 20) + + rs.getFloat("SALARY")); + System.out.println(); + connDd.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + if (rs != null) + rs.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } + + } // displayData + +} // DbRsHold diff --git a/java/jdbc/DbSeq.java b/java/jdbc/DbSeq.java new file mode 100644 index 0000000..ae1408f --- /dev/null +++ b/java/jdbc/DbSeq.java @@ -0,0 +1,437 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DbSeq.java +// +// SAMPLE: How to create, alter and drop a sequence in a database +// +// This sample demonstrates how to create, alter and drop a +// sequence object. It also demonstrates how to use 'next value' +// and 'previous value' with a sequence object. +// +// SQL STATEMENTS USED: +// CREATE SEQUENCE +// ALTER SEQUENCE +// DROP SEQUENCE +// INSERT +// SELECT +// COMMIT +// ROLLBACK +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DbSeq.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import java.lang.*; + +class DbSeq +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO USE A SEQUENCE IN A DATABASE."); + + // connect to the 'sample' database + db.connect(); + + createSequence(db.con); + + // The following code demonstrates how to GRANT the usage permission + // on the sequence 'id_seq' to a user, Tom, from Bob. Comment out the + // following and replace 'Tom' with the user you want to grant usage + // permission to. + + // Statement grantstmt = con.createStatement(); + // grantstmt.executeUpdate("GRANT USAGE ON SEQUENCE id_seq TO Tom"); + // grantstmt.close(); + + // The following code demonstrates how to REVOKE the usage permission + // on the sequence 'id_seq' from Tom by Bob. Comment out the + // following, replace 'Bob' with your user name and 'Tom' with the + // user you want to revoke usage permission from. + + // Statement revostmt = con.createStatement(); + // revostmt.executeUpdate( + // "REVOKE USAGE ON SEQUENCE id_seq FROM Tom BY Bob"); + // revostmt.close(); + + nextValSeq(db.con); + prevValSeq(db.con); + dropSequence(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + } //main + + // Helping function: This function is used to display the contents of + // the tables created in this sample program. + static void tbContentDisplay(Connection con, String tableName) + { + try + { + int empNo; + String info = null; + + String column = "Name"; + System.out.println("\n SELECT * FROM " + tableName); + + if (tableName.equalsIgnoreCase("emp_location")) + { + column="Location"; + } + System.out.println(" EmpNo " + column); + System.out.println(" ----- ----------"); + PreparedStatement pstmt = con.prepareStatement( + "SELECT * FROM " + tableName); + + ResultSet rs = pstmt.executeQuery(); + + while (rs.next()) + { + info = rs.getString(2); + empNo = rs.getInt(1); + System.out.println(" "+empNo + " " + info); + } + rs.close(); + pstmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tbContentDisplay + + // This function shows how to create a table and a sequence in a database. + static void createSequence(Connection con) + { + try + { + System.out.println( + "\n---------------------------------------------------\n"+ + "USE THE SQL STATEMENT:\n" + + " CREATE SEQUENCE\n" + + "TO CREATE A SEQUENCE."); + + // Create a sequence object called 'id_seq' that generates the + // employee's ID number. + System.out.println(); + System.out.println( + " CREATE SEQUENCE id_seq\n" + + " AS INTEGER\n" + + " START WITH 400\n" + + " INCREMENT BY 10\n" + + " NO MINVALUE\n" + + " MAXVALUE 430\n" + + " NO CYCLE\n" + + " NO CACHE"); + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE SEQUENCE id_seq AS INTEGER START WITH 400 " + + "INCREMENT BY 10 NO MINVALUE MAXVALUE 430 NO CYCLE " + + "NO CACHE"); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // createTbAndSeq + + // This function shows how to drop a table and a sequence object in a + // database. + static void dropSequence(Connection con) + { + try + { + System.out.println(); + System.out.println( + "------------------------------------------------\n"+ + "USE THE SQL STATEMENT:\n" + + " DROP SEQUENCE\n" + + "TO DROP A SEQUENCE."); + + // drop a sequence object called 'id_seq' + System.out.println(); + System.out.println(" DROP SEQUENCE id_seq RESTRICT"); + + Statement drop = con.createStatement(); + drop.executeUpdate("DROP SEQUENCE id_seq RESTRICT"); + drop.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // dropTbAndSeq + + // This function shows how to alter a sequence object. + static void alterSeq(Connection con) + { + try + { + System.out.println( + "USE THE SQL STATEMENTS:\n" + + " ALTER\n" + + "TO ALTER A SEQUENCE"); + + // Alter the sequence to restart from 430 with a range of 400 to 430 + // inclusively while incrementing by -10 (decrementing by 10) with + // no maximum value. + System.out.println(); + System.out.println( + " ALTER SEQUENCE id_seq\n" + + " RESTART WITH 430\n" + + " INCREMENT BY -10\n" + + " MINVALUE 400\n" + + " NO MAXVALUE\n" + + " CYCLE\n" + + " CACHE 10"); + + Statement altstmt = con.createStatement(); + altstmt.executeUpdate( + "ALTER SEQUENCE id_seq RESTART WITH 430 INCREMENT BY -10" + + " MINVALUE 400 NO MAXVALUE CYCLE CACHE 10"); + altstmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // alterSeq + + // This function shows how to use a sequence with 'NEXT VALUE' to insert + // table data and generate a gap. + static void nextValSeq(Connection con) + { + try + { + System.out.println(); + System.out.println( + "---------------------------------------------------\n"+ + "USE THE SQL STATEMENTS:\n" + + " INSERT\n" + + "TO INSERT TABLE DATA USING A SEQUENCE WITH 'NEXT VALUE'"); + + // create a table called 'contract_emp' + System.out.println(); + System.out.println( + " CREATE TABLE contract_emp(empNo INTEGER, name CHAR(10))"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE contract_emp(empNo INTEGER, name CHAR(10))"); + stmt.close(); + + // insert table data using 'NEXT VALUE' + System.out.println(); + System.out.println( + " INSERT INTO contract_emp\n" + + " VALUES(NEXT VALUE FOR id_seq, 'shameem')\n"); + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO contract_emp VALUES(NEXT VALUE FOR id_seq, 'shameem')"); + stmt1.close(); + + System.out.println(" COMMIT\n"); + con.commit(); + + // display the content of the 'contract_emp' table + tbContentDisplay(con, "contract_emp"); + + // insert table data using 'NEXT VALUE' + System.out.println( + " INSERT INTO contract_emp\n" + + " VALUES(NEXT VALUE FOR id_seq, 'mohammed')\n"); + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "INSERT INTO contract_emp VALUES(NEXT VALUE FOR id_seq, 'mohammed')"); + stmt2.close(); + + // display the content of the 'contract_emp' table + tbContentDisplay(con, "contract_emp"); + + System.out.println(" ROLLBACK\n"); + con.rollback(); + + // display the content of the 'contract_emp' table + tbContentDisplay(con, "contract_emp"); + + // insert table data using 'NEXT VALUE' + System.out.println(); + System.out.println( + " INSERT INTO contract_emp\n" + + " VALUES(NEXT VALUE FOR id_seq, 'sunny')\n"); + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate( + "INSERT INTO contract_emp VALUES(NEXT VALUE FOR id_seq,'sunny')"); + stmt3.close(); + + // display the content of the 'contract_emp' table + tbContentDisplay(con, "contract_emp"); + + System.out.println(); + System.out.println( + " Note:\n"+ + " The new insertion has EmpNo 420. Note the gap in the\n"+ + " EmpNo. This shows numbers generated by SEQUENCE are\n"+ + " independent of the status of the transaction that\n"+ + " generated the previous value in the sequence.\n"); + + System.out.println( + " Altering the sequence to show overlap can be generated by\n"+ + " a sequence object.\n"); + alterSeq(con); + + // insert table data using 'NEXT VALUE' after altering the sequence + System.out.println(); + System.out.println( + " INSERT INTO contract_emp\n" + + " VALUES(NEXT VALUE FOR id_seq, 'saba')\n"+ + " (NEXT VALUE FOR id_seq, 'repeat')"); + + Statement stmt4 = con.createStatement(); + stmt4.executeUpdate( + "INSERT INTO contract_emp VALUES(NEXT VALUE FOR " + + "id_seq,'saba'), (NEXT VALUE FOR id_seq, 'repeat')"); + stmt4.close(); + + // display the content of the 'contract_emp' table after altering the + // sequence + tbContentDisplay(con, "contract_emp"); + + System.out.println(); + System.out.println( + " Note:\n"+ + " One of the new insertions has EmpNo 420 which\n" + + " already exists. This happened because the new altered range\n" + + " of sequence overlaps the old one. It is the responsibility\n" + + " of the programmer to ensure that these overlaps do not\n" + + " occur if they are not wanted.\n"); + + // drop the table 'emp_location' + System.out.println(" DROP TABLE contract_emp"); + Statement drop = con.createStatement(); + drop.executeUpdate("DROP TABLE contract_emp"); + drop.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // nextValSeq + + // This function shows how to use a sequence with 'PREVIOUS VALUE' to insert + // the last generated sequence value into a table. + static void prevValSeq(Connection con) + { + try + { + System.out.println(); + System.out.println( + "---------------------------------------------------\n"+ + "USE THE SQL STATEMENTS:\n" + + " INSERT INTO PREVIOUS VALUE\n" + + "TO INSERT DATA INTO A TABLE USING A SEQUENCE WITH 'PREVIOUS VALUE'"); + + // create a table called 'emp_location' + System.out.println(); + System.out.println( + " CREATE TABLE emp_location(empNo INTEGER, city CHAR(10))\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE emp_location(empNo INTEGER, city CHAR(10))"); + stmt.close(); + + // insert table data using 'PREVIOUS VALUE' + System.out.println( + " INSERT INTO emp_location\n" + + " VALUES(PREVIOUS VALUE FOR id_seq, 'repeat')"); + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO emp_location VALUES(PREVIOUS VALUE FOR id_seq, 'repeat')"); + stmt1.close(); + + // display the content of the 'emp_location' table + tbContentDisplay(con, "emp_location"); + + System.out.println(); + System.out.println( + " Note:\n"+ + " By using SEQUENCE with 'PREVIOUS VALUE', you can insert\n"+ + " into a different table with the last generated\n"+ + " EmpNo.\n"); + + // drop the 'emp_location' table + System.out.println(" DROP TABLE emp_location"); + Statement drop = con.createStatement(); + drop.executeUpdate("DROP TABLE emp_location"); + drop.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // prevValSeq +} // DbSeq + diff --git a/java/jdbc/DbUse.java b/java/jdbc/DbUse.java new file mode 100644 index 0000000..e056e0b --- /dev/null +++ b/java/jdbc/DbUse.java @@ -0,0 +1,219 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DbUse.java +// +// SAMPLE: How to use a database +// +// SQL Statements USED: +// CREATE TABLE +// DROP TABLE +// DELETE +// COMMIT +// ROLLBACK +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DbUse.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class DbUse +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO USE A DATABASE."); + + // connect to the 'sample' database + db.connect(); + + execStatement(db.con); + execPreparedStatement(db.con); + execPreparedStatementWithParam(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void execStatement(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " Statement\n" + + "TO EXECUTE A STATEMENT."); + + try + { + Statement stmt = con.createStatement(); + + // execute the statement + System.out.println(); + System.out.println(" CREATE TABLE t1(col1 INTEGER)"); + stmt.execute("CREATE TABLE t1(col1 INTEGER)"); + + // commit the transaction + System.out.println(" COMMIT"); + con.commit(); + + // execute the statement + System.out.println(" DROP TABLE t1"); + stmt.execute("DROP TABLE t1"); + + // commit the transaction + System.out.println(" COMMIT"); + con.commit(); + + // close the statement + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // execStatement + + static void execPreparedStatement(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " PreparedStatement\n" + + "TO EXECUTE A PREPARED STATEMENT."); + + try + { + // prepare the statement + System.out.println(); + System.out.println(" Prepared the statement:\n" + + " DELETE FROM org WHERE deptnumb <= 70"); + + PreparedStatement prepStmt = con.prepareStatement( + " DELETE FROM org WHERE deptnumb <= 70"); + + // execute the statement + System.out.println(); + System.out.println(" Executed the statement"); + prepStmt.execute(); + + // rollback the transaction + System.out.println(); + System.out.println(" ROLLBACK"); + con.rollback(); + + // close the statement + prepStmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // execPreparedStatement + + static void execPreparedStatementWithParam(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " PreparedStatement\n" + + "TO EXECUTE A PREPARED STATEMENT WITH PARAMETERS."); + + try + { + // prepare the statement + System.out.println(); + System.out.println( + " Prepared the statement:\n" + + " DELETE FROM org WHERE deptnumb <= ? AND division = ?"); + + PreparedStatement prepStmt = con.prepareStatement( + " DELETE FROM org WHERE deptnumb <= ? AND division = ? "); + + // execute the statement + System.out.println(); + System.out.println(" Executed the statement for:\n" + + " parameter 1 = 70\n" + + " parameter 2 = 'Eastern'"); + + prepStmt.setInt(1, 70); + prepStmt.setString(2, "Eastern"); + prepStmt.execute(); + + // rollback the transaction + System.out.println(); + System.out.println(" ROLLBACK"); + con.rollback(); + + // close the statement + prepStmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // execPreparedStatementWithParam +} // DbUse + diff --git a/java/jdbc/DropCGTT.db2 b/java/jdbc/DropCGTT.db2 new file mode 100644 index 0000000..5782f2b --- /dev/null +++ b/java/jdbc/DropCGTT.db2 @@ -0,0 +1,56 @@ +------------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +------------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: DropCGTT.db2 +-- +-- SAMPLE: +-- i) This script cleans-up all the database objects created by executing +-- the script file CreateCGTT.db2. +-- +-- Note: Use following command to execute the sample: +-- db2 -td@ -vf DropCGTT.db2 +-- +-- SQL STATEMENTS USED: +-- 1) TRUNCATE TABLE +-- 2) DROP +------------------------------------------------------------------------------- + +-- Remove contents from the created temporary table. +TRUNCATE TABLE cgtt.tax_cal IMMEDIATE@ + +-- DROP the trigger, procedure, and function created by the sample. . +DROP TRIGGER cgtt.tax_update@ +DROP FUNCTION cgtt.tax_compute@ +DROP SPECIFIC PROCEDURE cgtt.updater@ +DROP SPECIFIC PROCEDURE cgtt.initialTax@ +DROP SPECIFIC PROCEDURE cgtt.finalTax@ +DROP FUNCTION cgtt.printITSheet@ + +-- DROP all the tables, indexes, and views created by the sample. +DROP INDEX cgtt.IndexOnId@ +DROP TABLE cgtt.tax_cal@ +DROP TABLE cgtt.payroll@ +DROP VIEW cgtt.ViewOnCgtt@ + +-- DROP tablespaces created by the sample +DROP TABLESPACE TbspaceCgtt@ +DROP TABLESPACE TbspacePayroll@ +DROP BUFFERPOOL BufForSample@ +-------------------------------------------------------------------------------- diff --git a/java/jdbc/DropGTF.db2 b/java/jdbc/DropGTF.db2 new file mode 100644 index 0000000..650e439 --- /dev/null +++ b/java/jdbc/DropGTF.db2 @@ -0,0 +1,37 @@ +------------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2010 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +------------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: DropGTF.db2 +-- +-- SAMPLE: +-- i) This script cleans-up all the database objects created by executing +-- the script file CreateGTF.db2. +-- +-- Note: Use following command to execute the sample: +-- db2 -tvf DropGTF.db2 +-- +------------------------------------------------------------------------------- +CONNECT TO sample; + +drop specific function csvReadString; +drop specific function csvRead; +drop specific function httpCsvReadString; +drop specific function hadoopCsvReadString; + diff --git a/java/jdbc/DtInfo.java b/java/jdbc/DtInfo.java new file mode 100644 index 0000000..37276eb --- /dev/null +++ b/java/jdbc/DtInfo.java @@ -0,0 +1,204 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DtInfo.java +// +// SAMPLE: How to get information about data types +// +// JAVA 2 CLASSES USED: +// Connection +// ResultSet +// ResultSetMetaData +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DtInfo.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class DtInfo +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO GET INFO ABOUT DATA TYPES."); + + // connect to the 'sample' database + db.connect(); + + // Get information about the Data type + infoGet(db.con); + + db.con.commit(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void infoGet(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA APIs:\n" + + " Connection.getMetaData()\n" + + " ResultSet.getTypeInfo()\n" + + " ResultSetMetaData.getMetaData()\n" + + "TO GET INFO ABOUT DATA TYPES AND\n" + + "TO RETRIEVE THE AVAILABLE INFO IN THE RESULT SET."); + + DatabaseMetaData dbMetaData = con.getMetaData(); + + // Get a description of all the standard SQL types supported by + // this database + ResultSet rs = dbMetaData.getTypeInfo(); + + // Retrieve the number, type and properties of the resultset's columns + ResultSetMetaData rsMetaData = rs.getMetaData(); + + // Get the number of columns in the ResultSet + int colCount = rsMetaData.getColumnCount(); + System.out.println(); + System.out.println( + " Number of columns in the ResultSet = " + colCount); + + // Retrieve and display the column's name along with its type + // and precision in the ResultSet + System.out.println(); + System.out.println(" A LIST OF ALL COLUMNS IN THE RESULT SET:\n" + + " Column Name Column Type\n" + + " ------------------- -----------"); + + String colName, colType; + for (int i = 1 ; i <= colCount ; i++) + { + colName = rsMetaData.getColumnName(i); + colType = rsMetaData.getColumnTypeName(i); + System.out.println( + " " + Data.format(colName, 19) + + " " + Data.format(colType, 13) + " "); + } + + System.out.println(); + System.out.println( + " HERE ARE SOME OF THE COLUMNS' INFO IN THE TABLE ABOVE:\n"+ + " TYPE_NAME DATA_ COLUMN NULL- CASE_\n"+ + " TYPE _SIZE ABLE SENSITIVE\n"+ + " (int) \n"+ + " ------------------------- ----- ---------- ----- ---------"); + + String typeName; + int dataType; + Integer columnSize; + boolean nullable; + boolean caseSensitive; + + // Retrieve and display the columns' information in the table + while (rs.next()) + { + typeName = rs.getString(1); + dataType = rs.getInt(2); + if (rs.getInt(7) == 1) + { + nullable = true; + } + else + { + nullable = false; + } + if (rs.getInt(8) == 1) + { + caseSensitive = true; + } + else + { + caseSensitive = false; + } + if (rs.getString(3) != null) + { + columnSize = Integer.valueOf(rs.getString(3)); + System.out.println( + " " + Data.format(typeName, 25) + + " " + Data.format(dataType, 5) + + " " + Data.format(columnSize, 10) + + " " + Data.format(String.valueOf(nullable), 5) + + " " + Data.format(String.valueOf(caseSensitive), 10)); + } + else + // for the distinct data type, column size does not apply + { + System.out.println( + " " + Data.format(typeName, 25) + + " " + Data.format(dataType, 5) + + " n/a" + + " " + Data.format(String.valueOf(nullable), 5) + + " " + Data.format(String.valueOf(caseSensitive), 10)); + } + } + // close the result set + rs.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } +} // DtInfo + diff --git a/java/jdbc/DtLob.java b/java/jdbc/DtLob.java new file mode 100644 index 0000000..86206be --- /dev/null +++ b/java/jdbc/DtLob.java @@ -0,0 +1,547 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DtLob.java +// +// SAMPLE: How to use LOB data type +// +// This program ONLY works with jdk 1.2.2 or later version. +// +// Before running this sample, ensure that you set the database +// manager configuration parameter UDF Shared Memory Set Size +// (udf_mem_sz) to at least two pages more than the larger +// of the input arguments or the resulting CLOB being retrieved. +// +// For example, issue: db2 UPDATE DBM CFG USING udf_mem_sz 1024 +// to run this sample program against the SAMPLE database. +// +// Stop and restart the server for the change to take effect. +// +// SQL Statements USED: +// SELECT +// INSERT +// DELETE +// +// JAVA 2 CLASSES USED: +// Connection +// PreparedStatement +// Statement +// ResultSet +// Clob +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DtLob.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.*; +import java.lang.*; +import java.util.*; +import java.sql.*; + +class DtLob +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO USE LOB DATA TYPE."); + + // connect to the 'sample' database + db.connect(); + + blobFileUse(db.con); + clobUse(db.con); + clobFileUse(db.con); + clobSearchStringUse(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void blobFileUse(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + " INSERT\n" + + " DELETE\n" + + "TO SHOW HOW TO USE BINARY LARGE OBJECT (BLOB) FILES."); + + String osName = System.getProperty("os.name"); + String photoFormat; + String fileName; + String empno; + + if (osName.equals("Windows NT")) + { + photoFormat = "bitmap"; + fileName = "photo.BMP"; + } + else + { + // UNIX + photoFormat = "gif"; + fileName = "photo.GIF"; + } + + // ---------- Read BLOB data from file ------------------- + System.out.println(); + System.out.println( + " ---------------------------------------------------\n" + + " READ BLOB DATA FROM THE FILE '" + fileName + "':"); + + System.out.println(); + System.out.println( + " Prepare the statement:\n" + + " SELECT picture\n" + + " FROM emp_photo\n" + + " WHERE photo_format = ? AND empno = ?"); + + PreparedStatement pstmt = con.prepareStatement( + "SELECT picture " + + " FROM emp_photo " + + " WHERE photo_format = ? AND empno = ?"); + + System.out.println(); + System.out.println( + " Execute the prepared statement using:\n" + + " photo_format = 'bitmap'\n" + + " empno = '000130'"); + + empno = "000130"; + pstmt.setString(1, photoFormat); + pstmt.setString(2, empno); + ResultSet rs = pstmt.executeQuery(); + rs.next(); + Blob blob = rs.getBlob(1); + + System.out.println(); + System.out.println(" READ FROM BLOB FILE SUCCESSFULLY!"); + + // -------------- Write BLOB data into file ----------------- + System.out.println(); + System.out.println( + " ---------------------------------------------------\n" + + " INSERT BLOB FILE " + fileName + " INTO THE DB:"); + + System.out.println(); + System.out.println( + " Prepare the statement:\n" + + " INSERT INTO emp_photo(photo_format, empno, picture)\n" + + " VALUES (?, ?, ?)"); + + PreparedStatement pstmt2 = con.prepareStatement( + "INSERT INTO emp_photo (photo_format, empno, picture) " + + " VALUES (?, ?, ?)"); + + System.out.println(); + System.out.println( + " Execute the prepared statement using:\n" + + " photo_format = 'bitmap'\n" + + " empno = '200140'\n" + + " And the blob object that we get from reading the\n" + + " file 'photo.*' eariler."); + + empno = "200140"; + pstmt2.setString(1, photoFormat); + pstmt2.setString(2, empno); + pstmt2.setBlob(3, blob); + pstmt2.executeUpdate(); + rs.close(); + pstmt.close(); + pstmt2.close(); + + System.out.println(); + System.out.println(" INSERT BLOB FILE TO DB SUCCESSFULLY!"); + + // ------------ Delete NEW RECORD from the database --------- + System.out.println(); + System.out.println( + " ---------------------------------------------------\n" + + " DELETE THE NEW RECORD FROM THE DATABASE:"); + + System.out.println(); + System.out.println( + " Prepare the statement:\n" + + " DELETE FROM emp_photo WHERE empno = ?"); + + PreparedStatement pstmt3 = con.prepareStatement( + "DELETE FROM emp_photo WHERE empno = ? "); + + System.out.println(); + System.out.println( + " Execute the prepared statement using:\n" + + " empno = '200140'"); + + pstmt3.setString(1, empno); + pstmt3.executeUpdate(); + pstmt3.close(); + + System.out.println(); + System.out.println(" DELETE THE NEW RECORD FROM DB SUCCESSFULLY!"); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // blobFileUse + + static void clobUse(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + " INSERT\n" + + " DELETE\n" + + "TO SHOW HOW TO USE CHARACTER LARGE OBJECT (CLOB) DATA TYPE."); + + // ----------- Read CLOB data type from DB ---------------- + System.out.println(); + System.out.println( + " ---------------------------------------------------\n" + + " READ CLOB DATA TYPE:"); + + System.out.println(); + System.out.println( + " Execute the statement:\n" + + " SELECT resume\n" + + " FROM emp_resume\n" + + " WHERE resume_format = 'ascii' AND empno = '000130'\n" + + "\n" + + " Note: resume is a CLOB data type!"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT resume " + + " FROM emp_resume " + + " WHERE resume_format = 'ascii' AND empno = '000130'"); + + rs.next(); + Clob clob = rs.getClob(1); + + System.out.println(); + System.out.println(" READ CLOB DATA TYPE FROM DB SUCCESSFULLY!"); + + // ------------ Display the CLOB data onto the screen ------- + long clobLength = clob.length(); + + System.out.println(); + System.out.println( + " ---------------------------------------------------\n" + + " HERE IS THE RESUME WITH A LENGTH OF " + clobLength + + " CHARACTERS."); + + String clobString = clob.getSubString(1, (int)clobLength); + System.out.println(); + System.out.println(clobString); + System.out.println(" --- END OF RESUME ---"); + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // clobUse + + static void clobFileUse(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO SHOW HOW TO USE CHARACTER LARGE OBJECT (CLOB) DATA TYPE."); + + String fileName = "RESUME.TXT"; + + // ----------- Read CLOB data type from DB ----------------- + System.out.println(); + System.out.println( + " ---------------------------------------------------\n" + + " READ CLOB DATA TYPE:"); + + System.out.println(); + System.out.println( + " Execute the statement:\n" + + " SELECT resume\n" + + " FROM emp_resume\n" + + " WHERE resume_format = 'ascii' AND empno = '000130'\n" + + "\n" + + " Note: resume is a CLOB data type!"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT resume " + + " FROM emp_resume " + + " WHERE resume_format = 'ascii' AND empno = '000130'"); + rs.next(); + Clob clob = rs.getClob(1); + + System.out.println(); + System.out.println(" READ CLOB DATA TYPE DB SUCCESSFULLY!"); + + // ---------- Write CLOB data into file ------------------- + long clobLength = clob.length(); + + System.out.println( + " ---------------------------------------------------\n" + + " WRITE THE CLOB DATA THAT WE GET FROM ABOVE INTO THE " + + "FILE '" + fileName + "'"); + + String clobString = clob.getSubString(1, (int)clobLength); + + FileWriter letters = new FileWriter(fileName); + letters.write(clobString, 0, (int)clobLength-1); + letters.close(); + + rs.close(); + stmt.close(); + + System.out.println(); + System.out.println(" WRITE CLOB DATA TYPE INTO FILE SUCCESSFULLY!"); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // clobFileUse + +static void clobSearchStringUse(Connection con) +{ + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO SHOW HOW TO SEARCH A SUBSTRING WITHIN A CLOB OBJECT."); + + // ----------- Read CLOB data from file ------------------- + System.out.println(); + System.out.println( + " ---------------------------------------------------\n" + " READ CLOB DATA TYPE:"); + + System.out.println(); + System.out.println( + " Execute the statement:\n" + + " SELECT resume\n" + + " FROM emp_resume\n" + + " WHERE resume_format = 'ascii' AND empno = '000130'\n" + + "\n" + + " Note: resume is a CLOB data type!"); + + Statement stmt = con.createStatement(); + ResultSet rs = + + stmt.executeQuery( + "SELECT resume " + + " FROM emp_resume " + + " WHERE resume_format = 'ascii' AND empno = '000130'"); + + rs.next(); + + ResultSetMetaData rsMetaData = rs.getMetaData(); + int clobType = rsMetaData.getColumnType(1); + Clob clob = rs.getClob(1); + + System.out.println(); + System.out.println(" READ CLOB DATA TYPE FROM DB SUCCESSFULLY!"); + // ------ Display the ORIGINAL CLOB data onto the screen ------- + + long clobLength = clob.length(); + System.out.println(" The original CLOB is " + clobLength + " bytes long."); + + System.out.println(); + System.out.println( + " ***************************************************\n" + + " ORIGINAL RESUME -- VIEW \n" + + " ***************************************************"); + + String clobString = clob.getSubString(1, (int) clobLength); + System.out.println(clobString); + System.out.println(" -- END OF ORIGINAL RESUME -- "); + + System.out.println(); + System.out.println( + " ***************************************************\n" + + " NEW RESUME -- CREATE \n" + + " ***************************************************"); + + // Determine the starting position of each section of the resume + long resPos = 1; //this is the 'Resume: Delores M. Quintana' part + long prsPos = clob.position("Personal Information", 1); + long depPos = clob.position("Department Information", 1); + long eduPos = clob.position("Education", 1); + long wrkPos = clob.position("Work History", 1); + long intPos = clob.position("Interests", 1); + + // Determine the length of each section of the resume + long resLength = prsPos - 1; + long prsLength = depPos - prsPos; + long depLength = eduPos - depPos; + long eduLength = wrkPos - eduPos; + long wrkLength = intPos - wrkPos; + long intLength = clobLength - intPos + 1; + + System.out.println(); + System.out.println(" Create new resume with Department info at end."); + // Create a separate String for each section of the resume + String resInfo = clob.getSubString(resPos, (int) resLength); + String prsInfo = clob.getSubString(prsPos, (int) prsLength); + String depInfo = clob.getSubString(depPos, (int) depLength); + String eduInfo = clob.getSubString(eduPos, (int) eduLength); + String wrkInfo = clob.getSubString(wrkPos, (int) wrkLength); + String intInfo = clob.getSubString(intPos, (int) intLength); + + rs.close(); + stmt.close(); + + // Concatenate the sections in the desired order + String newClobString = resInfo + prsInfo + eduInfo + wrkInfo + intInfo + "\r\n \r\n " + depInfo; + + // Put the new resume in the database but use a different employee number, 200140, so that the + // original row is not overlaid. + System.out.println(); + System.out.println(" Insert the new resume into the database."); + + PreparedStatement pstmt = con.prepareStatement( + "INSERT INTO emp_resume (empno, resume_format, resume) " + " VALUES (?, ?, ?)"); + + String empno = "200140"; + String resume_format = "ascii"; + Object newObject = newClobString; + pstmt.setString(1, empno); + pstmt.setString(2, resume_format); + pstmt.setObject(3, newObject, clobType); + pstmt.executeUpdate(); + pstmt.close(); + + System.out.println(); + System.out.println( + " ***************************************************\n" + + " NEW RESUME -- VIEW \n" + + " ***************************************************"); + + // ----------- Read the NEW RESUME (CLOB) from DB ------------ + System.out.println(); + System.out.println( + " ---------------------------------------------------\n" + " READ CLOB DATA TYPE:"); + + System.out.println(); + System.out.println( + " Execute the statement:\n" + + " SELECT resume\n" + + " FROM emp_resume\n" + + " WHERE resume_format = 'ascii' AND empno = '200140'"); + + Statement stmt2 = con.createStatement(); + ResultSet rs2 = stmt2.executeQuery( + "SELECT resume " + " FROM emp_resume " + " WHERE empno = '200140'"); + + rs2.next(); + + Clob clob2 = rs2.getClob(1); + System.out.println(); + System.out.println(" READ NEW RESUME (CLOB) FROM DB SUCCESSFULLY!"); + + // ------ Display the NEW RESUME (CLOB) onto the screen ------- + long clobLength2 = clob2.length(); + System.out.println(" The new CLOB is " + clobLength2 + " bytes long."); + + System.out.println(); + System.out.println( + " ---------------------------------------------------\n" + + " HERE IS THE NEW RESUME:"); + + String clobString2 = clob2.getSubString(1, (int) clobLength2); + System.out.println(clobString2); + System.out.println(); + System.out.println(" -- END OF NEW RESUME --"); + + rs2.close(); + stmt2.close(); + // ---------- Delete the NEW RESUME from the database ---- + System.out.println(); + System.out.println( + " ***************************************************\n" + + " NEW RESUME -- DELETE \n" + + " ***************************************************"); + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate("DELETE FROM emp_resume WHERE empno = '200140' "); + stmt3.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } +} // clobSearchStringUse + +} // DtLob Class + diff --git a/java/jdbc/DtUdt.java b/java/jdbc/DtUdt.java new file mode 100644 index 0000000..f11595f --- /dev/null +++ b/java/jdbc/DtUdt.java @@ -0,0 +1,261 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DtUdt.java +// +// SAMPLE: How to create, use and drop user defined distinct types +// +// SQL statements USED: +// CREATE DISTINCT TYPE +// CREATE TABLE +// DROP DISTINCT TYPE +// DROP TABLE +// INSERT +// COMMIT +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: DtUdt.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class DtUdt +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO CREATE, USE AND DROP\n" + + "USER DEFINED DISTINCT TYPES."); + + // connect to the 'sample' database + db.connect(); + + create(db.con); + use(db.con); + drop(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // main + + // This function creates a few user defined distinct types + static void create(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE DISTINCT TYPE\n" + + " COMMIT\n" + + "TO CREATE UDTs."); + + System.out.println(); + System.out.println( + " CREATE DISTINCT TYPE udt1 AS INTEGER WITH COMPARISONS"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE DISTINCT TYPE udt1 AS INTEGER WITH COMPARISONS"); + stmt.close(); + + System.out.println( + " CREATE DISTINCT TYPE udt2 AS CHAR(2) WITH COMPARISONS"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "CREATE DISTINCT TYPE udt2 AS CHAR(2) WITH COMPARISONS"); + stmt1.close(); + + System.out.println( + " CREATE DISTINCT TYPE udt3 AS DECIMAL(7, 2) WITH COMPARISONS"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "CREATE DISTINCT TYPE udt3 AS DECIMAL(7, 2) WITH COMPARISONS "); + stmt2.close(); + + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // create + + // This function uses the user defined distinct types that we created + // at the beginning of this program. + static void use(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " EXECUTE IMMEDIATE\n" + + " COMMIT\n" + + "TO USE UTDs."); + + // Create a table that uses the user defined distinct types + try + { + System.out.println(); + System.out.println( + " CREATE TABLE udt_table(col1 udt1, col2 udt2, col3 udt3)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE udt_table(col1 udt1, col2 udt2, col3 udt3)"); + stmt.close(); + + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // Insert data into the table with the user defined distinct types + try + { + String strStmt; + System.out.println(); + System.out.println( + " INSERT INTO udt_table \n" + + " VALUES(CAST(77 AS udt1),\n" + + " CAST('ab' AS udt2),\n" + + " CAST(111.77 AS udt3))"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO udt_table VALUES(CAST(77 AS udt1), " + + " CAST('ab' AS udt2), " + + " CAST(111.77 AS udt3))"); + stmt1.close(); + + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // Drop the table with the user defined distinct types + try + { + System.out.println(); + System.out.println(" DROP TABLE udt_table"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("DROP TABLE udt_table"); + stmt2.close(); + + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con) ; + jdbcExc.handle(); + } + } // use + + // This function drops all of the user defined distinct types that + // we created at the beginning of this program + static void drop(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DROP\n" + + " COMMIT\n" + + "TO DROP UDTs."); + + try + { + System.out.println(); + System.out.println(" DROP USER DISTINCT TYPE udt1"); + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP DISTINCT TYPE udt1"); + stmt.close(); + + System.out.println(" DROP USER DISTINCT TYPE udt2"); + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("DROP DISTINCT TYPE udt2"); + stmt1.close(); + + System.out.println(" DROP USER DISTINCT TYPE udt3"); + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("DROP DISTINCT TYPE udt3"); + stmt2.close(); + + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con) ; + jdbcExc.handle(); + } + } // drop +} // DtUdt + diff --git a/java/jdbc/GTFqueries.db2 b/java/jdbc/GTFqueries.db2 new file mode 100644 index 0000000..1b64667 --- /dev/null +++ b/java/jdbc/GTFqueries.db2 @@ -0,0 +1,38 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2010 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: GTFqueries.db2 +-- +-- SAMPLE: Query to read the sample.csv file using functions in +-- UDFcsvReader.java +-- +-- To run this script from the CLP, perform the following steps: +-- 1. Change the path of the sample.csv in the query to path it is placed +-- in currently +-- 2. issue the command "db2 -tvf GTFqueries.db2" +---------------------------------------------------------------------------- +CONNECT TO sample; + +select * from +table(csvRead('$DB2PATH/samples/java/jdbc/sample.csv')) as +TX(first varchar(23), last varchar(10), +street varchar(50), city varchar(15), state char(2), +zip char(5), age smallint, salary integer, id bigint, +gpa real, rand_double double); diff --git a/java/jdbc/GeneratePayroll.java b/java/jdbc/GeneratePayroll.java new file mode 100644 index 0000000..e144146 --- /dev/null +++ b/java/jdbc/GeneratePayroll.java @@ -0,0 +1,341 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: GeneratePayroll.java +// +// SAMPLE: Geneate payroll reports by department +// +// SQL Statements USED: +// SELECT +// +// Classes used from Util.java are: +// Db +// SqljException +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + + +import java.sql.* ; +import java.util.* ; + +public class GeneratePayroll +{ + // Empty Constructor for use in other programs + public GeneratePayroll() + { + } + + public static void main(String[] args) + { + Db db = null; + Connection conn = null ; + System.out.println(); + System.out.println( + "THIS SAMPLE GENERATES THE PAYROLL REPORTS BY DEPARTMENT."); + + try + { + // Obtain a Connection to the 'sample' database + db = new Db(args); + db.connect(); + conn = db.con; + } + catch(ClassNotFoundException cle) + { + System.out.println(" Driver class not found, please check the PATH" + + " and CLASSPATH system variables to ensure they are correct"); + } + catch(SQLException sqle) + { + System.out.println(" Could not open connection"); + sqle.printStackTrace(); + } + catch(Exception ne) + { + System.out.println(" Unexpected Error"); + ne.printStackTrace(); + } + // If a connection was obtained successfully run the rest of the Sample + if(conn != null) + { + System.out.println("..............................................."); + System.out.println(" USE THE SQL STATEMENT SELECT TO SELECT"); + System.out.println(" PAYROLL DATA FROM THE EMPLOYEE TABLE"); + try + { + Vector al = new Vector(); + Statement st = conn.createStatement(); + // Call getDepartment to get the Work Departments from the Employee + // Table and to get the users choice + String dept = getDepartment(conn); + + // Select all Employee information for the Employee's in the Selected + // Department + String query = "SELECT EMPNO,FIRSTNME,MIDINIT,LASTNAME" + + ",WORKDEPT,JOB,SALARY,BONUS,COMM FROM EMPLOYEE"; + if(dept!=null) + { + query += " WHERE WORKDEPT LIKE '%" + dept + "%'"; + } + System.out.println(" "+query); + // Use a ResultSet Object to store Payroll objects in a vector for + // later use + ResultSet rs = st.executeQuery(query); + for(int i=0;rs.next();i++) + { + Payroll pr = new Payroll(); + pr.setEmployeeNumber(rs.getString(1)); + pr.setFirstName(rs.getString(2)); + pr.setMiddleInitial(rs.getString(3)); + pr.setLastName(rs.getString(4)); + pr.setWorkDepartment(rs.getString(5)); + pr.setJob(rs.getString(6)); + pr.setSalary(rs.getDouble(7)); + pr.setBonus(rs.getDouble(8)); + pr.setCommission(rs.getDouble(9)); + al.add(pr); + } + Object[] obj = al.toArray(); + Payroll[] pra = new Payroll[obj.length]; + for(int i=0;i +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Class used from Util.java are: +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: GetDBCfgParams.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class GetDBCfgParams +{ + public static void main(String argv[]) + { + + System.out.print("--------------------------------------------------"); + System.out.println("----------------------------------------"); + System.out.print("THIS SAMPLE SHOWS HOW TO SELECT THE DB CONFIGURATION"); + System.out.println(" PARAMETERS FROM SYSIBMADM.DBCFG"); + System.out.print("--------------------------------------------------"); + System.out.println("----------------------------------------"); + System.out.println(); + Connection con = null; + Statement stmt = null; + ResultSet rs = null; + + if (argv.length < 1) + { + System.out.print("Missing input arguments. Enter one or more "); + System.out.println("configuration parameter names."); + } + else + { + try + { + // initialize DB2Driver and establish database connection. + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + // create the SQL statement and execute. + stmt = con.createStatement(); + + String whereClause = "WHERE NAME IN ("; + + for (int i = 0; i < argv.length; i++) + { + whereClause += "'" + argv[i].trim() + "',"; + } + + whereClause = whereClause.substring(0, whereClause.length()-1) + ")"; + + String stmtText = "SELECT NAME, VALUE, DEFERRED_VALUE, DATATYPE, "+ + "DBPARTITIONNUM FROM SYSIBMADM.DBCFG " + + whereClause; + + System.out.println(stmtText); + + rs = stmt.executeQuery(stmtText); + + while (rs.next()) + { + String paramName = rs.getString("NAME").trim(); + String paramValue = rs.getString("VALUE"); + String paramDeferredValue = rs.getString("DEFERRED_VALUE"); + String paramType = rs.getString("DATATYPE").trim(); + String partitionNum = rs.getString("DBPARTITIONNUM"); + + paramValue = (paramValue == null) ? "" : paramValue.trim(); + paramDeferredValue = (paramDeferredValue == null) ? + "" : paramDeferredValue.trim(); + partitionNum = (partitionNum == null) ? "" : partitionNum.trim(); + + System.out.println(); + System.out.println("Parameter Name = " + paramName); + System.out.println("Parameter Value = " + paramValue); + System.out.print("Parameter Deferred Value = "); + System.out.println(paramDeferredValue); + System.out.println("Parameter Data Type = " + paramType); + System.out.println("Database partition number = " + partitionNum); + + // cast parameter value to appropriate type if needed. + if (paramType.equals("INTEGER")) + { + int value = Integer.parseInt(paramValue); + } + else if (paramType.equals("BIGINT")) + { + long value = Long.parseLong(paramValue); + } + else if (paramType.equals("DOUBLE")) + { + double value = Double.parseDouble(paramValue); + } + else if (paramType.startsWith("VARCHAR")) + { + String value = paramValue; + } + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + // close the resultset + rs.close(); + + // close the statement + stmt.close(); + + // close the connection + con.close(); + } + catch (Exception x) + { + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } + } // main +} // GetDBCfgParams diff --git a/java/jdbc/GetDBMCfgParams.java b/java/jdbc/GetDBMCfgParams.java new file mode 100644 index 0000000..d196c4d --- /dev/null +++ b/java/jdbc/GetDBMCfgParams.java @@ -0,0 +1,181 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: GetDBMCfgParams.java +// +// SAMPLE: Use the view SYSIBMADM.DBMCFG to retrieve a database +// manager configuration parameter. +// +// Run this sample using the following steps: +// 1. Create and populate the "sample" database +// with the following command: +// db2sampl +// +// 2. Compile the program with the following command: +// javac GetDBMCfgParams.java Util.java +// +// 3. Run this sample with the following command: +// java GetDBMCfgParams +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Class used from Util.java are: +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: GetDBMCfgParams.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class GetDBMCfgParams +{ + public static void main(String argv[]) + { + + System.out.print("--------------------------------------------------"); + System.out.println("----------------------------------------"); + System.out.print("THIS SAMPLE SHOWS HOW TO CALL THE UDF DBM_GET_CFG "); + System.out.println("AND RETRIEVE DBM CONFIGURATION PARAMETERS."); + System.out.print("--------------------------------------------------"); + System.out.println("----------------------------------------"); + Connection con = null; + Statement stmt = null; + ResultSet rs = null; + + if (argv.length < 1) + { + System.out.print("Missing input arguments. Enter one or"); + System.out.println(" more configuration parameter names."); + } + else + { + try + { + // initialize DB2Driver and establish database connection. + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + // create the SQL statement and execute. + stmt = con.createStatement(); + + String whereClause = "WHERE NAME IN ("; + + for (int i = 0; i < argv.length; i++) + { + whereClause += "'" + argv[i].trim() + "',"; + } + + whereClause = whereClause.substring(0, whereClause.length()-1) + ")"; + + String stmtText = "SELECT NAME, VALUE, DEFERRED_VALUE, DATATYPE " + + "FROM SYSIBMADM.DBMCFG " + + whereClause; + + System.out.println(stmtText); + + rs = stmt.executeQuery(stmtText); + + while (rs.next()) + { + String paramName = rs.getString("NAME").trim(); + String paramValue = rs.getString("VALUE"); + String paramDeferredValue = rs.getString("DEFERRED_VALUE"); + String paramType = rs.getString("DATATYPE").trim(); + + paramValue = (paramValue == null) ? "" : paramValue.trim(); + paramDeferredValue = (paramDeferredValue == null) ? + "" : paramDeferredValue.trim(); + System.out.println(); + System.out.println("Parameter Name = " + paramName); + System.out.println("Parameter Value = " + paramValue); + System.out.print("Parameter Deferred Value = "); + System.out.println(paramDeferredValue); + System.out.println("Parameter Data Type = " + paramType); + + // cast parameter value to appropriate type if needed. + if (paramType.equals("INTEGER")) + { + int value = Integer.parseInt(paramValue); + } + else if (paramType.equals("BIGINT")) + { + long value = Long.parseLong(paramValue); + } + else if (paramType.equals("DOUBLE")) + { + double value = Double.parseDouble(paramValue); + } + else if (paramType.startsWith("VARCHAR")) + { + String value = paramValue; + } + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + // close the resultset + rs.close(); + + // close the statement + stmt.close(); + + // close the connection + con.close(); + } + catch (Exception x) + { + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } + } // main +} // GetDBMCfgParams diff --git a/java/jdbc/GetLogs.java b/java/jdbc/GetLogs.java new file mode 100644 index 0000000..5557a63 --- /dev/null +++ b/java/jdbc/GetLogs.java @@ -0,0 +1,324 @@ +//************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************** +// +// SOURCE FILE NAME: GetLogs.java +// +// SAMPLE: How to get the customer view of diagnostic log file entries +// +// This sample shows: +// 1. How to retrieve messages from the notification log starting +// at a specified point in time. +// 2. How to retrieve messages from the notification log written +// over the last week. +// 3. How to get all critical log messages logged in the last 24 +// hours using the PDLOGMSGS_LAST24HOURS view. +// +// SQL STATEMENTS USED: +// SELECT +// TERMINATE +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.java are: +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: GetLogs.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//************************************************************************** + +import java.lang.*; +import java.sql.*; + +class GetLogs +{ + public static void main(String argv[]) + { + String argvDate = null; + String argvTime = null; + String alias = null; + String userId = null; + String password = null; + String url = null; + Connection con = null; + + try + { + // check and assign command line arguments + switch (argv.length) + { + case 2: + alias = "sample"; + userId = ""; + password = ""; + argvDate = argv[0]; + argvTime = argv[1]; + break; + + case 3: + alias = argv[2]; + userId = ""; + password = ""; + argvDate = argv[0]; + argvTime = argv[1]; + break; + + case 5: + alias = argv[2]; + userId = argv[3]; + password = argv[4]; + argvDate = argv[0]; + argvTime = argv[1]; + break; + + default: + System.out.println( + "USAGE: GetLogs [dbname] [userid password]\n" + + " Timestamp Format: YYYY-MM-DD HOUR:MINUTE:SECOND" + + " Example1: GetLogs 2005-12-22 06.44.44\n" + + " Example2: GetLogs 2005-12-22 06.44.44 \n" + + " Example3: GetLogs 2005-12-22 06.44.44 \n"); + System.exit(0); + } + + url = "jdbc:db2:" + alias; + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection( url ); + + System.out.println(); + System.out.println( + " THIS SAMPLE SHOWS HOW TO RETRIEVE NOTIFICATION LOGS MESSAGES.\n"); + + // Retrieve all the notification messages written after the specified + // timestamp. If NULL is specified as the input timestamp to + // PD_GET_LOG_MSGS UDF, then all the entries will be returned. + getPdLogMesgs(con, argvDate, argvTime); + + // Retrieve all notification messages written in the last week from all + // partitions in chronological order. + getPdLogMesgsWeek(con); + + // Get all critical log messages logged in the last 24 hours, order by + // most recent + getPdLogMesgs24Hours(con); + + // disconnect from 'sample' database + con.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // main + + // Retrieve all the notification messages written after + // the specified timestamp + static void getPdLogMesgs(Connection con, String date, String time) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "--------------------------------------------------------------\n" + + "NOTIFICATION MESSAGES STARTING AT A SPECIFIED POINT IN TIME \n" + + "FROM ALL PARTITIONS\n" + + "--------------------------------------------------------------\n"); + + System.out.println( + "SELECT timestamp,\n" + + " instancename,\n" + + " dbpartitionnum,\n" + + " dbname,\n" + + " processname,\n" + + " appl_id,\n" + + " msgtype,\n" + + " msgseverity,\n" + + " msg \n" + + "FROM TABLE ( PD_GET_LOG_MSGS( TIMESTAMP('2005-12-22', '06.44.44') ) )\n" + + "AS t ORDER BY TIMESTAMP;\n\n" ); + + String query = "SELECT timestamp, instancename, dbpartitionnum, " + + " dbname, processname, appl_id, msgtype, msgseverity, " + + " msg FROM TABLE (PD_GET_LOG_MSGS (TIMESTAMP('" + + date + "' , '" + + time + "' ))) AS t ORDER BY TIMESTAMP"; + + ResultSet rs = stmt.executeQuery(query); + + while (rs.next()) + { + System.out.println("TimeStamp : " + rs.getString(1) + "\n" + + "Instance Name : " + rs.getString(2) + "\n" + + "DBPartition No : " + rs.getInt(3) + "\n" + + "DB Name : " + rs.getString(4) + "\n" + + "ProcessName : " + rs.getString(5) + "\n" + + "Application ID : " + rs.getString(6) + "\n" + + "Message Type : " + rs.getString(7) + "\n" + + "Message Severity : " + rs.getString(7) + "\n" + + "Message : " + rs.getString(8) + "\n") ; + } + + rs.close(); + stmt.close(); + } + + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // getPdLogMesgs + + // Retrieve all the notification messages written over the last week + static void getPdLogMesgsWeek(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "--------------------------------------------------------------\n" + + "NOTIFICATION MESSAGES WRITTEN IN THE LAST WEEK FROM \n" + + "FROM ALL PARTITIONS\n" + + "--------------------------------------------------------------\n"); + + System.out.println( + "SELECT timestamp,\n" + + " instancename,\n" + + " dbpartitionnum,\n" + + " dbname,\n" + + " processname,\n" + + " appl_id,\n" + + " msgtype,\n" + + " msgseverity,\n" + + " msg \n" + + "FROM TABLE ( PD_GET_LOG_MSGS( current_timestamp - 7 days) )\n" + + "AS t ORDER BY TIMESTAMP;\n"); + + String query = "SELECT timestamp, instancename, " + + "dbpartitionnum, dbname, processname, appl_id, " + + "msgtype, msgseverity, msg FROM TABLE ( PD_GET_LOG_MSGS" + + "( current_timestamp - 7 days ) ) AS t ORDER BY TIMESTAMP"; + + ResultSet rs = stmt.executeQuery(query); + + while (rs.next()) + { + System.out.println("TimeStamp : " + rs.getString(1) + "\n" + + "Instance Name : " + rs.getString(2) + "\n" + + "DBPartition No : " + rs.getInt(3) + "\n" + + "DB Name : " + rs.getString(4) + "\n" + + "ProcessName : " + rs.getString(5) + "\n" + + "Application ID : " + rs.getString(6) + "\n" + + "Message Type : " + rs.getString(7) + "\n" + + "Message Severity : " + rs.getString(7) + "\n" + + "Message : " + rs.getString(8) + "\n") ; + } + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // getPdLogMesgsWeek + + // Retrieve all the notification messages written in the last 24 hours + static void getPdLogMesgs24Hours(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "--------------------------------------------------------------\n" + + "NOTIFICATION MESSAGES WRITTEN OVER LAST 24 HOURS FROM\n" + + "FROM ALL PARTITIONS\n" + + "--------------------------------------------------------------\n"); + + System.out.println( + "SELECT timestamp,\n" + + " instancename,\n" + + " dbpartitionnum,\n" + + " dbname,\n" + + " processname,\n" + + " appl_id,\n" + + " msgtype,\n" + + " msgseverity,\n" + + " msg \n" + + "FROM SYSIBMADM.PDLOGMSGS_LAST24HOURS WHERE msgseverity = 'C'\n" + + "ORDER BY TIMESTAMP DESC;\n" ); + + String query = "SELECT timestamp, instancename, dbpartitionnum, " + + "dbname, processname, appl_id, msgtype," + + "msgseverity, msg FROM SYSIBMADM.PDLOGMSGS_LAST24HOURS " + + "WHERE msgseverity = 'C' ORDER BY TIMESTAMP DESC"; + + ResultSet rs = stmt.executeQuery(query); + + while (rs.next()) + { + System.out.println("TimeStamp : " + rs.getString(1) + "\n" + + "Instance Name : " + rs.getString(2) + "\n" + + "DBPartition No : " + rs.getInt(3) + "\n" + + "DB Name : " + rs.getString(4) + "\n" + + "ProcessName : " + rs.getString(5) + "\n" + + "Application ID : " + rs.getString(6) + "\n" + + "Message Type : " + rs.getString(7) + "\n" + + "Message Severity : " + rs.getString(7) + "\n" + + "Message : " + rs.getString(8) + "\n") ; + } + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // getPdLogMesgs24Hours +} // GetLogs diff --git a/java/jdbc/GetMessage.java b/java/jdbc/GetMessage.java new file mode 100644 index 0000000..52e5922 --- /dev/null +++ b/java/jdbc/GetMessage.java @@ -0,0 +1,147 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: GetMessage.java +// +// SAMPLE : How to get error message in the required locale with token +// replacement. The tokens can be programatically obtained by +// invoking Sqlaintp using JNI. +// +// JAVA CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.java are: +// Db +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: GetMessage.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.*; //JDBC classes +import java.lang.*; +import java.util.*; +import java.sql.*; + +class GetMessage +{ + public static void main(String argv[]) + { + Connection con = null; + Statement stmt = null; + ResultSet rs = null; + Db db = null; + + try + { + db = new Db(argv); + + // connect to the 'sample' database + db.connect(); + con = db.con; + + System.out.println + ("How to get error message in the required locale with token\n" + + " replacement. The tokens can be programatically obtained\n" + + " by onvoking Sqlaintp API.\n\n"); + + stmt = con.createStatement(); + + System.out.print("Executing\n"); + System.out.print(" SELECT SYSPROC.SQLERRM ('sql551',\n" ); + System.out.print(" 'USERA;UPDATE;"); + System.out.print("SYSCAT.TABLES',\n"); + System.out.print(" ';',\n"); + System.out.print(" 'en_US',\n"); + System.out.print(" 1)\n"); + System.out.print(" FROM SYSIBM.SYSDUMMY1;\n"); + + // Suppose: + // 'sql551' is sqlcode + // 'USERA', 'UPDATE', 'SYSCAT.TABLES' are tokens + // ';' is the delimiter for tokens. + // 'en_US' is the locale + // If the above information is passed to the scalar function SQLERRM, + // a message is returned in the specified LOCALE. + + // perform a SELECT against the "org" table in the sample database. + rs = stmt.executeQuery("SELECT SYSPROC.SQLERRM ('sql551'," + + "'USERA;" + + "UPDATE;SYSCAT.TABLES'," + + "';','en_us'," + + "1)" + + "FROM SYSIBM.SYSDUMMY1"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + String message = rs.getString(1); + System.out.println("\nThe message is \n" + message); + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + finally + { + try + { + //close the resultset + rs.close(); + + // close the Statement + stmt.close(); + + // roll back any changes to the database made by this sample + con.rollback(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception x) + { + System.out.print("\n Unable to Rollback/Disconnect "); + System.out.println("from 'sample' database"); + } + } + } // main +} // GetMessage diff --git a/java/jdbc/IlInfo.java b/java/jdbc/IlInfo.java new file mode 100644 index 0000000..e7ee51e --- /dev/null +++ b/java/jdbc/IlInfo.java @@ -0,0 +1,171 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: IlInfo.java +// +// SAMPLE: How to get and set information at the installation image level +// +// JAVA 2 CLASSES USED: +// DatabaseMetaData +// +// Classes used from Util.java are: +// Db +// JdbcException +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class IlInfo +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO GET AND SET \n" + + "INFORMATION AT INSTALLATION IMAGE LEVEL."); + + // connect to the 'sample' database + db.connect(); + + serverImageInfoGet(db.con); + clientImageInfoGet(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // main + + // This function gets the information of the Server's image + static void serverImageInfoGet(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE DatabaseMetaData FUNCTIONS:\n" + + " getDatabaseProductName()\n" + + " getDatabaseProductVersion()\n" + + "TO GET SERVER'S IMAGE INFOMATION."); + + DatabaseMetaData dbMetaData = con.getMetaData(); + + String dbProductName = dbMetaData.getDatabaseProductName(); + System.out.println(); + System.out.println(" DATABASE Product Name: " + dbProductName); + + String dbProductVersion = dbMetaData.getDatabaseProductVersion(); + System.out.println(" DATABASE Product Version: " + dbProductVersion); + + System.out.println(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // serverImageInfoGet + + // This function gets the information of the client's image + static void clientImageInfoGet(Connection con) + { + try + { + System.out.println( + "----------------------------------------------------------\n" + + "USE THE DatabaseMetaData FUNCTIONS:\n" + + " getDriverName()\n" + + " getDriverVersion()\n" + + "TO GET CLIENT'S IMAGE INFOMATION, \n" + + " supportsExtendedSQLGrammar()\n" + + " supportsCoreSQLGrammar()\n" + + " supportsMinimumSQLGrammar()\n" + + "TO GET ODBC CONFORMANCE LEVEL."); + + DatabaseMetaData dbMetaData = con.getMetaData(); + + String driverName = dbMetaData.getDriverName(); + System.out.println(); + System.out.println(" CLIENT JDBC Driver Name: " + driverName); + + String driverVersion = dbMetaData.getDriverVersion(); + System.out.println(" CLIENT JDBC Driver Version: " + + driverVersion); + + System.out.print(" ODBC CLI Conformance Level: "); + + boolean isExtended = dbMetaData.supportsExtendedSQLGrammar(); + boolean isCore = dbMetaData.supportsCoreSQLGrammar(); + boolean isMinimum = dbMetaData.supportsMinimumSQLGrammar(); + + if (isExtended == true) + { + System.out.println("Extended Grammer"); + } + else if (isCore == true) + { + System.out.println("CORE GRAMMER"); + } + else if (isMinimum == true) + { + System.out.println("MINIMUM GRAMMER"); + } + else + { + System.out.println(" -- ERROR: UNKNOWN ---"); + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // clientImageInfoGet +} // IlInfo + diff --git a/java/jdbc/ImplicitCasting.java b/java/jdbc/ImplicitCasting.java new file mode 100644 index 0000000..8ef6f8a --- /dev/null +++ b/java/jdbc/ImplicitCasting.java @@ -0,0 +1,968 @@ +//****************************************************************************** +// (c) Copyright IBM Corp. 2008 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose +// of assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the +// above limitations or exclusions may not apply to you. IBM shall not be +// liable for any damages you suffer as a result of using, copying, modifying +// or distributing the Sample, even if IBM has been advised of the possibility +// of such damages. +//****************************************************************************** +// +// SAMPLE FILE NAME: ImplicitCasting.java +// +// PURPOSE: To demonstrate use of implicit casting. +// 01. STRING to NUMERIC assignment +// 02. NUMERIC to STRING assignment +// 03. STRING to NUMERIC comparison +// 04. NUMERIC to STRING comparison +// 05. USE of BETWEEN PREDICATE +// 06. Implicit Casting with UNION +// 07. Assignment of a TIMESTAMP +// 08. Implicit Casting in following scalar functions +// a. CONCAT +// b. REAL +// 09. Untyped null +// 10. Untyped Expression +// +// +// PREREQUISITE: +// +// +// INPUTS: NONE +// +// OUTPUT: Result of all the functionalities +// +// OUTPUT FILE: ImplicitCasting.out (available in online documentation) +// +// SQL STATEMENTS USED: +// CREATE TABLE +// INSERT +// SELECT +// VALUES +// TRUNCATE TABLE +// DROP TABLE +// +// SQL ROUTINES USED: +// NONE +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// ************************************************************************* +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// +// http://www.ibm.com/software/data/db2/ad/ +// +// *************************************************************************/ +// SAMPLE DESCRIPTION +// +// /************************************************************************* +// +// 1. Implicit casting between string and numeric data on assignments. +// 2. Implicit casting between string and numeric data on comparisons. +// 3. USE of BETWEEN PREDICATE +// 4. Implicit casting between string and numeric data for arithmetic +// operations. +// 5 Support for assignment of a timestamp to a date or time. +// 6. Implicit Casting in scalar functions. +// 7. Untyped null +// 8. Untyped Expression +// +/***************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class ImplicitCasting +{ + static Db db; + public static void main(String argv[]) + { + try + { + System.out.println(); + System.out.println("This sample is to demonstrate use of implicit casting"); + + Connection con = null; + ResultSet rs = null; + + // connect to sample database + try + { + db=new Db(argv); + + } + catch (Exception e) + { + System.out.println(" Error loading DB2 Driver...\n"); + System.out.println(e); + System.exit(1); + } + try + { + con=db.connect(); + con.setAutoCommit(false); + } + catch (Exception e) + { + System.out.println("Connection to sample db can't be established."); + System.err.println(e) ; + System.exit(1); + } + + // Create the temp table + CreateTable(con); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* Implicit Casting between string and numeric data on */"); + System.out.println("/* assignments. */"); + System.out.println("/*****************************************************************/"); + + StringAndNumeric(con); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* USE BETWEEN PREDICATE */"); + System.out.println("/*****************************************************************/"); + + UseBetween(con); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* Implicit casting with UNION */"); + System.out.println("/*****************************************************************/"); + + WithUnion(con); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* Implicit casting between string and numeric data for */"); + System.out.println("/* arithmetic operations. */"); + System.out.println("/*****************************************************************/"); + + CastingForArithmetic(con); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* Implicit casting in assignment of a timestamp */"); + System.out.println("/*****************************************************************/"); + + AssignTimestamp(con); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* Implicit Casting in some scalar functions. */"); + System.out.println("/*****************************************************************/"); + + CastingForScalarFunctions(con); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* Null Enhancements with Implicit Casting */"); + System.out.println("/*****************************************************************/"); + + NullEnhancements(con); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* Use of Untyped Expressions */"); + System.out.println("/*****************************************************************/"); + + UntypedExpressions(con); + + // Drop the temp_employee table + DropTable(con); + } + catch (Exception e) + { + System.out.println("Error Msg: "+ e.getMessage()); + } + }// Main + + static void CreateTable(Connection con) + { + try + { + String st="CREATE TABLE temp_employee(" + + " empno INT NOT NULL," + + " firstname CHAR(12) NOT NULL," + + " midinit CHAR(1)," + + " lastname CHAR(15) NOT NULL," + + " workdept VARCHAR(3)," + + " phoneno CHAR(4)," + + " hiredate DATE," + + " job CHAR(8)," + + " edlevel SMALLINT NOT NULL," + + " sex CHAR(1), birthdate DATE," + + " salary DECIMAL(9,2), bonus INT, comm INT)"; + + System.out.println("\n\n CREATE TABLE temp_employee(" + + " empno INT NOT NULL," + + " firstname CHAR(12) NOT NULL," + + " midinit CHAR(1)," + + " lastname CHAR(15) NOT NULL," + + " workdept VARCHAR(3)," + + " phoneno CHAR(4)," + + " hiredate DATE," + + " job CHAR(8)," + + " edlevel SMALLINT NOT NULL," + + " sex CHAR(1), birthdate DATE," + + " salary DECIMAL(9,2), bonus INT, comm INT))\n \n"); + Statement stmt = con.createStatement(); + stmt.executeUpdate(st); + } + catch(Exception e) + { + System.out.print(" Create Table temp_employee Failed....."+e); + } + }//CreateTable + +static void DescribeTable(Connection con,String tablename) +{ + + try + { + String tabname = tablename; + CallableStatement callStmt = null; + + // prepare the CALL statement + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt = con.prepareCall(sql); + + String param = "DESCRIBE TABLE " + tabname; + + // setting the imput parameter + callStmt.setString(1, param); + + System.out.println("\nCALL ADMIN_CMD('" + param + "')"); + callStmt.execute(); + + ResultSet rs = callStmt.getResultSet(); + + // retrieving the resultset + while (rs.next()) + { + + // retrieving column name and displaying it + String colname = rs.getString(1); + System.out.println("\nColname = " + colname); + + // retrieving typeschema and displaying it + String typeschema = rs.getString(2); + System.out.println("Typeschema = " + typeschema); + + // retrieving typename and displaying it + String typename = rs.getString(3); + System.out.println("Typename = " + typename); + + // retrieving length and displaying it + int length = rs.getInt(4); + System.out.println("Length = " + length); + + // retrieving scale and displaying it + int scale = rs.getInt(5); + System.out.println("Scale = " + scale); + + // retrieving nullable and displaying it + String nullable = rs.getString(6); + System.out.println("Nullable = " + nullable); + + } + rs.close(); + callStmt.close(); + + } + catch(Exception e) + { + System.out.print(" Describe Table Failed....."+e); + } + +}// DescribeTable + +// Select data from the Employee table +static void SelectFromEmployee(ResultSet rs) +{ +try + { + + System.out.println("\n\n Empno \t Firstname \t Midint \t Lastname \t " + + "Workdept \t Phoneno \t Hiredate \t Job \t Edlevel \t " + + "Sex \t Birthdate \t Salary \t Bonus \t Comm "); + + System.out.println("\n ------------------------------------------------------- " + + "-------------------------------------------------------------\n"); + while (rs.next()) + { + + String empno = rs.getString(1); + System.out.print(empno); + + String firstname = rs.getString(2); + System.out.print("\t" + firstname); + + String midint = rs.getString(3); + System.out.print("\t" + midint); + + String lastname = rs.getString(4); + System.out.print("\t" + lastname); + + String workdept = rs.getString(5); + System.out.print("\t" + workdept); + + String phoneno = rs.getString(6); + System.out.print("\t" + phoneno); + + Date hiredate = rs.getDate(7); + System.out.print("\t" + hiredate); + + String job = rs.getString(8); + System.out.print("\t" + job); + + int edlevel = rs.getInt(9); + System.out.print("\t" + edlevel); + + String sex = rs.getString(10); + System.out.print("\t" + sex); + + Date birthdate = rs.getDate(11); + System.out.print("\t" + birthdate); + + String salary = rs.getString(12); + System.out.print("\t" + salary); + + String bonus = rs.getString(13); + System.out.print("\t" + bonus); + + String comm = rs.getString(14); + System.out.print("\t" + comm); + + System.out.println("\n "); + + } + rs.close(); + + } + catch(Exception e) + { + System.out.print(" Select from employee Failed....."+e); + } + +}// SelectFromEmployee + +// Select data from temp_Employee table +static void SelectFromTempEmployee(ResultSet rs) +{ +try + { + + System.out.println("\n\n Temp_Empno \t Temp_Firstname \t Temp_Midint \t Temp_Lastname " + + "Temp_Workdept \t Temp_Phoneno \t Temp_Hiredate \t Temp_Job \t " + + "Temp_Edlevel \t Temp_Sex \t Temp_Birthdate \t Temp_Salary \t " + + "Temp_Bonus \t Temp_Comm "); + + System.out.println("\n ------------------------------------------------------- " + + "------------------------------------------------------------\n"); + while (rs.next()) + { + + int temp_empno = rs.getInt(1); + System.out.print(temp_empno); + + String temp_firstname = rs.getString(2); + System.out.print("\t" + temp_firstname); + + String midint = rs.getString(3); + System.out.print("\t" + midint); + + String temp_lastname = rs.getString(4); + System.out.print("\t" + temp_lastname); + + String temp_workdept = rs.getString(5); + System.out.print("\t" + temp_workdept); + + String temp_phoneno = rs.getString(6); + System.out.print("\t" + temp_phoneno); + + Date temp_hiredate = rs.getDate(7); + System.out.print("\t" + temp_hiredate); + + String temp_job = rs.getString(8); + System.out.print("\t" + temp_job); + + int temp_edlevel = rs.getInt(9); + System.out.print("\t" + temp_edlevel); + + String temp_sex = rs.getString(10); + System.out.print("\t" + temp_sex); + + Date temp_birthdate = rs.getDate(11); + System.out.print("\t" + temp_birthdate); + + float temp_salary = rs.getFloat(12); + System.out.print("\t" + temp_salary); + + String temp_bonus = rs.getString(13); + System.out.print("\t" + temp_bonus); + + String temp_comm = rs.getString(14); + System.out.print("\t" + temp_comm); + + System.out.println("\n "); + + } + rs.close(); + + } + catch(Exception e) + { + System.out.print(" Select from temp_employee Failed....."+e); + } + +}// SelectFromTempEmployee + + + +static void StringAndNumeric(Connection con) +{ + try + { + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* STRING TO NUMERIC ASSIGNMENT */"); + System.out.println("/*****************************************************************/"); + + System.out.println("\n DESCRIBE TABLE temp_employee"); + System.out.println("\n------------------------------------\n"); + + DescribeTable(con,"temp_employee"); + + + System.out.println("\n DESCRIBE TABLE employee"); + System.out.println("\n------------------------------------\n"); + + DescribeTable(con,"employee"); + + + System.out.println("\nSELECT * FROM employee "+ + "WHERE empno < '000100' "); + System.out.println("\n------------------------------------\n"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM employee "+ + "WHERE empno < '000100'"); + + SelectFromEmployee(rs); + + + // In employee table empno is of STRING type and in temp_employee table + // empno is of NUMERIC type. + + // Copy data from one table to another table of different datatypes without + // changing the table structure. + + stmt.executeUpdate("INSERT INTO temp_employee SELECT * FROM employee"); + + // Fetch data from temp_employee table + System.out.println("\nSELECT * FROM temp_employee "+ + "WHERE empno < 000100 "); + System.out.println("\n------------------------------------\n"); + + rs = stmt.executeQuery("SELECT * FROM temp_employee "+ + "WHERE empno < 000100"); + + SelectFromTempEmployee(rs); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* NUMERIC TO STRING ASSIGNMENT */"); + System.out.println("/*****************************************************************/"); + + // In temp_table data type of column phoneno is STRING. Update phoneno column + // by passing NUMERIC phone number. + + System.out.println("\n UPDATE temp_employee " + + "SET phoneno = 5678 "+ + "WHERE empno = '000110'"); + System.out.println("\n------------------------------------\n"); + + stmt.executeUpdate("UPDATE temp_employee " + + "SET phoneno = 5678 "+ + "WHERE empno = '000110'"); + + System.out.println("\nSELECT * FROM temp_employee "+ + "WHERE phoneno = 5678 "); + System.out.println("\n------------------------------------\n"); + + rs = stmt.executeQuery("SELECT * FROM temp_employee "+ + "WHERE phoneno = 5678"); + SelectFromTempEmployee(rs); + rs.close(); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* Implicit Casting between string and numeric data on comparison*/"); + System.out.println("/*****************************************************************/"); + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* STRING TO NUMERIC COMPARISON */"); + System.out.println("/*****************************************************************/"); + + + // Retrieve rows from temp_employee table where empno is 000330. + // In temp_employee table empno is of NUMERIC TYPE. + // Pass empno as STRING while fetching the data from table. + + System.out.println("\nSELECT * FROM temp_employee "+ + " WHERE empno = '000330'"); + System.out.println("\n------------------------------------\n"); + + rs = stmt.executeQuery("SELECT * FROM temp_employee "+ + " WHERE empno = '000330'"); + SelectFromTempEmployee(rs); + rs.close(); + + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* NUMERIC TO STRING COMPARISON */"); + System.out.println("/*****************************************************************/"); + + // Retrieve rows from temp_employee table where salary is 37750.00 + // or bonus is 400 or comm is 1272. + // + // In temp_employee table salary, bonus, comm is of NUMERIC TYPE. + // Pass salary, bonus, comm as STRING while fetching the data from table. + + + System.out.println("\nSELECT * FROM temp_employee "+ + " WHERE salary = '37750.00'" + + " OR bonus = '400' OR comm = '1272'"); + System.out.println("\n------------------------------------\n"); + + rs = stmt.executeQuery("SELECT * FROM temp_employee "+ + " WHERE salary = '37750.00'" + + " OR bonus = '400' OR comm = '1272'"); + SelectFromTempEmployee(rs); + rs.close(); + stmt.close(); + + } + catch(Exception e) + { + System.out.print("Implicit Casting between string and numeric data Failed....."+e); + } + }//StringAndNumeric + + +static void UseBetween(Connection con) +{ + +try + { + // BETWEEN predicate compares a value with a range of values. + // Pass STRING value of empno as range1 and NUMERIC value of empno as range2. + + System.out.println("\nSELECT * FROM temp_employee "+ + " WHERE empno" + + " BETWEEN '000120' AND 000160"); + System.out.println("\n------------------------------------\n"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM temp_employee "+ + " WHERE empno" + + " BETWEEN '000120' AND 000160"); + SelectFromTempEmployee(rs); + rs.close(); + stmt.close(); + + +} + catch(Exception e) + { + System.out.print(" UseBetween Failed....."+e); + } + + +}// UseBetween + + +static void WithUnion(Connection con) +{ + +try + { + + // Here columns in the query are of different type. + // firstname is of CHAR type, phoneno is of CHAR type, projname is of VARCHAR + // type and prstaff is of DECIMAL type. + + System.out.println("\nSELECT firstname, phoneno AS col1 "+ + " FROM temp_employee" + + " WHERE workdept = 'D11' " + + " UNION " + + " SELECT projname, prstaff AS col2" + + " FROM proj" + + " WHERE deptno = 'E21'"); + System.out.println("\n------------------------------------\n"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT firstname, phoneno AS col1 "+ + " FROM temp_employee" + + " WHERE workdept = 'D11' " + + " UNION " + + " SELECT projname, prstaff AS col2" + + " FROM proj" + + " WHERE deptno = 'E21'"); + + System.out.println("\n Col1 col2 \n"); + + // retrieving the resultset + while (rs.next()) + { + // retrieving data and displaying it + String col1 = rs.getString(1); + System.out.print(col1); + + String col2 = rs.getString(2); + System.out.print("\t"+col2); + + System.out.println("\n "); + } + + rs.close(); + stmt.close(); + + +} + catch(Exception e) + { + System.out.print(" WithUnion Failed....."+e); + } +}// WithUnion + + +static void CastingForArithmetic(Connection con) +{ +try + { + // STRING and NUMERIC data can be used in arithmetic operation. + // Update salary of empno 000250 by adding bonus + comm + + System.out.println("\nUPDATE temp_employee "+ + " SET SALARY = SALARY + comm + bonus + '1000'" + + " WHERE empno = 000250"); + System.out.println("\n------------------------------------\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("UPDATE temp_employee "+ + " SET SALARY = SALARY + comm + bonus + '1000'" + + " WHERE empno = 000250"); + + + System.out.println("\nSELECT salary AS updated_salary "+ + " FROM temp_employee" + + " WHERE empno = '000250'"); + System.out.println("\n------------------------------------\n"); + ResultSet rs = stmt.executeQuery("SELECT salary AS updated_salary "+ + " FROM temp_employee" + + " WHERE empno = '000250'"); + + System.out.println("\n Updated_salary "); + // retrieving the resultset + while (rs.next()) + { + // retrieving updated_salary and displaying it + int sal= rs.getInt(1); + System.out.println(sal); + + } + rs.close(); + stmt.close(); + +} + catch(Exception e) + { + System.out.print("CastingForArithmetic Failed....."+e); + } + +}// CastingForArithmetic + + +static void AssignTimestamp(Connection con) +{ +try + { + + Statement stmt = con.createStatement(); + + // Create table date_time + System.out.print("CREATE TABLE date_time (new_date DATE, new_time TIME)"); + stmt.executeUpdate("CREATE TABLE date_time (new_date DATE, new_time TIME)"); + + + // Insert values into date_time + stmt.executeUpdate("INSERT INTO date_time " + + " VALUES ('2008-04-11-03.45.30.999', " + + " '2008-04-11-03.45.30.999')"); + + stmt.executeUpdate("INSERT INTO date_time " + + " VALUES ('2008-05-12-03.45.30.123', " + + " '2008-05-12-03.45.30.123')"); + + // Fetch data from data_time table + System.out.println("\nSELECT TO_CHAR(new_date, 'DAY-YYYY-Month-DD'), "+ + " new_time FROM date_time"); + System.out.println("\n------------------------------------\n"); + ResultSet rs = stmt.executeQuery("SELECT TO_CHAR(new_date, 'DAY-YYYY-Month-DD'), "+ + " new_time FROM date_time"); + + System.out.println("\n NewDate NewTime \n"); + System.out.println("\n------------------------------------\n"); + + // retrieving the resultset + while (rs.next()) + { + // retrieving data and displaying + String newdate= rs.getString(1); + System.out.print(newdate); + + Time newtime = rs.getTime(2); + System.out.print("\t" + newtime); + + System.out.println("\n "); + + } + rs.close(); + + // drop table date_time + System.out.print("DROP TABLE date_time"); + stmt.executeUpdate("DROP TABLE date_time"); + + stmt.close(); + + +} + catch(Exception e) + { + System.out.print(" AssignTimestamp Failed....."+e); + } +}// AssignTimestamp + + +static void CastingForScalarFunctions(Connection con) +{ + + + + System.out.println("/*****************************************************************/"); + System.out.println("/* USE of CONCAT scalar function */"); + System.out.println("/*****************************************************************/"); + try + { + + // CONCAT scalar function can take arguments of different data types. + System.out.println("\nSELECT CONCAT (CONCAT (CONCAT "+ + "(CONCAT (empno, ' || ' ), "+ + " firstname),' || '), hiredate) AS employee_information" + + " FROM temp_employee " + + " WHERE empno BETWEEN " + + " 000100 AND '000340' "); + System.out.println("\n------------------------------------\n"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT CONCAT (CONCAT (CONCAT "+ + "(CONCAT (empno, ' || ' ), "+ + " firstname),' || '), hiredate) AS employee_information" + + " FROM temp_employee " + + " WHERE empno BETWEEN " + + " 000100 AND '000340' "); + + System.out.println("\n employee_information"); + System.out.println("\n------------------------------------\n"); + + // retrieving the resultset + while (rs.next()) + { + // retrieving data and displaying + String empinfo= rs.getString(1); + System.out.println(empinfo); + + } + rs.close(); + stmt.close(); + + } + catch(Exception e) + { + System.out.print(" UseConcat Failed....."+e); + } + + + System.out.println("\n\n/*****************************************************************/"); + System.out.println("/* USE of REAL scalar function */"); + System.out.println("/*****************************************************************/"); + try + { + + // Real scalar function can take string and numeric arguments. + System.out.println("\nSELECT REAL (salary) as real_salary "+ + " FROM temp_employee "); + System.out.println("\n------------------------------------\n"); + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT REAL(salary) as real_salary FROM temp_employee "); + + System.out.println("\n real_salary"); + System.out.println("\n------------------------------------\n"); + // retrieving the resultset + while (rs.next()) + { + // retrieving data and displaying + int real_salary= rs.getInt(1); + System.out.println(real_salary); + + } + rs.close(); + + System.out.println("\nSELECT REAL (CAST(salary AS CHAR(9))) "+ + " as real_salary FROM temp_employee "); + System.out.println("\n------------------------------------\n"); + + rs = stmt.executeQuery("SELECT REAL (CAST(salary AS CHAR(9))) "+ + " as real_salary FROM temp_employee "); + System.out.println("\n real_salary"); + System.out.println("\n------------------------------------\n"); + // retrieving the resultset + while (rs.next()) + { + // retrieving data and displaying + int realsalary= rs.getInt(1); + System.out.println(realsalary); + + } + + rs.close(); + stmt.close(); + + } + catch(Exception e) + { + System.out.print(" UseReal Failed....."+e); + } + + +}// CastingForScalarFunctions + +static void NullEnhancements(Connection con) +{ + try + { + + // Null can be used anywhere in the expression. + Statement stmt = con.createStatement(); + stmt.executeUpdate(" UPDATE temp_employee SET comm = NULL WHERE empno = 000330"); + + // Select row where empno is 000330 + System.out.println("\nSELECT * FROM temp_employee WHERE empno = 000330 "); + System.out.println("\n------------------------------------\n"); + ResultSet rs = stmt.executeQuery("SELECT * FROM temp_employee WHERE empno = 000330"); + SelectFromTempEmployee(rs); + rs.close(); + + // If either operand is null, the result will be null. + stmt.executeUpdate(" UPDATE temp_employee SET salary = salary + comm + NULL WHERE empno = 000330 "); + + // Select row where empno is 000330 + rs = stmt.executeQuery("SELECT * FROM temp_employee WHERE empno = 000330 "); + SelectFromTempEmployee(rs); + rs.close(); + stmt.close(); + + } + catch(Exception e) + { + System.out.print(" NullEnhancements Failed....."+e); + } +}// NullEnhancements + +static void UntypedExpressions(Connection con) +{ + try + { + + System.out.println("\n\n*****************************************************"); + System.out.println("\n Use of Untyped Expressions" ); + System.out.println("*****************************************************"); + + /* Pass empno as numeric and string in parameter marker */ + System.out.println("\n SELECT fisrtname, lastname FROM org WHERE empno = ?"); + System.out.println("\n------------------------------------\n"); + + String empno = "000110"; + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT firstname,lastname FROM temp_employee WHERE empno = " + empno); + + System.out.println("\n fisrtname lastname "); + System.out.println("\n------------------------------------\n"); + // retrieving the resultset + while (rs.next()) + { + // retrieving data and displaying + String fname= rs.getString(1); + System.out.print(fname); + + String lname= rs.getString(2); + System.out.print("\t" +lname); + + System.out.println("\n "); + } + + rs.close(); + stmt.close(); + + } + catch(Exception e) + { + System.out.println("Untyped Expression failed....."); + } + } // UntypedExpressions + + +//Drop table temp_employee + +static void DropTable(Connection con) +{ + try + { + String st="DROP TABLE temp_employee"; + Statement stmt = con.createStatement(); + stmt.executeUpdate(st); + System.out.println("\n\nDrop table temp_employee; \n"); + con.commit(); + db.disconnect(); + } + catch(Exception e) + { + System.out.println("Unable to drop table....."); + } + } //DropTable + +}// ImplicitCasting + + diff --git a/java/jdbc/JCCKerberosPlugin.java b/java/jdbc/JCCKerberosPlugin.java new file mode 100644 index 0000000..bbc0971 --- /dev/null +++ b/java/jdbc/JCCKerberosPlugin.java @@ -0,0 +1,253 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: JCCKerberosPlugin.java +// +// This set of sample shows: +// +// 1. How to implement a JCC plugin which does Kerberos authentication +// 2. How to use this sample plugin to get a Connection. +// +// In order to implement a JCC plugin, user needs to extend com.ibm.db2.jcc.DB2JCCPlugin +// and implement the following method: +// public abstract byte[] getTicket (String username, String password, +// byte[] returnedToken) throws org.ietf.jgss.GSSException; +// +// Plugin users also need to implement some JGSS APIs. The following is a list of JGSS APIs +// required for Java Security Plugin interface. +// +// GSSContext.requestMutualAuth(boolean state) +// GSSContext.getMutualAuthState() +// GSSContext.requestCredDeleg(boolean state) +// GSSContext.getCredDelegState() +// GSSContext.initSecContext (byte[] inputBuf, int offset, int len) +// GSSContext.dispose() +// GSSCredential.dispose() +// +// The APIs should follow the Generic Security Service Application Program Interface, +// Version 2 (IETF RFC2743) and Generic Security Service +// API Version 2: Java-Bindings (IETF RFC2853) specifications. +// For Kerberos, the implementations are already available through the default instance +// of the GSSManager class. +// +// This set of sample implements a plugin that does kerberos authentication. +// It uses Kerberos implementation in jgss package +// It corresponds to the c sample plugin IBMkrb5 in sqllib\samples\securtiy\plugins\ +// +// This set of sample contains the following 3 files: +// +// JCCKerberosPluginTest.java +// This file uses sample plugin JCCKerberosPlugin to get a Connection from DB2 server +// +// JCCKerberosPlugin.java +// This file implements the sample JCCKerberosPlugin. +// +// JCCSimpleGSSException.java +// This file is used by JCCKerberosPlugin for Exception handling +// +// How to run this JCCKerberosPlugin sample: +// +// Compile the above 3 files using: javac *.java +// Run JCCKerberosPluginTest using +// java JCCKerberosPluginTest server port dbname userid password serverPrincipalName +// +// Note: To run this sample, server side plugin IBMkrb5 needs to be installed in +// the server plug-in directory on the server. Database manager configuration +// parameters SRVCON_GSS_PLUGIN_LIST and SRVCON_AUTH need to set correctly +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import org.ietf.jgss.*; + +public class JCCKerberosPlugin extends com.ibm.db2.jcc.DB2JCCPlugin implements java.security.PrivilegedExceptionAction +{ + private org.ietf.jgss.GSSManager manager_ = org.ietf.jgss.GSSManager.getInstance(); + private org.ietf.jgss.GSSName serverGSSName_ ; + private byte[] ticket = null; + private byte[] returnedToken_ = null; + + public JCCKerberosPlugin() + {} + + public JCCKerberosPlugin ( String serverPrincipalName) + { + serverPrincipalName_ = serverPrincipalName; + } + + + /** + * Convert text service principal name into the GSS-API internal format for use with the other APIs + * @parm serverPrincipalName String + * @return GSSName server principal name in GSSName format + * @throws GSSException if an error occurs. + */ + public org.ietf.jgss.GSSName processServerPrincipalName(String serverPrincipalName) throws org.ietf.jgss.GSSException + { + org.ietf.jgss.Oid krb5Oid = new org.ietf.jgss.Oid("1.2.840.113554.1.2.2"); + if (serverPrincipalName != null) + return manager_.createName (serverPrincipalName_, + null, + krb5Oid); + + else + throw new JCCSimpleGSSException(0,"plugin bad principal name."); + } + + + /** + * This method will generate the security context information for the username/password pair. + * The security context information will be used to get the connection + * @param username String + * @param password String + * @param returnedByte byte[] the token returned by DB2 server + * @throws SQLException if an error occurs. + * @return byte[] the security context information for this username/password pair + */ + + public byte[] getTicket(String username, String password, byte[] returnedByte) throws java.sql.SQLException + + { + returnedToken_ = returnedByte; + + if (username == null) { + setUseSubjectCredsOnly(false); + try{ + getTicketX(); + } + catch(org.ietf.jgss.GSSException e) + { + throw new java.sql.SQLException(e.getMessage()); + } + } + else { + setUseSubjectCredsOnly (true); + try { + com.ibm.db2.jcc.am.Krb5JAASCallbackHandler handler = + new com.ibm.db2.jcc.am.Krb5JAASCallbackHandler(); + + handler.setUser(username); + handler.setPassword(password); + + javax.security.auth.login.LoginContext loginCtxt = + new javax.security.auth.login.LoginContext("JaasClient", handler); + + loginCtxt.login(); + javax.security.auth.Subject subject = loginCtxt.getSubject(); + + javax.security.auth.Subject.doAsPrivileged(subject, this, null); + } + + catch (javax.security.auth.login.LoginException e) { + throw new java.sql.SQLException("javax.security.auth.login.LoginException happened"); + } + catch (java.security.PrivilegedActionException e) { + throw new java.sql.SQLException("java.security.PrivilegedActionException happened."); + } + + } + return ticket; + } + + /** + * This method will generate the security context information. + * It is called by getTicket(String username, String password, byte[] returnedByte) + * @throws GSSException if an error occurs + */ + public void getTicketX() throws org.ietf.jgss.GSSException + { + if(returnedToken_ == null) { + /* + * Create a GSSName out of the server's name. + */ + serverGSSName_ = processServerPrincipalName(serverPrincipalName_); + + /* + * Create a GSSContext for mutual authentication with the + * server. + */ + org.ietf.jgss.Oid defaultMech = null; + context_ = manager_.createContext(serverGSSName_, + defaultMech, + gssCredential_, + org.ietf.jgss.GSSContext.INDEFINITE_LIFETIME); + + context_.requestMutualAuth(true); // Mutual authentication + + returnedToken_ = new byte[0]; + } + + int tokenLength = 0; + if (returnedToken_ != null) + tokenLength = returnedToken_.length; + + ticket = context_.initSecContext(returnedToken_, 0, tokenLength); + } + + + /** + * It sets the JAVA variable javax.security.auth.useSubjectCredsOnly + * to useSubjectCredsOnly + * If useSubjectCredsOnly is false, JGSS will not acquire credentials + * through JAAS and Kinit will be used to get the initial credentials + * If useSubjectCredsOnly is true, JGSS will acquire credentials + * through JAAS + * @param useSubjectCredsOnly boolean + */ + public void setUseSubjectCredsOnly (boolean useSubjectCredsOnly) + { + final String subjectOnly = useSubjectCredsOnly ? "true" : "false"; + final String property = "javax.security.auth.useSubjectCredsOnly"; + + String temp = (String) java.security.AccessController.doPrivileged ( + new sun.security.action.GetPropertyAction (property)); + + // Property not set. Set it to the specified value. + if(temp == null) + java.security.AccessController.doPrivileged ( + new java.security.PrivilegedAction() { + public Object run() + { + System.setProperty (property, subjectOnly); + return null; + } + } + ); + } + + public Object run () throws org.ietf.jgss.GSSException + { + getTicketX(); + return null; + } + +} diff --git a/java/jdbc/JCCKerberosPluginTest.java b/java/jdbc/JCCKerberosPluginTest.java new file mode 100644 index 0000000..80a9c2d --- /dev/null +++ b/java/jdbc/JCCKerberosPluginTest.java @@ -0,0 +1,120 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: JCCKerberosPluginTest.java +// +// This set of sample shows +// +// 1. How to implement a JCC plugin which does Kerberos authentication +// 2. How to use this sample plugin to get a Connection. +// +// In order to implement a JCC plugin in, user needs to extend com.ibm.db2.jcc.DB2JCCPlugin +// and implement the following method: +// public abstract byte[] getTicket (String username, String password, +// byte[] returnedToken) throws org.ietf.jgss.GSSException; +// +// User also needs to implement some JGSS APIs +// +// This set of sample implements a plugin that does kerberos authentication. +// It uses Kerberos implementation in jgss package +// It corresponds to the c sample plugin IBMkrb5 in sqllib\samples\securtiy\plugins +// +// This set of samples contain the following 3 files: +// +// JCCKerberosPluginTest.java +// This file uses sample plugin JCCKerberosPlugin to get a Connection from DB2 server +// +// JCCKerberosPlugin.java +// This file implements the sample JCCKerberosPlugin. +// +// JCCSimpleGSSException.java +// used by JCCKerberosPlugin for Exception handling +// How to run this JCCKerberosPlugin sample +// +// Compile the above 3 files using javac *.java +// Run JCCKerberosPluginTest using +// java JCCKerberosPluginTest server port dbname userid password serverPrincipalName +// +// Note: To run this sample, server side plugin IBMkrb5 needs to be installed in +// the server plug-in directory on the server. Database manager configuration +// parameters SRVCON_GSSPLUGIN_LIST and SRVCON_AUTH need to set correctly +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +public class JCCKerberosPluginTest +{ + public static void main (String[] args) throws Exception + { + + if(args.length != 6) + throw new Exception("Usage: program_name [server] [port] [dbname] [userid] [password] [serverPrincipalName]"); + String ServerName = args[0]; + int PortNumber = (new Integer(args[1])).intValue(); + String DatabaseName = args[2]; + String userid = args[3]; + String password = args[4]; + String serverPrincipalName = args[5]; + + String url = "jdbc:db2://" + ServerName + ":"+ PortNumber + "/" + DatabaseName ; + + java.util.Properties properties = new java.util.Properties(); + properties.put("user", userid); + properties.put("password", password); + properties.put("pluginName", "IBMkrb5"); + properties.put("securityMechanism", + new String("" + com.ibm.db2.jcc.DB2BaseDataSource.PLUGIN_SECURITY + "")); + properties.put("plugin", new JCCKerberosPlugin( serverPrincipalName) ); + + java.sql.Connection con = null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + catch ( Exception e ) + { + System.out.println("Error: failed to load Db2 jcc driver."); + } + + try + { + con = java.sql.DriverManager.getConnection(url, properties); + System.out.println("Connected through JCC Type 4 driver using JCCKerberosPlugin"); + + } + catch (Exception e) + { + System.out.println("Error occurred when getting a Connection. " + e.getMessage()); + } + + } +} diff --git a/java/jdbc/JCCSimpleGSSContext.java b/java/jdbc/JCCSimpleGSSContext.java new file mode 100644 index 0000000..d70c69e --- /dev/null +++ b/java/jdbc/JCCSimpleGSSContext.java @@ -0,0 +1,1295 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: JCCSimpleGSSContext.java +// +// SAMPLE: This file is used by JCCSimpleGSSPlugin to implement a JCC +// GSS-API plugin sample +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.InputStream; +import java.io.OutputStream; +import org.ietf.jgss.*; + +public class JCCSimpleGSSContext implements org.ietf.jgss.GSSContext +{ + private JCCSimpleGSSCredential source_; + private JCCSimpleGSSName target_; + private int ctxCount_; + private boolean anonymity_; + private boolean dataConfidentiality_; + private boolean credentialDelegation_; + private boolean dataIntegrity_; + private int lifetime_; + private boolean mutualAuth_; + private boolean replayDetection_; + private boolean sequenceChecking_; + + public JCCSimpleGSSContext(JCCSimpleGSSCredential source, JCCSimpleGSSName target, int ctxCount) + { + source_ = source; + target_ = target; + ctxCount_ = ctxCount; + } + + public JCCSimpleGSSCredential getSource() + { + return source_; + } + + public JCCSimpleGSSName getTarget() + { + return target_; + } + + public int getctxCount() + { + return ctxCount_; + } + + public void setSource(JCCSimpleGSSCredential source) + { + source_ = source; + } + + public void setTarget(JCCSimpleGSSName target) + { + target_ = target; + } + + public void setctxCount(int count) + { + ctxCount_ = count; + } + + /** + * + * @return a byte[] containing the token to be sent to the + * peer. null indicates that no token is generated. + * @param byteArray token generated by the peer. This parameter is ignored + * on the first call since no token has been received from the peer. + * @param start the offset within the inputBuf where the token begins. + * @param len the length of the token. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#DEFECTIVE_TOKEN GSSException.DEFECTIVE_TOKEN}, + * {@link GSSException#BAD_MIC GSSException.BAD_MIC}, + * {@link GSSException#NO_CRED GSSException.NO_CRED}, + * {@link GSSException#CREDENTIALS_EXPIRED + * GSSException.CREDENTIALS_EXPIRED}, + * {@link GSSException#BAD_BINDINGS GSSException.BAD_BINDINGS}, + * {@link GSSException#OLD_TOKEN GSSException.OLD_TOKEN}, + * {@link GSSException#DUPLICATE_TOKEN GSSException.DUPLICATE_TOKEN}, + * {@link GSSException#BAD_NAMETYPE GSSException.BAD_NAMETYPE}, + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public byte[] initSecContext(byte[] byteArray, int start, int len) throws GSSException + { + if (this.ctxCount_ ==0) { + if (byteArray == null) { + + int useridlen = source_.getUserid().length(); + int pwdlen = source_.getPassword().length(); + int targetlen = target_.getUserid().length(); + + /* + Format of the token in gssapi_simple.c on server side + + #define TOKEN_MAX_STRLEN 64 + typedef struct _token{ + int useridLen; + char userid[TOKEN_MAX_STRLEN]; + int pwdLen; + char pwd[TOKEN_MAX_STRLEN]; + int targetLen; + char target[TOKEN_MAX_STRLEN]; + OM_uint32 retFlags; + } TOKEN_T; + + So the length of the token is 4 + 64 + 4 + 64 + 4 + 64 + 4 = 208 + */ + int tokenLength = 208; + byte[] tokenb = new byte[tokenLength]; + int offset = 0; + + //4 byte userid length + tokenb[offset++] = (byte) ( (useridlen >>> 24) & 0xff); + tokenb[offset++] = (byte) ( (useridlen >>> 16) & 0xff); + tokenb[offset++] = (byte) ( (useridlen >>> 8) & 0xff); + tokenb[offset++] = (byte) (useridlen & 0xff); + + //userid in byte format + byte[] useridb = source_.getUserid().getBytes(); + for (int i = offset; i < offset + useridb.length; i++) + tokenb[i] = useridb[i - offset]; + offset += useridb.length; + //pad with blank 0x20 if the length of userid is less than 64 + for (int i = offset; i < 68; i++) + tokenb[i] = 0x20; + + offset = 68; + + //4 byte password length + tokenb[offset++] = (byte) ( (pwdlen >>> 24) & 0xff); + tokenb[offset++] = (byte) ( (pwdlen >>> 16) & 0xff); + tokenb[offset++] = (byte) ( (pwdlen >>> 8) & 0xff); + tokenb[offset++] = (byte) (pwdlen & 0xff); + + //password in byte format + byte[] pwdb = source_.getPassword().getBytes(); + for (int i = offset; i < offset + pwdb.length; i++) + tokenb[i] = pwdb[i - offset]; + offset += pwdb.length; + //pad with blank 0x20 if the passwor is less than 64 + for (int i = offset; i < 68 * 2; i++) + tokenb[i] = 0x20; + + offset = 136; + + //4 byte server principal name length + tokenb[offset++] = (byte) ( (targetlen >>> 24) & 0xff); + tokenb[offset++] = (byte) ( (targetlen >>> 16) & 0xff); + tokenb[offset++] = (byte) ( (targetlen >>> 8) & 0xff); + tokenb[offset++] = (byte) (targetlen & 0xff); + + //server principal name in byte format + byte[] targetb = target_.getUserid().getBytes(); + for (int i = offset; i < offset + targetb.length; i++) + tokenb[i] = targetb[i - offset]; + offset += targetb.length; + //pad with blank 0x20 if server principal is less than 64 + for (int i = offset; i < 68 * 3; i++) + tokenb[i] = 0x20; + + offset = 68 * 3; + + //retFlags + tokenb[offset++] = 0; + tokenb[offset++] = 0; + tokenb[offset++] = 0; + tokenb[offset++] = 1; + ctxCount_++; + return tokenb; + } + else { //consistant with gssapi_simple.c, if input_token != GSS_C_NO_BUFFER, throw error + throw new JCCSimpleGSSException(0,"bad input token"); + } + + } + else if (this.ctxCount_ == 1) { + //second invokation + //sanity check + ctxCount_++; + if (len != 208) + throw new JCCSimpleGSSException(0,"bad input token"); + else { + return null; //don't send more token to server + } + + } + else + throw new JCCSimpleGSSException(0,"context count too high"); + } + + /** + * + * @return the number of bytes written to the OutputStream as part of the + * token to be sent to the peer. A value of 0 indicates that no token + * needs to be sent. + * @param inStream an InputStream that contains the token generated by + * the peer. This parameter is ignored on the first call since no token + * has been or will be received from the peer at that point. + * @param outStream an OutputStream where the output token will be + * written. During the final stage of context establishment, there may be + * no bytes written. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#DEFECTIVE_TOKEN GSSException.DEFECTIVE_TOKEN}, + * {@link GSSException#BAD_MIC GSSException.BAD_MIC}, + * {@link GSSException#NO_CRED GSSException.NO_CRED}, + * {@link GSSException#CREDENTIALS_EXPIRED GSSException.CREDENTIALS_EXPIRED}, + * {@link GSSException#BAD_BINDINGS GSSException.BAD_BINDINGS}, + * {@link GSSException#OLD_TOKEN GSSException.OLD_TOKEN}, + * {@link GSSException#DUPLICATE_TOKEN GSSException.DUPLICATE_TOKEN}, + * {@link GSSException#BAD_NAMETYPE GSSException.BAD_NAMETYPE}, + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public int initSecContext(InputStream inputStream, OutputStream outputStream) throws GSSException + { + throw new JCCSimpleGSSException(0,"initSecContext(InputStream inputStream, OutputStream outputStream) is not implemented"); + } + + /* + * @return a byte[] containing the token to be sent to the + * peer. null indicates that no token is generated. + * @param inToken token generated by the peer. + * @param offset the offset within the inToken where the token begins. + * @param len the length of the token. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#DEFECTIVE_TOKEN GSSException.DEFECTIVE_TOKEN}, + * {@link GSSException#BAD_MIC GSSException.BAD_MIC}, + * {@link GSSException#NO_CRED GSSException.NO_CRED}, + * {@link GSSException#CREDENTIALS_EXPIRED + * GSSException.CREDENTIALS_EXPIRED}, + * {@link GSSException#BAD_BINDINGS GSSException.BAD_BINDINGS}, + * {@link GSSException#OLD_TOKEN GSSException.OLD_TOKEN}, + * {@link GSSException#DUPLICATE_TOKEN GSSException.DUPLICATE_TOKEN}, + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + + public byte[] acceptSecContext(byte[] inToken, int offset, int len) throws GSSException + { + throw new JCCSimpleGSSException(0,"acceptSecContext(byte[] inToken, int offset, int len) is not implemented"); + } + + /* + * @param inputStream an InputStream that contains the token generated by + * the peer. + * @param outStream an OutputStream where the output token will be + * written. During the final stage of context establishment, there may be + * no bytes written. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#DEFECTIVE_TOKEN GSSException.DEFECTIVE_TOKEN}, + * {@link GSSException#BAD_MIC GSSException.BAD_MIC}, + * {@link GSSException#NO_CRED GSSException.NO_CRED}, + * {@link GSSException#CREDENTIALS_EXPIRED + * GSSException.CREDENTIALS_EXPIRED}, + * {@link GSSException#BAD_BINDINGS GSSException.BAD_BINDINGS}, + * {@link GSSException#OLD_TOKEN GSSException.OLD_TOKEN}, + * {@link GSSException#DUPLICATE_TOKEN GSSException.DUPLICATE_TOKEN}, + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void acceptSecContext(InputStream inputStream, OutputStream outputStream) throws GSSException + { + throw new JCCSimpleGSSException(0,"acceptSecContext(InputStream inputStream, OutputStream outputStream) is not implemented."); + } + + /** + * Used during context establishment to determine the state of the + * context. + * + * @return true if this is a fully established context on + * the caller's side and no more tokens are needed from the peer. + */ + + public boolean isEstablished() + { + return false; //not used by jcc. always return false + } + + /** + * Releases any system resources and cryptographic information stored in + * the context object and invalidates the context. + * + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void dispose() throws GSSException //gss_delete_sec_context + { + source_ = null; + target_ = null; + ctxCount_ = 0; + + } + + /** + * Used to determine limits on the size of the message + * that can be passed to wrap. Returns the maximum + * message size that, if presented to the wrap method with + * the same confReq and qop parameters, will + * result in an output token containing no more + * than maxTokenSize bytes.

+ * + * This call is intended for use by applications that communicate over + * protocols that impose a maximum message size. It enables the + * application to fragment messages prior to applying protection.

+ * + * GSS-API implementations are recommended but not required to detect + * invalid QOP values when getWrapSizeLimit is called. + * This routine guarantees only a maximum message size, not the + * availability of specific QOP values for message protection.

+ * + * @param qop the level of protection wrap will be asked to provide. + * @param confReq true if wrap will be asked to provide + * privacy, false otherwise. + * @param maxTokenSize the desired maximum size of the token emitted by + * wrap. + * @return the maximum size of the input token for the given output + * token size + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED}, + * {@link GSSException#BAD_QOP GSSException.BAD_QOP}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public int getWrapSizeLimit(int qop, boolean confReq, + int maxTokenSize) throws GSSException + { + throw new JCCSimpleGSSException(0,"getWrapSizeLimit(int qop, boolean confReq,int maxTokenSize) is not implmented."); + } + + /** + * Applies per-message security services over the established security + * context. The method will return a token with the + * application supplied data and a cryptographic MIC over it. + * The data may be encrypted if confidentiality (privacy) was + * requested.

+ * + * The MessageProp object is instantiated by the application and used + * to specify a QOP value which selects cryptographic algorithms, and a + * privacy service to optionally encrypt the message. The underlying + * mechanism that is used in the call may not be able to provide the + * privacy service. It sets the actual privacy service that it does + * provide in this MessageProp object which the caller should then + * query upon return. If the mechanism is not able to provide the + * requested QOP, it throws a GSSException with the BAD_QOP code.

+ * + * Since some application-level protocols may wish to use tokens + * emitted by wrap to provide "secure framing", implementations should + * support the wrapping of zero-length messages.

+ * + * The application will be responsible for sending the token to the + * peer. + * + * @param inBuf application data to be protected. + * @param offset the offset within the inBuf where the data begins. + * @param len the length of the data + * @param msgProp instance of MessageProp that is used by the + * application to set the desired QOP and privacy state. Set the + * desired QOP to 0 to request the default QOP. Upon return from this + * method, this object will contain the the actual privacy state that + * was applied to the message by the underlying mechanism. + * @return a byte[] containing the token to be sent to the peer. + * + * @throws GSSException containing the following major error codes: + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED}, + * {@link GSSException#BAD_QOP GSSException.BAD_QOP}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public byte[] wrap(byte inBuf[], int offset, int len, + MessageProp msgProp) throws GSSException + { + throw new JCCSimpleGSSException(0,"wrap(byte inBuf[], int offset, int len, MessageProp msgProp) is not implmented."); + } + + /** + * Applies per-message security services over the established security + * context using streams. The method will return a + * token with the application supplied data and a cryptographic MIC over it. + * The data may be encrypted if confidentiality + * (privacy) was requested. This method is equivalent to the byte array + * based {@link #wrap(byte[], int, int, MessageProp) wrap} method.

+ * + * The application will be responsible for sending the token to the + * peer. Typically, the application would + * ensure this by calling the {@link java.io.OutputStream#flush() flush} + * method on an OutputStream that encapsulates the + * connection between the two peers.

+ * + * The MessageProp object is instantiated by the application and used + * to specify a QOP value which selects cryptographic algorithms, and a + * privacy service to optionally encrypt the message. The underlying + * mechanism that is used in the call may not be able to provide the + * privacy service. It sets the actual privacy service that it does + * provide in this MessageProp object which the caller should then + * query upon return. If the mechanism is not able to provide the + * requested QOP, it throws a GSSException with the BAD_QOP code.

+ * + * Since some application-level protocols may wish to use tokens + * emitted by wrap to provide "secure framing", implementations should + * support the wrapping of zero-length messages.

+ * + * @param inStream an InputStream containing the application data to be + * protected. All of the data that is available in + * inStream is used. + * @param outStream an OutputStream to write the protected message + * to. + * @param msgProp instance of MessageProp that is used by the + * application to set the desired QOP and privacy state. Set the + * desired QOP to 0 to request the default QOP. Upon return from this + * method, this object will contain the the actual privacy state that + * was applied to the message by the underlying mechanism. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED}, + * {@link GSSException#BAD_QOP GSSException.BAD_QOP}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void wrap(InputStream inStream, OutputStream outStream, + MessageProp msgProp) throws GSSException + { + throw new JCCSimpleGSSException(0,"wrap(InputStream inStream, OutputStream outStream, MessageProp msgProp) is not implmented."); + } + + /** + * Used to process tokens generated by the wrap method on + * the other side of the context. The method will return the message + * supplied by the peer application to its wrap call, while at the same + * time verifying the embedded MIC for that message.

+ * + * The MessageProp object is instantiated by the application and is + * used by the underlying mechanism to return information to the caller + * such as the QOP, whether confidentiality was applied to the message, + * and other supplementary message state information.

+ * + * Since some application-level protocols may wish to use tokens + * emitted by wrap to provide "secure framing", implementations should + * support the wrapping and unwrapping of zero-length messages.

+ * + * @param inBuf a byte array containing the wrap token received from + * peer. + * @param offset the offset where the token begins. + * @param len the length of the token + * @param msgProp upon return from the method, this object will contain + * the applied QOP, the privacy state of the message, and supplementary + * information stating if the token was a duplicate, old, out of + * sequence or arriving after a gap. + * @return a byte[] containing the message unwrapped from the input + * token. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#DEFECTIVE_TOKEN GSSException.DEFECTIVE_TOKEN}, + * {@link GSSException#BAD_MIC GSSException.BAD_MIC}, + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public byte [] unwrap(byte[] inBuf, int offset, int len, + MessageProp msgProp) throws GSSException + { + throw new JCCSimpleGSSException(0,"unwrap(byte[] inBuf, int offset, int len, MessageProp msgProp) is not implmented."); + } + + /** + * Uses streams to process tokens generated by the wrap + * method on the other side of the context. The method will return the + * message supplied by the peer application to its wrap call, while at + * the same time verifying the embedded MIC for that message.

+ * + * The MessageProp object is instantiated by the application and is + * used by the underlying mechanism to return information to the caller + * such as the QOP, whether confidentiality was applied to the message, + * and other supplementary message state information.

+ * + * Since some application-level protocols may wish to use tokens + * emitted by wrap to provide "secure framing", implementations should + * support the wrapping and unwrapping of zero-length messages.

+ * + * The format of the input token that this method + * reads is defined in the specification for the underlying mechanism that + * will be used. This method will attempt to read one of these tokens per + * invocation. If the mechanism token contains a definitive start and + * end this method may block on the InputStream if only + * part of the token is available. If the start and end of the token + * are not definitive then the method will attempt to treat all + * available bytes as part of the token.

+ * + * Other than the possible blocking behaviour described above, this + * method is equivalent to the byte array based {@link #unwrap(byte[], + * int, int, MessageProp) unwrap} method.

+ * + * @param inStream an InputStream that contains the wrap token generated + * by the peer. + * @param outStream an OutputStream to write the application message + * to. + * @param msgProp upon return from the method, this object will contain + * the applied QOP, the privacy state of the message, and supplementary + * information stating if the token was a duplicate, old, out of + * sequence or arriving after a gap. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#DEFECTIVE_TOKEN GSSException.DEFECTIVE_TOKEN}, + * {@link GSSException#BAD_MIC GSSException.BAD_MIC}, + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void unwrap(InputStream inStream, OutputStream outStream, + MessageProp msgProp) throws GSSException + { + throw new JCCSimpleGSSException(0,"public void unwrap(InputStream inStream, OutputStream outStream, MessageProp msgProp) is not implmented."); + } + + /** + * Returns a token containing a cryptographic Message Integrity Code + * (MIC) for the supplied message, for transfer to the peer + * application. Unlike wrap, which encapsulates the user message in the + * returned token, only the message MIC is returned in the output + * token.

+ * + * Note that privacy can only be applied through the wrap call.

+ * + * Since some application-level protocols may wish to use tokens emitted + * by getMIC to provide "secure framing", implementations should support + * derivation of MICs from zero-length messages. + * + * @param inMsg the message to generate the MIC over. + * @param offset offset within the inMsg where the message begins. + * @param len the length of the message + * @param msgProp an instance of MessageProp that is used + * by the application to set the desired QOP. Set the desired QOP to + * 0 in msgProp to request the default + * QOP. Alternatively pass in null for msgProp + * to request the default QOP. + * @return a byte[] containing the token to be sent to the peer. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED}, + * {@link GSSException#BAD_QOP GSSException.BAD_QOP}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public byte[] getMIC(byte []inMsg, int offset, int len, + MessageProp msgProp) throws GSSException + { + throw new JCCSimpleGSSException(0,"getMIC(byte []inMsg, int offset, int len, MessageProp msgProp) is not implmented."); + } + + /** + * Uses streams to produce a token containing a cryptographic MIC for + * the supplied message, for transfer to the peer application. + * Unlike wrap, which encapsulates the user message in the returned + * token, only the message MIC is produced in the output token. This + * method is equivalent to the byte array based {@link #getMIC(byte[], + * int, int, MessageProp) getMIC} method. + * + * Note that privacy can only be applied through the wrap call.

+ * + * Since some application-level protocols may wish to use tokens emitted + * by getMIC to provide "secure framing", implementations should support + * derivation of MICs from zero-length messages. + * + * @param inStream an InputStream containing the message to generate the + * MIC over. All of the data that is available in + * inStream is used. + * @param outStream an OutputStream to write the output token to. + * @param msgProp an instance of MessageProp that is used + * by the application to set the desired QOP. Set the desired QOP to + * 0 in msgProp to request the default + * QOP. Alternatively pass in null for msgProp + * to request the default QOP. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED}, + * {@link GSSException#BAD_QOP GSSException.BAD_QOP}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void getMIC(InputStream inStream, OutputStream outStream, + MessageProp msgProp) throws GSSException + { + throw new JCCSimpleGSSException(0,"getMIC(InputStream inStream, OutputStream outStream, MessageProp msgProp) is not implmented."); + } + + /** + * Verifies the cryptographic MIC, contained in the token parameter, + * over the supplied message.

+ * + * The MessageProp object is instantiated by the application and is used + * by the underlying mechanism to return information to the caller such + * as the QOP indicating the strength of protection that was applied to + * the message and other supplementary message state information.

+ * + * Since some application-level protocols may wish to use tokens emitted + * by getMIC to provide "secure framing", implementations should support + * the calculation and verification of MICs over zero-length messages. + * + * @param inToken the token generated by peer's getMIC method. + * @param tokOffset the offset within the inToken where the token + * begins. + * @param tokLen the length of the token. + * @param inMsg the application message to verify the cryptographic MIC + * over. + * @param msgOffset the offset in inMsg where the message begins. + * @param msgLen the length of the message. + * @param msgProp upon return from the method, this object will contain + * the applied QOP and supplementary information stating if the token + * was a duplicate, old, out of sequence or arriving after a gap. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#DEFECTIVE_TOKEN GSSException.DEFECTIVE_TOKEN} + * {@link GSSException#BAD_MIC GSSException.BAD_MIC} + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED} + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void verifyMIC(byte[] inToken, int tokOffset, int tokLen, + byte[] inMsg, int msgOffset, int msgLen, + MessageProp msgProp) throws GSSException + { + throw new JCCSimpleGSSException(0,"verifyMIC(byte[] inToken, int tokOffset, int tokLen, byte[] inMsg, int msgOffset, int msgLen, MessageProp msgProp) is not implmented."); + } + + /** + * Uses streams to verify the cryptographic MIC, contained in the token + * parameter, over the supplied message. This method is equivalent to + * the byte array based {@link #verifyMIC(byte[], int, int, byte[], int, + * int, MessageProp) verifyMIC} method. + * + * The MessageProp object is instantiated by the application and is used + * by the underlying mechanism to return information to the caller such + * as the QOP indicating the strength of protection that was applied to + * the message and other supplementary message state information.

+ * + * Since some application-level protocols may wish to use tokens emitted + * by getMIC to provide "secure framing", implementations should support + * the calculation and verification of MICs over zero-length messages.

+ * + * The format of the input token that this method + * reads is defined in the specification for the underlying mechanism that + * will be used. This method will attempt to read one of these tokens per + * invocation. If the mechanism token contains a definitive start and + * end this method may block on the InputStream if only + * part of the token is available. If the start and end of the token + * are not definitive then the method will attempt to treat all + * available bytes as part of the token.

+ * + * Other than the possible blocking behaviour described above, this + * method is equivalent to the byte array based {@link #verifyMIC(byte[], + * int, int, byte[], int, int, MessageProp) verifyMIC} method.

+ * + * @param tokStream an InputStream containing the token generated by the + * peer's getMIC method. + * @param msgStream an InputStream containing the application message to + * verify the cryptographic MIC over. All of the data + * that is available in msgStream is used. + * @param msgProp upon return from the method, this object will contain + * the applied QOP and supplementary information stating if the token + * was a duplicate, old, out of sequence or arriving after a gap. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#DEFECTIVE_TOKEN GSSException.DEFECTIVE_TOKEN} + * {@link GSSException#BAD_MIC GSSException.BAD_MIC} + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED} + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void verifyMIC(InputStream tokStream, InputStream msgStream, + MessageProp msgProp) throws GSSException + { + throw new JCCSimpleGSSException(0,"verifyMIC(InputStream tokStream, InputStream msgStream, MessageProp msgProp) is not implmented."); + } + + /** + * Exports this context so that another process may + * import it.. Provided to support the sharing of work between + * multiple processes. This routine will typically be used by the + * context-acceptor, in an application where a single process receives + * incoming connection requests and accepts security contexts over + * them, then passes the established context to one or more other + * processes for message exchange.

+ * + * This method deactivates the security context and creates an + * interprocess token which, when passed to {@link + * GSSManager#createContext(byte[]) GSSManager.createContext} in + * another process, will re-activate the context in the second process. + * Only a single instantiation of a given context may be active at any + * one time; a subsequent attempt by a context exporter to access the + * exported security context will fail.

+ * + * The implementation may constrain the set of processes by which the + * interprocess token may be imported, either as a function of local + * security policy, or as a result of implementation decisions. For + * example, some implementations may constrain contexts to be passed + * only between processes that run under the same account, or which are + * part of the same process group.

+ * + * The interprocess token may contain security-sensitive information + * (for example cryptographic keys). While mechanisms are encouraged + * to either avoid placing such sensitive information within + * interprocess tokens, or to encrypt the token before returning it to + * the application, in a typical GSS-API implementation this may not be + * possible. Thus the application must take care to protect the + * interprocess token, and ensure that any process to which the token + * is transferred is trustworthy.

+ * + * Implementations are not required to support the inter-process + * transfer of security contexts. Calling the {@link #isTransferable() + * isTransferable} method will indicate if the context object is + * transferable.

+ * + * Calling this method on a context that + * is not exportable will result in this exception being thrown with + * the error code {@link GSSException#UNAVAILABLE + * GSSException.UNAVAILABLE}. + * + * @return a byte[] containing the exported context + * @see GSSManager#createContext(byte[]) + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#UNAVAILABLE GSSException.UNAVAILABLE}, + * {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED}, + * {@link GSSException#NO_CONTEXT GSSException.NO_CONTEXT}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public byte [] export() throws GSSException + { + throw new JCCSimpleGSSException(0,"export() is not implmented."); + } + + /** + * Requests that mutual authentication be done during + * context establishment. This request can only be made on the context + * initiator's side and it has to be done prior to the first call to + * initSecContext.

+ * + * Not all mechanisms support mutual authentication and some mechanisms + * might require mutual authentication even if the application + * doesn't. Therefore, the application should check to see if the + * request was honored with the {@link #getMutualAuthState() + * getMutualAuthState} method.

+ * + * @param state a boolean value indicating whether mutual + * authentication shouls be used or not. + * @see #getMutualAuthState() + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void requestMutualAuth(boolean state) throws GSSException + { + mutualAuth_ = state; + } + + /** + * Requests that replay detection be enabled for the + * per-message security services after context establishemnt. This + * request can only be made on the context initiator's side and it has + * to be done prior to the first call to + * initSecContext. During context establishment replay + * detection is not an option and is a function of the underlying + * mechanism's capabilities.

+ * + * Not all mechanisms support replay detection and some mechanisms + * might require replay detection even if the application + * doesn't. Therefore, the application should check to see if the + * request was honored with the {@link #getReplayDetState() + * getReplayDetState} method. If replay detection is enabled then the + * {@link MessageProp#isDuplicateToken() MessageProp.isDuplicateToken} and {@link + * MessageProp#isOldToken() MessageProp.isOldToken} methods will return + * valid results for the MessageProp object that is passed + * in to the unwrap method or the verifyMIC + * method.

+ * + * @param state a boolean value indicating whether replay detection + * should be enabled over the established context or not. + * @see #getReplayDetState() + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void requestReplayDet(boolean state) throws GSSException + { + replayDetection_ = state; + } + + /** + * Requests that sequence checking be enabled for the + * per-message security services after context establishemnt. This + * request can only be made on the context initiator's side and it has + * to be done prior to the first call to + * initSecContext. During context establishment sequence + * checking is not an option and is a function of the underlying + * mechanism's capabilities.

+ * + * Not all mechanisms support sequence checking and some mechanisms + * might require sequence checking even if the application + * doesn't. Therefore, the application should check to see if the + * request was honored with the {@link #getSequenceDetState() + * getSequenceDetState} method. If sequence checking is enabled then the + * {@link MessageProp#isDuplicateToken() MessageProp.isDuplicateToken}, + * {@link MessageProp#isOldToken() MessageProp.isOldToken}, + * {@link MessageProp#isUnseqToken() MessageProp.isUnseqToken}, and + * {@link MessageProp#isGapToken() MessageProp.isGapToken} methods will return + * valid results for the MessageProp object that is passed + * in to the unwrap method or the verifyMIC + * method.

+ * + * @param state a boolean value indicating whether sequence checking + * should be enabled over the established context or not. + * @see #getSequenceDetState() + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void requestSequenceDet(boolean state) throws GSSException + { + sequenceChecking_ = state; + } + + /** + * Requests that the initiator's credentials be + * delegated to the acceptor during context establishment. This + * request can only be made on the context initiator's side and it has + * to be done prior to the first call to + * initSecContext. + * + * Not all mechanisms support credential delegation. Therefore, an + * application that desires delegation should check to see if the + * request was honored with the {@link #getCredDelegState() + * getCredDelegState} method. If the application indicates that + * delegation must not be used, then the mechanism will honor the + * request and delegation will not occur. This is an exception + * to the general rule that a mechanism may enable a service even if it + * is not requested.

+ * + * @param state a boolean value indicating whether the credentials + * should be delegated or not. + * @see #getCredDelegState() + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void requestCredDeleg(boolean state) throws GSSException + { + credentialDelegation_ = state; + } + + /** + * Requests that the initiator's identity not be + * disclosed to the acceptor. This request can only be made on the + * context initiator's side and it has to be done prior to the first + * call to initSecContext. + * + * Not all mechanisms support anonymity for the initiator. Therefore, the + * application should check to see if the request was honored with the + * {@link #getAnonymityState() getAnonymityState} method.

+ * + * @param state a boolean value indicating if the initiator should + * be authenticated to the acceptor as an anonymous principal. + * @see #getAnonymityState + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void requestAnonymity(boolean state) throws GSSException + { + anonymity_ = state; + } + + /** + * Requests that data confidentiality be enabled + * for the wrap method. This request can only be made on + * the context initiator's side and it has to be done prior to the + * first call to initSecContext. + * + * Not all mechanisms support confidentiality and other mechanisms + * might enable it even if the application doesn't request + * it. The application may check to see if the request was honored with + * the {@link #getConfState() getConfState} method. If confidentiality + * is enabled, only then will the mechanism honor a request for privacy + * in the {@link MessageProp#MessageProp(int, boolean) MessageProp} + * object that is passed in to the wrap method.

+ * + * Enabling confidentiality will also automatically enable + * integrity.

+ * + * @param state a boolean value indicating whether confidentiality + * should be enabled or not. + * @see #getConfState() + * @see #getIntegState() + * @see #requestInteg(boolean) + * @see MessageProp + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void requestConf(boolean state) throws GSSException + { + dataConfidentiality_ = state; + } + + /** + * Requests that data confidentiality be enabled + * for the wrap method. This request can only be made on + * the context initiator's side and it has to be done prior to the + * first call to initSecContext. + * + * Not all mechanisms support confidentiality and other mechanisms + * might enable it even if the application doesn't request + * it. The application may check to see if the request was honored with + * the {@link #getConfState() getConfState} method. If confidentiality + * is enabled, only then will the mechanism honor a request for privacy + * in the {@link MessageProp#MessageProp(int, boolean) MessageProp} + * object that is passed in to the wrap method.

+ * + * Enabling confidentiality will also automatically enable + * integrity.

+ * + * @param state a boolean value indicating whether confidentiality + * should be enabled or not. + * @see #getConfState() + * @see #getIntegState() + * @see #requestInteg(boolean) + * @see MessageProp + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void requestInteg(boolean state) throws GSSException + { + dataIntegrity_ = state; + } + + /** + * Requests a lifetime in seconds for the + * context. This method can only be called on the context initiator's + * side and it has to be done prior to the first call to + * initSecContext.

+ * + * The actual lifetime of the context will depend on the capabilites of + * the underlying mechanism and the application should call the {@link + * #getLifetime() getLifetime} method to determine this.

+ * + * @param lifetime the desired context lifetime in seconds. Use + * INDEFINITE_LIFETIME to request an indefinite lifetime + * and DEFAULT_LIFETIME to request a default lifetime. + * @see #getLifetime() + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void requestLifetime(int lifetime) throws GSSException + { + lifetime_ = lifetime; + } + + /** + * Sets the channel bindings to be used during context + * establishment. This method can be called on both + * the context initiator's and the context acceptor's side, but it must + * be called before context establishment begins. This means that an + * initiator must call it before the first call to + * initSecContext and the acceptor must call it before the + * first call to acceptSecContext. + * + * @param cb the channel bindings to use. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void setChannelBinding(ChannelBinding channelBinding) throws GSSException + { + throw new JCCSimpleGSSException(0,"setChannelBinding(ChannelBinding channelBinding) is not implmented."); + } + + /** + * Determines if credential delegation is enabled on + * this context. It can be called by both the context initiator and the + * context acceptor. For a definitive answer this method must be + * called only after context establishment is complete. Note that if an + * initiator requests that delegation not be allowed the {@link + * #requestCredDeleg(boolean) requestCredDeleg} method will honor that + * request and this method will return false on the + * initiator's side from that point onwards.

+ * + * @return true if delegation is enabled, false otherwise. + * @see #requestCredDeleg(boolean) + */ + public boolean getCredDelegState() + { + return credentialDelegation_; + } + + /** + * Determines if mutual authentication is enabled on + * this context. It can be called by both the context initiator and the + * context acceptor. For a definitive answer this method must be + * called only after context establishment is complete. An initiator + * that requests mutual authentication can call this method after + * context completion and dispose the context if its request was not + * honored.

+ * + * @return true if mutual authentication is enabled, false otherwise. + * @see #requestMutualAuth(boolean) + */ + public boolean getMutualAuthState() + { + return mutualAuth_; + } + + /** + * Determines if replay detection is enabled for the + * per-message security services from this context. It can be called by + * both the context initiator and the context acceptor. For a + * definitive answer this method must be called only after context + * establishment is complete. An initiator that requests replay + * detection can call this method after context completion and + * dispose the context if its request was not honored.

+ * + * @return true if replay detection is enabled, false otherwise. + * @see #requestReplayDet(boolean) + */ + public boolean getReplayDetState() + { + return replayDetection_; + } + + /** + * Determines if sequence checking is enabled for the + * per-message security services from this context. It can be called by + * both the context initiator and the context acceptor. For a + * definitive answer this method must be called only after context + * establishment is complete. An initiator that requests sequence + * checking can call this method after context completion and + * dispose the context if its request was not honored.

+ * + * @return true if sequence checking is enabled, false otherwise. + * @see #requestSequenceDet(boolean) + */ + public boolean getSequenceDetState() + { + return sequenceChecking_; + } + + /** + * Determines if the context initiator is + * anonymously authenticated to the context acceptor. It can be called by + * both the context initiator and the context acceptor, and at any + * time. On the initiator side, a call to this method determines + * if the identity of the initiator has been disclosed in any of the + * context establishment tokens that might have been generated thus far + * by initSecContext. An initiator that absolutely must be + * authenticated anonymously should call this method after each call to + * initSecContext to determine if the generated token + * should be sent to the peer or the context aborted. On the + * acceptor side, a call to this method determines if any of the tokens + * processed by acceptSecContext thus far have divulged + * the identity of the initiator.

+ * + * @return true if the context initiator is still anonymous, false + * otherwise. + * @see #requestAnonymity(boolean) + */ + public boolean getAnonymityState() + { + return anonymity_; + } + + /** + * Determines if the context is transferable to other processes + * through the use of the {@link #export() export} method. This call + * is only valid on fully established contexts. + * + * @return true if this context can be exported, false otherwise. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public boolean isTransferable() throws GSSException + { + throw new JCCSimpleGSSException(0,"isTransferable() is not implmented."); + } + + /** + * Determines if the context is ready for per message operations to be + * used over it. Some mechanisms may allow the usage of the + * per-message operations before the context is fully established. + * + * @return true if methods like wrap, unwrap, + * getMIC, and verifyMIC can be used with + * this context at the current stage of context establishment, false + * otherwise. + */ + public boolean isProtReady() + { + return false; + } + + /** + * Determines if data confidentiality is available + * over the context. This method can be called by both the context + * initiator and the context acceptor, but only after one of {@link + * #isProtReady() isProtReady} or {@link #isEstablished() + * isEstablished} return true. If this method returns + * true, so will {@link #getIntegState() + * getIntegState}

+ * + * @return true if confidentiality services are available, false + * otherwise. + * @see #requestConf(boolean) + */ + public boolean getConfState() + { + return dataConfidentiality_; + } + + /** + * Determines if data integrity is available + * over the context. This method can be called by both the context + * initiator and the context acceptor, but only after one of {@link + * #isProtReady() isProtReady} or {@link #isEstablished() + * isEstablished} return true. This method will always + * return true if {@link #getConfState() getConfState} + * returns true.

+ * + * @return true if integrity services are available, false otherwise. + * @see #requestInteg(boolean) + */ + public boolean getIntegState() + { + return dataIntegrity_; + } + + /** + * Determines what the remaining lifetime for this + * context is. It can be called by both the context initiator and the + * context acceptor, but for a definitive answer it should be called + * only after {@link #isEstablished() isEstablished} returns + * true.

+ * + * @return the remaining lifetime in seconds + * @see #requestLifetime(int) + */ + public int getLifetime() + { + return lifetime_; + } + + /** + * Returns the name of the context initiator. This call is valid only + * after one of {@link #isProtReady() isProtReady} or {@link + * #isEstablished() isEstablished} return true. + * + * @return a GSSName that is an MN containing the name of the context + * initiator. + * @see GSSName + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public GSSName getSrcName() throws GSSException + { + return new JCCSimpleGSSName(source_.getUserid()); + } + + /** + * Returns the name of the context acceptor. This call is valid only + * after one of {@link #isProtReady() isProtReady} or {@link + * #isEstablished() isEstablished} return true. + * + * @return a GSSName that is an MN containing the name of the context + * acceptor. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public GSSName getTargName() throws GSSException + { + return target_; + } + + /** + * Determines what mechanism is being used for this + * context. This method may be called before the context is fully + * established, but the mechanism returned may change on successive + * calls in the negotiated mechanism case. + * + * @return the Oid of the mechanism being used + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public Oid getMech() throws GSSException + { + throw new JCCSimpleGSSException(0,"getMech() is not implmented."); + } + + /** + * Obtains the credentials delegated by the context + * initiator to the context acceptor. It should be called only on the + * context acceptor's side, and once the context is fully + * established. The caller can use the method {@link + * #getCredDelegState() getCredDelegState} to determine if there are + * any delegated credentials. + * + * @return a GSSCredential containing the initiator's delegated + * credentials, or null is no credentials + * were delegated. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public GSSCredential getDelegCred() throws GSSException + { + throw new JCCSimpleGSSException(0,"getDelegCred() is not implmented."); + } + + /** + * Determines if this is the context initiator. This + * can be called on both the context initiator's and context acceptor's + * side. + * + * @return true if this is the context initiator, false if it is the + * context acceptor. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public boolean isInitiator() throws GSSException + { + throw new JCCSimpleGSSException(0,"isInitiator() is not implmented."); + } + +} diff --git a/java/jdbc/JCCSimpleGSSCredential.java b/java/jdbc/JCCSimpleGSSCredential.java new file mode 100644 index 0000000..ae04d99 --- /dev/null +++ b/java/jdbc/JCCSimpleGSSCredential.java @@ -0,0 +1,346 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: JCCSimpleCredential.java +// +// SAMPLE: This file is used by JCCSimpleGSSPlugin to implement a JCC +// GSS-API plugin sample +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.InputStream; +import java.io.OutputStream; +import org.ietf.jgss.*; + +public class JCCSimpleGSSCredential implements org.ietf.jgss.GSSCredential +{ + private String userid_; + private String password_; + + public JCCSimpleGSSCredential(String uid, String pwd) + { + userid_ = uid; + password_ = pwd; + } + + public String getUserid() + { + return userid_; + } + public String getPassword() + { + return password_; + } + + + /** + * Releases any sensitive information that the GSSCredential object may + * be containing. Applications should call this method as soon as the + * credential is no longer needed to minimize the time any sensitive + * information is maintained. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void dispose() throws GSSException //this is equivalent to gss_release_cred + { + userid_ = null; + password_ = null; + } + + /** + * Retrieves the name of the entity that the credential asserts. + * + * @return a GSSName representing the entity + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public GSSName getName() throws GSSException + { + return new JCCSimpleGSSName(userid_); + } + + /** + * Retrieves a Mechanism Name of the entity that the credential + * asserts. This is equivalent to calling {@link + * GSSName#canonicalize(Oid) canonicalize} on the value returned by + * the other form of {@link #getName() getName}. + * + * @param mech the Oid of the mechanism for which the Mechanism Name + * should be returned. + * @return a GSSName representing the entity canonicalized for the + * desired mechanism + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public GSSName getName(Oid mech) throws GSSException + { + throw new JCCSimpleGSSException(0,"getName(Oid mech) method isn't implemented."); + } + + /** + * Returns the remaining lifetime in seconds for a credential. The + * remaining lifetime is the minimum lifetime amongst all of the underlying + * mechanism specific credential elements. + * + * @return the minimum remaining lifetime in seconds for this + * credential. A return value of {@link #INDEFINITE_LIFETIME + * INDEFINITE_LIFETIME} indicates that the credential does + * not expire. A return value of 0 indicates that the credential is + * already expired. + * + * @see #getRemainingInitLifetime(Oid) + * @see #getRemainingAcceptLifetime(Oid) + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public int getRemainingLifetime() throws GSSException + { + return INDEFINITE_LIFETIME; + } + + /** + * Returns the lifetime in seconds for the credential to remain capable + * of initiating security contexts using the specified mechanism. This + * method queries the initiator credential element that belongs to the + * specified mechanism. + * + * @return the number of seconds remaining in the life of this credential + * element. A return value of {@link #INDEFINITE_LIFETIME + * INDEFINITE_LIFETIME} indicates that the credential element does not + * expire. A return value of 0 indicates that the credential element is + * already expired. + * + * @param mech the Oid of the mechanism whose intiator credential element + * should be queried. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public int getRemainingInitLifetime(Oid mech) throws GSSException + { + return INDEFINITE_LIFETIME; + } + + /** + * Returns the lifetime in seconds for the credential to remain capable + * of accepting security contexts using the specified mechanism. This + * method queries the acceptor credential element that belongs to the + * specified mechanism. + * + * @return the number of seconds remaining in the life of this credential + * element. A return value of {@link #INDEFINITE_LIFETIME + * INDEFINITE_LIFETIME} indicates that the credential element does not + * expire. A return value of 0 indicates that the credential element is + * already expired. + * + * @param mech the Oid of the mechanism whose acceptor credential element + * should be queried. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public int getRemainingAcceptLifetime(Oid mech) throws GSSException + { + return INDEFINITE_LIFETIME; + } + + /** + * Returns the credential usage mode. In other words, it + * tells us if this credential can be used for initiating or accepting + * security contexts. It does not tell us which mechanism(s) has to be + * used in order to do so. It is expected that an application will allow + * the GSS-API to pick a default mechanism after calling this method. + * + * @return The return value will be one of {@link #INITIATE_ONLY + * INITIATE_ONLY}, {@link #ACCEPT_ONLY ACCEPT_ONLY}, and {@link + * #INITIATE_AND_ACCEPT INITIATE_AND_ACCEPT}. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public int getUsage() throws GSSException + { + return INITIATE_AND_ACCEPT; + } + + /** + * Returns the credential usage mode for a specific mechanism. In other + * words, it tells us if this credential can be used + * for initiating or accepting security contexts with a given underlying + * mechanism. + * + * @return The return value will be one of {@link #INITIATE_ONLY + * INITIATE_ONLY}, {@link #ACCEPT_ONLY ACCEPT_ONLY}, and {@link + * #INITIATE_AND_ACCEPT INITIATE_AND_ACCEPT}. + * @param mech the Oid of the mechanism whose credentials usage mode is + * to be determined. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public int getUsage(Oid mech) throws GSSException + { + return INITIATE_AND_ACCEPT; + } + + /** + * Returns a list of mechanisms supported by this credential. It does + * not tell us which ones can be used to initiate + * contexts and which ones can be used to accept contexts. The + * application must call the {@link #getUsage(Oid) getUsage} method with + * each of the returned Oid's to determine the possible modes of + * usage. + * + * @return an array of Oid's corresponding to the supported mechanisms. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public Oid[] getMechs() throws GSSException + { + throw new JCCSimpleGSSException(0,"getMechs() is not implemented"); + } + + /** + * Adds a mechanism specific credential-element to an existing + * credential. This method allows the construction of credentials, one + * mechanism at a time.

+ * + * This routine is envisioned to be used mainly by context acceptors + * during the creation of acceptor credentials which are to be used + * with a variety of clients using different security mechanisms.

+ * + * This routine adds the new credential element "in-place". To add the + * element in a new credential, first call clone to obtain a + * copy of this credential, then call its add method.

+ * + * As always, GSS-API implementations must impose a local access-control + * policy on callers to prevent unauthorized callers from acquiring + * credentials to which they are not entitled. + * + * Non-default values for initLifetime and acceptLifetime cannot always + * be honored by the underlying mechanisms, thus callers should be + * prepared to call {@link #getRemainingInitLifetime(Oid) + * getRemainingInitLifetime} and {@link #getRemainingAcceptLifetime(Oid) + * getRemainingAcceptLifetime} on the credential. + * + * @param name the name of the principal for whom this credential is to + * be acquired. Use null to specify the default + * principal. + * @param initLifetime the number of seconds that the credential element + * should remain valid for initiating of security contexts. Use {@link + * GSSCredential#INDEFINITE_LIFETIME GSSCredential.INDEFINITE_LIFETIME} + * to request that the credentials have the maximum permitted lifetime + * for this. Use {@link GSSCredential#DEFAULT_LIFETIME + * GSSCredential.DEFAULT_LIFETIME} to request default credential lifetime + * for this. + * @param acceptLifetime the number of seconds that the credential + * element should remain valid for accepting security contexts. Use {@link + * GSSCredential#INDEFINITE_LIFETIME GSSCredential.INDEFINITE_LIFETIME} + * to request that the credentials have the maximum permitted lifetime + * for this. Use {@link GSSCredential#DEFAULT_LIFETIME + * GSSCredential.DEFAULT_LIFETIME} to request default credential lifetime + * for this. + * @param mech the mechanism over which the credential is to be acquired. + * @param usage the usage mode that this credential + * element should add to the credential. The value + * of this parameter must be one of: + * {@link #INITIATE_AND_ACCEPT INITIATE_AND_ACCEPT}, + * {@link #ACCEPT_ONLY ACCEPT_ONLY}, and + * {@link #INITIATE_ONLY INITIATE_ONLY}. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#DUPLICATE_ELEMENT + * GSSException.DUPLICATE_ELEMENT}, + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#BAD_NAMETYPE GSSException.BAD_NAMETYPE}, + * {@link GSSException#NO_CRED GSSException.NO_CRED}, + * {@link GSSException#CREDENTIALS_EXPIRED + * GSSException.CREDENTIALS_EXPIRED}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void add(GSSName name, int initLifetime, int acceptLifetime, + Oid mech, int usage) throws GSSException + { + throw new JCCSimpleGSSException(0,"add(GSSName name, int initLifetime, int acceptLifetime,Oid mech, int usage) is not implemented"); + } + + /** + * Tests if this GSSCredential asserts the same entity as the supplied + * object. The two credentials must be acquired over the same + * mechanisms and must refer to the same principal. + * + * @return true if the two GSSCredentials assert the same + * entity; false otherwise. + * @param another another GSSCredential for comparison to this one + */ + public boolean equals(Object another) + { + if (another instanceof JCCSimpleGSSCredential) + return (userid_ == ((JCCSimpleGSSCredential)another).getUserid() && password_ == ((JCCSimpleGSSCredential)another).getPassword()); + else + return false; + + } + + /** + * Returns a hashcode value for this GSSCredential. + * + * @return a hashCode value + */ + public int hashCode() + { + //not used by JCC. return 0 + return 0; + } + + +} diff --git a/java/jdbc/JCCSimpleGSSException.java b/java/jdbc/JCCSimpleGSSException.java new file mode 100644 index 0000000..70eba70 --- /dev/null +++ b/java/jdbc/JCCSimpleGSSException.java @@ -0,0 +1,61 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: JCCSimpleGSSEexception.java +// +// SAMPLE: This file is used by JCCSimpleGSSPlugin and JCCKerberosPlugin +// to handle Exceptions +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + + +public class JCCSimpleGSSException extends org.ietf.jgss.GSSException +{ + String reason_; + public JCCSimpleGSSException(int majorCode,String reason) + { + super(majorCode); + reason_ = reason; + } + + public JCCSimpleGSSException (int majorCode, int minorCode, String minorString, String reason) + { + super(majorCode, minorCode, minorString); + reason_ = reason; + } + + public String getMessage() + { + return super.getMessage() + " " + reason_; + } +} diff --git a/java/jdbc/JCCSimpleGSSName.java b/java/jdbc/JCCSimpleGSSName.java new file mode 100644 index 0000000..e51b4c3 --- /dev/null +++ b/java/jdbc/JCCSimpleGSSName.java @@ -0,0 +1,227 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: JCCSimpleGSSName.java +// +// SAMPLE: This file is used by JCCSimpleGSSPlugin to implement a JCC +// GSS-API plugin sample +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.InputStream; +import java.io.OutputStream; +import org.ietf.jgss.*; + +public class JCCSimpleGSSName implements org.ietf.jgss.GSSName +{ + private String userid_; + + public JCCSimpleGSSName(String userid) + { + userid_ = userid; + } + + public String getUserid() + { + return userid_; + } + + public void setUserid(String user) + { + userid_ = user; + } + + /** + * Compares two GSSName objects to determine if they refer to the + * same entity. + * + * @param another the GSSName to compare this name with + * @return true if the two names contain at least one primitive element + * in common. If either of the names represents an anonymous entity, the + * method will return false. + * + * @throws GSSException when the names cannot be compared, containing the following + * major error codes: + * {@link GSSException#BAD_NAMETYPE GSSException.BAD_NAMETYPE}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public boolean equals(GSSName another) throws GSSException + { + if(another instanceof JCCSimpleGSSName) + return (userid_ == ((JCCSimpleGSSName)another).getUserid()); + else + return false; + } + + /** + * Compares this GSSName object to another Object that might be a + * GSSName. The behaviour is exactly the same as in {@link + * #equals(GSSName) equals} except that no GSSException is thrown; + * instead, false will be returned in the situation where an error + * occurs. + * @return true if the object to compare to is also a GSSName and the two + * names refer to the same entity. + * @param another the object to compare this name to + * @see #equals(GSSName) + */ + public boolean equals(Object another) + { + if(another instanceof JCCSimpleGSSName) + return (userid_ == ((JCCSimpleGSSName)another).getUserid()); + else + return false; + + } + + /** + * Returns a hashcode value for this GSSName. + * + * @return a hashCode value + */ + public int hashCode() + { + //not used by JCC, return 0 + return 0; + } + + /** + * Creates a name that is canonicalized for some + * mechanism. + * + * @return a GSSName that contains just one primitive + * element representing this name in a canonicalized form for the desired + * mechanism. + * @param mech the oid for the mechanism for which the canonical form of + * the name is requested. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#BAD_MECH GSSException.BAD_MECH}, + * {@link GSSException#BAD_NAMETYPE GSSException.BAD_NAMETYPE}, + * {@link GSSException#BAD_NAME GSSException.BAD_NAME}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public GSSName canonicalize(Oid mech) throws GSSException + { + throw new JCCSimpleGSSException(0,"canonicalize(Oid mech) is not implemented"); + } + + /** + * Returns a canonical contiguous byte representation of a mechanism name + * (MN), suitable for direct, byte by byte comparison by authorization + * functions. If the name is not an MN, implementations may throw a + * GSSException with the NAME_NOT_MN status code. If an implementation + * chooses not to throw an exception, it should use some system specific + * default mechanism to canonicalize the name and then export + * it. Structurally, an exported name object consists of a header + * containing an OID identifying the mechanism that authenticated the + * name, and a trailer containing the name itself, where the syntax of + * the trailer is defined by the individual mechanism specification. The + * format of the header of the output buffer is specified in RFC 2743.

+ * + * The exported name is useful when used in large access control lists + * where the overhead of creating a GSSName object on each + * name and invoking the equals method on each name from the ACL may be + * prohibitive.

+ * + * Exported names may be re-imported by using the byte array factory + * method {@link GSSManager#createName(byte[], Oid) + * GSSManager.createName} and specifying the NT_EXPORT_NAME as the name + * type object identifier. The resulting GSSName name will + * also be a MN.

+ * @return a byte[] containing the exported name. RFC 2743 defines the + * "Mechanism-Independent Exported Name Object Format" for these bytes. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#BAD_NAME GSSException.BAD_NAME}, + * {@link GSSException#BAD_NAMETYPE GSSException.BAD_NAMETYPE}, + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public byte[] export() throws GSSException + { + throw new JCCSimpleGSSException(0,"export() is not implemented"); + } + + /** + * Returns a textual representation of the GSSName object. To retrieve + * the printed name format, which determines the syntax of the returned + * string, use the {@link #getStringNameType() getStringNameType} + * method. + * + * @return a String representing this name in printable form. + */ + public String toString() + { + return super.toString() + " "+ userid_; + } + + /** + * Returns the name type of the printable + * representation of this name that can be obtained from the + * toString method. + * + * @return an Oid representing the namespace of the name returned + * from the toString method. + * + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public Oid getStringNameType() throws GSSException + { + throw new JCCSimpleGSSException(0,"getStringNameType() is not implemented"); + } + + /** + * Tests if this name object represents an anonymous entity. + * + * @return true if this is an anonymous name, false otherwise. + */ + public boolean isAnonymous() + { + return false; + } + + /** + * Tests if this name object represents a Mechanism Name (MN). An MN is + * a GSSName the contains exactly one mechanism's primitive name + * element. + * + * @return true if this is an MN, false otherwise. + */ + public boolean isMN() + { + return false; + } +} diff --git a/java/jdbc/JCCSimpleGSSPlugin.java b/java/jdbc/JCCSimpleGSSPlugin.java new file mode 100644 index 0000000..5fb9638 --- /dev/null +++ b/java/jdbc/JCCSimpleGSSPlugin.java @@ -0,0 +1,169 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: JCCSimpleGSSPlugin.java +// +// SAMPLE: Implement a JCC GSS-API plugin sample which does a +// userid and password check +// +// This set of sample shows +// +// 1. How to implement a JCC GSS-API plugin sample which does a userid and password check +// 2. How to use this sample plugin to get a Connection +// +// In order to implement a JCC plugin in, user needs to extend com.ibm.db2.jcc.DB2JCCPlugin +// and implement the following method: +// public abstract byte[] getTicket (String username, String password, +// byte[] returnedToken) throws org.ietf.jgss.GSSException; +// +// Plugin users also need to implement some JGSS APIs. The following is a list of JGSS-APIs +// required for Java Security Plugin interface. +// +// GSSContext.requestMutualAuth(boolean state) +// GSSContext.getMutualAuthState() +// GSSContext.requestCredDeleg(boolean state) +// GSSContext.getCredDelegState() +// GSSContext.initSecContext (byte[] inputBuf, int offset, int len) +// GSSContext.dispose() +// GSSCredential.dispose() +// +// The APIs should follow the Generic Security Service Application Program Interface, +// Version 2 (IETF RFC2743) and Generic Security Service +// API Version 2: Java-Bindings (IETF RFC2853) specifications. +// +// This JCCSimpleGSSPlugin implements a sample that does a simple GSS-API plugin +// that performs userid and password checking. It corresponds to the c sample plugin +// gssapi_simple in sqllib\samples\securtiy\plugins\ +// +// The implementation of this JCCSimpleGSSPlugin contains the following 5 files: +// +// JCCSimpleGSSPlugin.java +// This file implements the sample JCCSimpleGSSPlugin. +// +// JCCSimpleGSSContext.java +// This file is used by JCCSimpleGSSPlugin.java to implement the plugin sample. +// +// JCCSimpleGSSCredential.java +// This file is used by JCCSimpleGSSPlugin.java to implement the plugin sample. +// +// JCCSimpleGSSException.java +// This file is used by JCCSimpleGSSPlugin.java to handle Exceptions. +// +// JCCSimpleGSSName.java +// This file is used by JCCSimpleGSSPlugin.java to implement the plugin sample. +// +// how to run this JCCSimpleGSSPlugin sample +// +// compile the above 5 files and JCCSimpleGSSPluginTest.java using javac *.java +// Run JCCSimpleGSSPluginTest using +// java JCCSimpleGSSPluginTest server port dbname userid password +// +// Note: To run this sample, server side plugin gssapi_simple needs to be installed in +// the server plug-in directory on the server. Database manager configuration +// parameters SRVCON_GSSPLUGIN_LIST and SRVCON_AUTH need to set correctly +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ +import org.ietf.jgss.*; + +public class JCCSimpleGSSPlugin extends com.ibm.db2.jcc.DB2JCCPlugin +{ + + protected org.ietf.jgss.GSSName serverGSSName_ ; + + public JCCSimpleGSSPlugin() + { + serverPrincipalName_ = "GSSAPI_SIMPLE"; + } + /** + * convert text service principal name into the GSS-API internal format for use with the other APIs + * @param serverPrincipalName String + * @throws GSSException + * @return GSSName + */ + + public org.ietf.jgss.GSSName processServerPrincipalName(String serverPrincipalName) throws org.ietf.jgss.GSSException + { + if (serverPrincipalName != null) + return new JCCSimpleGSSName(serverPrincipalName); + else + throw new JCCSimpleGSSException(0,"plugin bad principal name."); + } + + /** + * Generate the initial credentials based on the provided username/password pair and return the + * GSS-API credential + * @param username String + * @param password String + * @throws GSSException + * @return GSSCredential + */ + public org.ietf.jgss.GSSCredential generateInitialCred(String username, String password) throws org.ietf.jgss.GSSException + { + return new JCCSimpleGSSCredential(username, password); + } + + /** + * This method will generate the security context information for the username/password pair. + * The security context information will be used to get the connection + * @param userid String + * @param password String + * @param returnedToken byte[] the token returned by DB2 server + * @throws GSSException + * @return byte[] + */ + public byte[] getTicket(String userid, String password, byte[] returnedToken) throws java.sql.SQLException + { + try { + if (context_ == null || + ( (JCCSimpleGSSContext) context_).getctxCount() == 0) { + serverGSSName_ = (JCCSimpleGSSName) processServerPrincipalName( + serverPrincipalName_); + gssCredential_ = (JCCSimpleGSSCredential) generateInitialCred(userid, + password); + context_ = new JCCSimpleGSSContext( (JCCSimpleGSSCredential) gssCredential_, + (JCCSimpleGSSName) serverGSSName_, 0); + } + int length = 0; + if (returnedToken != null) + length = returnedToken.length; + context_.requestMutualAuth(true); + byte[] ticket = context_.initSecContext(returnedToken, 0, length); + return ticket; + } + catch (org.ietf.jgss.GSSException e) + { + throw new java.sql.SQLException(e.getMessage()); + } + + } +} diff --git a/java/jdbc/JCCSimpleGSSPluginTest.java b/java/jdbc/JCCSimpleGSSPluginTest.java new file mode 100644 index 0000000..9c146e9 --- /dev/null +++ b/java/jdbc/JCCSimpleGSSPluginTest.java @@ -0,0 +1,118 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: JCCSimpleGSSPluginTest.java +// SAMPLE: Get a DB2 Connection using plugin security +// +// This set of sample shows: +// 1. How to implement a JCC GSS-API plugin sample which does a userid and password check +// 2. How to use this sample plugin to get a Connection +// +// This sample plugin corresponds to the c sample plugin +// gssapi_simple in sqllib\samples\securtiy\plugins +// +// This set of sample contains the following 6 files: +// +// JCCSimpleGSSPluginTest.java +// This file uses sample plugin JCCSimpleGSSPlugin to get a Connection from DB2 server +// +// JCCSimpleGSSPlugin.java +// This file implements the sample JCCSimpleGSSPlugin that does a userid and password check. +// +// JCCSimpleGSSContext.java +// This file is used by JCCSimpleGSSPlugin.java to implement the plugin sample. +// +// JCCSimpleGSSCredential.java +// This file is used by JCCSimpleGSSPlugin.java to implement the plugin sample. +// +// JCCSimpleGSSException.java +// This file is used by JCCSimpleGSSPlugin.java to handle Exceptions +// +// JCCSimpleGSSName.java +// This file is used by JCCSimpleGSSPlugin.java to implement the plugin sample. +// +// how to run this JCCSimpleGSSPlugin sample +// +// compile the above 6 files using javac *.java +// Run JCCSimpleGSSPluginTest using +// java JCCSimpleGSSPluginTest server port dbname userid password +// Note: To run this sample, server side plugin gssapi_simple needs to be installed in +// the server plug-in directory on the server. Database manager configuration +// parameters SRVCON_GSSPLUGIN_LIST and SRVCON_AUTH need to set correctly +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ +public class JCCSimpleGSSPluginTest +{ + public static void main (String[] args) throws Exception + { + + if(args.length != 5) + throw new Exception("Usage: program_name [server] [port] [dbname] [userid] [password]"); + String ServerName = args[0]; + int PortNumber = (new Integer(args[1])).intValue(); + String DatabaseName = args[2]; + String userid = args[3]; + String password = args[4]; + + String url = "jdbc:db2://" + ServerName + ":"+ PortNumber + "/" + DatabaseName; + + java.util.Properties properties = new java.util.Properties(); + properties.put("user", userid); + properties.put("password", password); + properties.put("pluginName", "gssapi_simple"); + properties.put("securityMechanism", + new String("" + com.ibm.db2.jcc.DB2BaseDataSource.PLUGIN_SECURITY + "")); + properties.put("plugin", new JCCSimpleGSSPlugin()); + + java.sql.Connection con = null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + catch ( Exception e ) + { + System.out.println("Error: failed to load Db2 jcc driver."); + } + + try + { + con = java.sql.DriverManager.getConnection(url, properties); + System.out.println("Connected through JCC Type 4 driver using JCCSimpleGSSPlugin"); + + } + catch (Exception e) + { + System.out.println("Error occurred in getting Connection: "+ e.getMessage()); + } + } +} diff --git a/java/jdbc/LargeRid.java b/java/jdbc/LargeRid.java new file mode 100644 index 0000000..759e41a --- /dev/null +++ b/java/jdbc/LargeRid.java @@ -0,0 +1,757 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: LargeRid.java +// +// SAMPLE: How to enable Large RIDs support on both new tables/tablespaces +// and existing tables/tablespaces. +// +// SQL Statements USED: +// ALTER TABLESPACE +// CREATE TABLE +// CREATE TABLESPACE +// DROP +// INSERT +// REORG +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: LargeRid.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class LargeRid +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO ENABLE LARGE RID SUPPORT ON TABLES AND\n" + + " TABLESPACES\n"); + + // connect to the 'sample' database + db.connect(); + + dmstspaceaceCreate(db.con); + + System.out.println + ("\n************************************************************\n"); + System.out.println + ("THE FOLLOWING SCENARIO SHOWS HOW TO ENABLE LARGE RID SUPPORT"); + System.out.println(" FOR A NON-PARTITIONED TABLE\n"); + System.out.println + ("************************************************************"); + + tbCreate(db.con); + createIndex(db.con); + tbAlterSpace(db.con); + reorgIndex(db.con); + indexDrop(db.con); + + System.out.println + ("\n************************************************************\n"); + System.out.println + ("THE FOLLOWING SCENARIO SHOWS HOW TO ENABLE LARGE RID SUPPORT"); + System.out.println + (" FOR A PARTITIONED TABLE\n"); + System.out.println + ("************************************************************"); + + partitionedTbCreate(db.con); + insertData(db.con); + tbDetachPartition(db.con); + convertTbSpace(db.con); + tbReorganize(db.con); + tbAttachPartition(db.con); + tbDrop(db.con); + tablespacesDrop(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // Creates regular DMS tablespaces + static void dmstspaceaceCreate(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " CREATE REGULAR TABLESPACE \n" + + "TO CREATE A REGULAR TABLESPACE \n" + + "\n Execute the statement:\n" + + " CREATE REGULAR TABLESPACE dms_tspace"); + + // create regular DMS table space dms_tspace + Statement stmt = con.createStatement(); + String str = ""; + str = "CREATE REGULAR TABLESPACE dms_tspace"; + stmt.executeUpdate(str); + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE REGULAR TABLESPACE \n" + + "TO CREATE A REGULAR TABLESPACE \n" + + "\n Execute the statement:\n" + + " CREATE REGULAR TABLESPACE dms_tspace1"); + + // create regular DMS table space dms_tspace1 + str = "CREATE REGULAR TABLESPACE dms_tspace1"; + stmt.executeUpdate(str); + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE REGULAR TABLESPACE \n" + + "TO CREATE A REGULAR TABLESPACE \n" + + "\n Execute the statement:\n" + + " CREATE REGULAR TABLESPACE dms_tspace2"); + + // create regular DMS table space dms_tspace2 + str = "CREATE REGULAR TABLESPACE dms_tspace2"; + stmt.executeUpdate(str); + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE REGULAR TABLESPACE \n" + + "TO CREATE A REGULAR TABLESPACE \n" + + "\n Execute the statement:\n" + + " CREATE REGULAR TABLESPACE dms_tspace3"); + + // create regular DMS table space dms_tspace3 + str = "CREATE REGULAR TABLESPACE dms_tspace3"; + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // dmstspaceaceCreate + + // Creates a non-partitioned table. + static void tbCreate(Connection con) throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n" + + "\n Execute the statement:\n" + + " CREATE TABLE large (max INT, min INT) IN dms_tspace"); + + // create table in 'dms_tspace' regular DMS tablespace + Statement stmt = con.createStatement(); + String str = ""; + str = "CREATE TABLE large (max INT, min INT)" + + " IN dms_tspace"; + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tbCreate + + // Creates index on a table. + static void createIndex(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " CREATE INDEX \n" + + "TO CREATE AN INDEX \n" + + "\n Execute the statement:\n" + + " CREATE INDEX large_ind ON large (max)"); + + // create index + Statement stmt = con.createStatement(); + stmt.executeUpdate("CREATE INDEX large_ind ON large (max)"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // createIndex + + // Changes table space from regular to large. + static void tbAlterSpace(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLESPACE \n" + + "TO ALTER A TABLESPACE \n" + + "\n Execute the statement:\n" + + " ALTER TABLESPACE dms_tspace CONVERT TO LARGE"); + + // convert regular DMS tablespace 'dms_tspace' to large DMS tablespace + Statement stmt = con.createStatement(); + stmt.executeUpdate("ALTER TABLESPACE dms_tspace CONVERT TO LARGE"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tbAlterSpace + + // Reorganize indexes defined on a table. + static void reorgIndex(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " REORG INDEXES \n" + + "TO REORG INDEXES FOR A TABLE \n" + + "\n Execute the statement:\n" + + " REORG INDEXES ALL FOR TABLE large"); + + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + CallableStatement callStmt1 = con.prepareCall(sql); + + String param = "REORG INDEXES ALL FOR TABLE large" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // reorgIndex + + // Drop indexes defined on a table. + static void indexDrop(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " DROP INDEX \n" + + "TO DROP AN INDEX \n" + + "\n Execute the statement:\n" + + " DROP INDEX large_ind"); + + // drop the index + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX large_ind"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // indexDrop + + // Creates a partitioned table with 'part1' in 'dms_tspace1', 'part2' + // in 'dms_tspace2', and 'part3' in 'dms_tspace3'. + static void partitionedTbCreate(Connection con) throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n" + + "\n Execute the statement:\n" + + " CREATE TABLE large_ptab (max SMALLINT NOT NULL,\n" + + " CONSTRAINT CC CHECK (max>0))\n" + + " PARTITION BY RANGE (max)\n "+ + " (PART part1 STARTING FROM (1) ENDING (3) IN dms_tspace1,\n" + + " PART part2 STARTING FROM (4) ENDING (6) IN dms_tspace2,\n" + + " PART part3 STARTING FROM (7) ENDING (9) IN dms_tspace3)"); + + // create a partitioned table in regular DMS tablespaces i.e; part1 is + // placed at dms_tspace1, part2 is placed at dms_tspace2 and + // part3 at dms_tspace3. + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "CREATE TABLE large_ptab " + + "(max SMALLINT NOT NULL, CONSTRAINT CC CHECK (max>0))" + + " PARTITION BY RANGE (max) " + + "(PART part1 STARTING FROM (1) ENDING (3) " + + "IN dms_tspace1, PART part2 STARTING FROM (4) ENDING (6) " + + "IN dms_tspace2, PART part3 STARTING FROM (7) ENDING (9) " + + "IN dms_tspace3)"; + + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // partitionedTbCreate + + // Insert data into the table. + static void insertData(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " INSERT INTO \n" + + "TO INSERT DATA IN A TABLE \n" + + "\n Execute the statement:\n" + + " INSERT INTO large_ptab VALUES (1), (2), (3),\n" + + " (4), (5), (6),\n" + + " (7), (8), (9)"); + + // insert data into the table + Statement stmt = con.createStatement(); + String str = ""; + + str = "INSERT INTO large_ptab VALUES (1), (2), (3), (4)," + + " (5), (6), (7), (8), (9)"; + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // insertData + + // If a partitioned table has data partitions in different regular DMS + // tablespaces, then the tablespaces cannot be converted to large + // with the current definition. + // To do this, first detach all the partitions of the table, later + // convert all the tablespaces to large, reorg all the detached + // partitions to support large RID. Finally, reattach the partitions. + // Now the entire table supports large RIDs. + + // Remove partition from a partitioned table. + static void tbDetachPartition(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLE \n" + + "TO DETACH THE PARTITIONS \n" + + "\n Execute the statements:\n" + + " ALTER TABLE large_ptab\n" + + " DETACH PARTITION PART3\n" + + " INTO TABLE detach_part3\n\n" + + " ALTER TABLE large_ptab\n" + + " DETACH PARTITION PART3\n" + + " INTO TABLE detach_part2"); + + // detach partitions from base table into some temporary tables + CallableStatement callStmt1 = null; + Statement stmt = con.createStatement(); + String str =""; + String out = ""; + + str = "ALTER TABLE large_ptab DETACH PARTITION part3 " + + "INTO TABLE detach_part3"; + stmt.executeUpdate(str); + con.commit(); + + waitForDetachPart(con); + stmt.executeUpdate("DROP PROCEDURE tableExists"); + stmt.executeUpdate("DROP PROCEDURE waitForDetach"); + + str = "ALTER TABLE large_ptab DETACH PARTITION part2 " + + "INTO TABLE detach_part2"; + stmt.executeUpdate(str); + con.commit(); + waitForDetachPart(con); + + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tbDetachPartition + + // Changes table space from regular to large. + static void convertTbSpace(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLE \n" + + "TO DETACH THE PARTITIONS \n" + + "\n Execute the statements:\n" + + " ALTER TABLESPACE dms_tspace1 CONVERT TO LARGE\n" + + " ALTER TABLESPACE dms_tspace2 CONVERT TO LARGE\n" + + " ALTER TABLESPACE dms_tspace3 CONVERT TO LARGE"); + + // convert regular DMS tablespaces to large DMS tablespaces + Statement stmt = con.createStatement(); + stmt.executeUpdate("ALTER TABLESPACE dms_tspace1 CONVERT TO LARGE"); + con.commit(); + stmt.executeUpdate("ALTER TABLESPACE dms_tspace2 CONVERT TO LARGE"); + con.commit(); + stmt.executeUpdate("ALTER TABLESPACE dms_tspace3 CONVERT TO LARGE"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // convertTbSpace + + // Reorganize table. + static void tbReorganize(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " REORG TABLE \n" + + "TO REORG THE DETACHED PARTITIONS \n" + + "\n Execute the statements:\n" + + " REORG TABLE large_ptab ALLOW NO ACCESS\n" + + " REORG TABLE detach_part2 ALLOW NO ACCESS\n" + + " REORG TABLE detach_part3 ALLOW NO ACCESS\n"); + + String sql = "CALL SYSPROC.ADMIN_CMD(?)"; + CallableStatement callStmt1 = con.prepareCall(sql); + + String param1 = "REORG TABLE large_ptab ALLOW NO ACCESS"; + String param2 = "REORG TABLE detach_part2 ALLOW NO ACCESS"; + String param3 = "REORG TABLE detach_part3 ALLOW NO ACCESS"; + + // set the input parameter + callStmt1.setString(1, param1); + + // execute reorg by calling ADMIN_CMD + callStmt1.execute(); + + // set the input parameter + callStmt1.setString(1, param2); + + // execute reorg by calling ADMIN_CMD + callStmt1.execute(); + + // set the input parameter + callStmt1.setString(1, param3); + + // execute reorg by calling ADMIN_CMD + callStmt1.execute(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tbReorganize + + // Add partition to a partitioned table. + static void tbAttachPartition(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " REORG TABLE \n" + + "TO REORG THE DETACHED PARTITIONS \n" + + "\n Execute the statements:\n" + + " ALTER TABLE large_ptab\n" + + " ATTACH PARTITION part2\n" + + " STARTING FROM (4) ENDING (6)\n" + + " FROM TABLE detach_part2\n\n" + + " ALTER TABLE large_ptab\n" + + " ATTACH PARTITION part2\n" + + " STARTING FROM (7) ENDING (9)\n" + + " FROM TABLE detach_part3"); + + // reattach the reorganized detached partitions for table to support + // large RIDs. + Statement stmt = con.createStatement(); + String str = ""; + + str = "ALTER TABLE large_ptab ATTACH PARTITION part2" + + " STARTING FROM (4) ENDING (6)" + + " FROM TABLE detach_part2"; + stmt.executeUpdate(str); + + str = "ALTER TABLE large_ptab ATTACH PARTITION part3"; + str = str + " STARTING FROM (7) ENDING (9)"; + str = str + " FROM TABLE detach_part3"; + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tbAttachPartition + + // Drop tables. + static void tbDrop(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " DROP \n" + + "TO DROP THE TABLES \n" + + "\n Execute the statements:\n" + + " DROP TABLE large\n" + + " DROP TABLE large_ptab"); + + // drop the tables + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE large"); + stmt.executeUpdate("DROP TABLE large_ptab"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tbDrop + + // Drop tablespaces. + static void tablespacesDrop(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " DROP \n" + + "TO DROP THE TABLESPACES \n" + + "\n Execute the statements:\n" + + " DROP TABLESPACE dms_tspace\n" + + " DROP TABLESPACE dms_tspace1\n" + + " DROP TABLESPACE dms_tspace2\n" + + " DROP TABLESPACE dms_tspace3"); + + // drop the tablespaces + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLESPACE dms_tspace"); + stmt.executeUpdate("DROP TABLESPACE dms_tspace1"); + stmt.executeUpdate("DROP TABLESPACE dms_tspace2"); + stmt.executeUpdate("DROP TABLESPACE dms_tspace3"); + stmt.executeUpdate("DROP PROCEDURE tableExists"); + stmt.executeUpdate("DROP PROCEDURE waitForDetach"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tablespacesDrop + + + static void waitForDetachPart(Connection con) throws SQLException + { + try + { + Statement stmt = null; + + stmt = con.createStatement(); + + String str = "create procedure tableExists (IN schemaName varchar(128), IN tableName varchar(128), OUT notFound int) "+ + "specific tableExists "+ + "language SQL "+ + "BEGIN "+ + "declare dpid int; "+ + "declare tabCheck cursor for "+ + "select DATAPARTITIONID from sysibm.sysdatapartitions where tabschema = schemaName and tabname = tableName; "+ + "declare exit handler for NOT FOUND "+ + "set notFound = 1; "+ + "open tabCheck; "+ + "fetch tabCheck into dpid; "+ + "close tabCheck; "+ + "END "; + + stmt.executeUpdate(str); + + + str = "create procedure waitForDetach "+ + "(OUT msg varchar(128), IN schemaName varchar(128), IN tableName varchar(128), IN partName varchar(128) DEFAULT NULL) "+ + "specific waitForDetach "+ + "language SQL "+ + "BEGIN "+ + "declare dpid int; "+ + "declare dpstate char; "+ + "declare done int default 0; "+ + " declare tabNotFound int default 0; "+ + "declare allDetachCheck cursor for "+ + "select DATAPARTITIONID, STATUS from sysibm.sysdatapartitions "+ + "where tabschema = schemaName and tabname = tableName and (status = 'L' OR status = 'D'); "+ + "declare oneDetachCheck cursor for "+ + "select DATAPARTITIONID, STATUS from sysibm.sysdatapartitions "+ + "where tabschema = schemaName and tabname = tableName and datapartitionname = partName; "+ + "declare continue handler for NOT FOUND "+ + "set done = 1; "+ + "set current lock timeout 120; "+ + "call tableExists (schemaName, tableName, tabNotFound); "+ + "if tabNotFound = 1 "+ + "THEN "+ + "set msg = 'Table not found'; "+ + "RETURN -1; "+ + "END IF; "+ + "wait_loop: "+ + " LOOP "+ + "if partName IS NOT NULL "+ + "THEN "+ + "open oneDetachCheck; "+ + "fetch oneDetachCheck into dpid, dpstate; "+ + "IF done <> 1 AND (dpstate = '' OR dpstate = 'A') "+ + "THEN "+ + "set msg = 'Cannot waitForDetach if DETACH was not issued on this partition'; "+ + "return -1; "+ + " END IF; "+ + "close oneDetachCheck; "+ + "ELSE "+ + "open allDetachCheck; "+ + "fetch allDetachCheck into dpid, dpstate; "+ + "close allDetachCheck; "+ + "END IF; "+ + "if done = 1 "+ + "THEN "+ + "set msg = 'DETACH completed'; "+ + "LEAVE wait_loop; "+ + "ELSE "+ + "ITERATE wait_loop; "+ + " END IF; "+ + "END LOOP; "+ + "END"; + + + stmt.executeUpdate(str); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } +} // LargeRid diff --git a/java/jdbc/README b/java/jdbc/README new file mode 100644 index 0000000..8d14137 --- /dev/null +++ b/java/jdbc/README @@ -0,0 +1,431 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for JDBC Samples on Unix +* +* The /sqllib/samples/java/jdbc directory contains this README +* file. Where is the location of DB2 9.7 on your hard drive. +* The default location for is +* $HOME +* +* This README describes how to build and run jdbc sample code for DB2 9.7. +* The DB2 9.7 jdbc samples are located in the following directory: +* /sqllib/samples/java/jdbc +* +* Copy the files from this directory to your working directory prior to +* building the sample programs. The sample programs directory is +* typically read-only on most platforms and some samples produce output +* files that require write permissions on the directory. +* +* WARNING: Some of these samples may change your database or database +* manager configuration. Execute the samples against a test database +* only, such as the DB2 SAMPLE database. +* +****************************************************************************** +* +* Prepare your DB2 sample development environment +* +* 1) Copy the files in /sqllib/samples/java/jdbc/* to your +* working directory and ensure that directory has write permission. +* +* 2) Modify the CLASSPATH to include: +* /sqllib/java/db2java.zip +* /sqllib/java/db2jcc.jar +* /sqllib/java/db2jcc_license_cu.jar +* /sqllib/java//lib +* /sqllib/lib +* /sqllib/function +* /sqllib/java/sqlj.zip +* where is the name of the +* jdk directory under /sqllib/java. +* +* Modify the PATH to include /sqllib/java//bin, +* /sqllib/lib. +* +* Please make sure that JDK_PATH( db2 +* database manager configuration parameter) is +* pointing to the /sqllib/java/. +* +* To see the dbm cfg parameter value, run the following from db2 +* command window and look for the value of JDK_PATH +* db2 get dbm cfg +* +* 3) Start the Database Manager with the following command: +* db2start +* +* 4) Create the sample database with the following command: +* db2sampl +* +* 5) Connect to the database with the following command: +* db2 connect to sample +* +* 6) To build Stored Procedures and User Defined Functions, ensure +* that you have write permission on the +* /sqllib/function directory. +* +* 7) cd to the directory containing the files copied in step 1. +* +****************************************************************************** +* +* Building DB2 Samples +* +* There are two ways to build DB2 samples: using a make utility or +* using javac compiler. +* +* o To build samples using the make utility see +* 'BUILDING SAMPLES USING make UTILITY'. +* o To build samples using the javac compiler or when you do not +* have a compatible make utility see 'BUILDING +* SAMPLES USING JAVAC COMPILER'. +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING make UTILITY *** +* +* If you have a compatible make utility on your system, you +* can use the makefile provided. Modify the PATH +* variable to include the directory containing the make +* utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'make' command in your working +* directory: +* +* o make - builds the sample identified by +* +* Do not include the file extension for the +* program name. E.g. make DbAuth +* For any dependencies refer to the individual sample. +* +* o make srv - builds only samples that can be run on the +* server,including routines (stored procedures and User +* Defined Functions). +* +* o make rtn - builds only routines. +* +* o make call_rtn - builds only client programs that call +* routines. +* +* o make client_run - builds only programs that run +* completely on the client (not ones that call routines). +* +* o make all_client - builds all client samples (all +* programs in the 'call_rtn' and 'client_run' categories). +* +* o make all - builds all supplied sample programs including +* routines, stored procedures and UDFs. +* +* After compiling the sample, run it using normal java +* invocation, java +* +* Note: +* The makefile provided will only work if a compatible make +* executable program is resident on your system in a directory +* included in your PATH variable. Such a make utility may be +* provided by another language compiler. +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING JAVAC COMPILER *** +* +* As an alternative to the makefile, the javac compiler +* can be used to build the jdbc samples. +* +* If you do not have a compatible make utility you can use +* the javac bytecode compiler to build JDBC programs. +* +* Building and Executing Standalone Samples +* ----------------------------------------- +* +* o Build the general utility class called Util.java. +* javac Util.java +* +* o Build the sample program +* javac .java +* +* o After compiling the sample, run it using normal java +* invocation +* java +* +* Building and Executing Stored Procedures +* ---------------------------------------- +* +* o Build the server file sample using: +* javac +* copy the resulting .class file +* to the sqllib/function directory. +* +* o Build jdbc store procedure using build file: +* spcat +* +* o Build the corresponding client file sample using: +* javac .java +* +* o Run the client sample using normal java invocation: +* java +* +* Building and Executing User Defined Functions: +* ---------------------------------------------- +* +* o Build the server file sample using: +* javac +* copy the resulting .class file +* to the sqllib/function directory. +* +* o Build the User Defined Functions using build files: +* udfcat or udfjcat +* +* o Build the corresponding client file sample using: +* javac .java +* +* o Run the client sample using normal java invocation: +* java +* +****************************************************************************** +* +* Common file Descriptions +* +* The following are the common files for JDBC samples. For more +* information on these files, refer to the program source files. +* +****************************************************************************** +* +* Common files +* +* README - this file! +* makefile - Makefile for all files +* Util.java - utilities used by most programs +* +****************************************************************************** +* +* JDBC Samples Design +* +* The JDBC sample programs form an object-based design reflecting the +* component nature of DB2. Related samples demonstrate a specific level +* of database programming. Each level is identified by the first two +* characters of the sample name. Here are the database levels +* represented by the samples: +* +* Identifier DB2 Level +* +* Ap Applet Level. +* Il Installation Image Level. +* Db Database Level. +* Tb Table Level. +* Dt Data Type Level. +* Ud UDF Level. +* Sp Stored Procedure Level. +* +* Also, there are tutorial samples that demonstrate how to implement +* Java GSS-API Plugin and how to use the plugin to get a DB2 connection +* using IBM DB2 Universal Driver (JCC driver). These programs begin +* with "JCC". +* +****************************************************************************** +* +* JDBC Sample Descriptions +* +* The following are the JDBC sample files included with DB2. For more +* information on the sample programs, refer to the program source +* files. +* +****************************************************************************** +* +* Applet Level +* +* Applt.html - HTML file for Applt.java +* Applt.java - How to create applets +* +****************************************************************************** +* +* Installation Image Level +* +* IlInfo.java - How to get and set installation level information. +* +****************************************************************************** +* +* ADMIN_CMD stored procedure samples (program files that deal with +* using SQL ADMIN_CMD() Stored Procedures) +* +* AdmCmdAutoCfg.java - How to autoconfigure a database +* AdmCmdContacts.java - How to add, update and drop contacts and +* contactgroups +* AdmCmdDescribe.java - How to describe table and indexes +* AdmCmdExport.java - How to export data +* AdmCmdImport.java - How to import data +* AdmCmdOnlineBackup.java - How to perform online backup +* AdmCmdQuiesce.java - How to quiesce tablespaces and database +* AdmCmdUpdateCfg.java - How to update, reset Database and Database +* Manager Configuration Parameters +****************************************************************************** +* +* Database Level +* +* DbAuth.java - How to grant/display/revoke authorities at +* database level. +* DbConn.java - How to connect and disconnect from a database. +* DbInfo.java - How to get and set information at a database +* level. +* DbMCon.java - How to connect and disconnect from multiple +* databases. +* DbNative.java - How to translate a statement that contains an +* ODBC escape clause to a data source specific +* format. +* DbRsHold.java - How to use result set cursor holdability +* DbSeq.java - How to create, alter and drop a sequence in a +* database. +* DbUse.java - How to work with database objects. +* GetDBCfgParams.java - How to get DB CFG Parameters. +* GetDBMCfgParams.java - How to get DBM CFG Parameters. +* GetLogs.java - How to get customer view of diagnostic log +* file entries. +* TrustedContext.java - How to establish an explicit trusted connection and +* switching of the user. +* +****************************************************************************** +* +* Table Level +* +* GetMessage.java - How to get error message in the required locale +* with token replacement. +* ImplicitCasting.java- To demonstrate use of implicit casting. +* LargeRid.java - How to enable Large RIDs support on both new +* tables/tablespaces and existing +* tables/tablespaces. +* SetIntegrity.java - How to perform online SET INTEGRITY on a table. +* ScalarFunctions.java- How to use scalar functions and special register. +* TbAST.java - How to use staging table for updating deferred +* AST. +* TbCompress.java - How to create tables with null and default +* value compression option. +* TbConstr.java - How to work with table constraints. +* TbCreate.java - How to create, alter, and drop tables. +* TbGenCol.java - How to use generated columns. +* TbIdent.java - How to use identity columns. +* TbMerge.java - How to use the MERGE statement. +* TbInfo.java - How to get and set information at a table +* level. +* TbInTrig.java - How to use INSTEAD OF triggers. +* TbMod.java - How to modify information in a table. +* TbOnlineInx.java - How to create and reorg indexes on a table. +* TbPriv.java - How to grant/display/revoke privileges at a +* table level. +* TbRead.java - How to read information in a table. +* TbRowcompress.java - To demonstrate row compression and automatic +* dictionary creation on a table +* TbRunstats.java - How to perform runstats on a table. +* TbSel.java - How to select from each of: insert, update, +* delete. +* TbTemp.java - How to use Declared Temporary Table. +* TbTrig.java - How to use a trigger on a table. +* TbUMQT.java - How to use user materialzed query tables +* (summary tables). +* TbUnion.java - How to insert through a UNION ALL view. +* Temporal.java - How to create Temporal Table and to add, +* modify and query data. +* +****************************************************************************** +* +* Data Type Level +* +* DtInfo.java - How to get information on data types. +* DtLob.java - How to read and write LOB data. +* DtUdt.java - How to create/use/drop user defined distinct types. +* +****************************************************************************** +* +* UDF Level +* +* UDFcli.java - Call the UDFs in UDFsrv.java. +* UDFCreate.db2 - CLP script to catalog the Java UDFs contained in +* UDFsrv.java. +* UDFDrop.db2 - CLP script to uncatalog the Java UDFs contained in +* UDFsrv.java. +* UDFjcli.java - Call the UDFs in UDFjsrv.java. +* UDFjCreate.db2 - CLP script to catalog the Java UDFs contained in +* UDFjsrv.java. +* UDFjDrop.db2 - CLP script to uncatalog the Java UDFs contained in +* UDFjsrv.java. +* UDFjsrv.java - Provide UDFs to be called by UDFjcli.java. +* UDFsCreate.db2 - CLP script to catalog the Java UDFs contained in +* UDFsqlsv.java. +* UDFsDrop.db2 - CLP script to uncatalog the Java UDFs contained in +* UDFsqlsv.java. +* UDFsqlcl.java - Call the UDFs in UDFsqlsv.java. +* UDFsqlsv.java - Provide UDFs to be called by UDFsqlcl.java. +* UDFsrv.java - Provide UDFs to be called by UDFcli.java. +* +****************************************************************************** +* +* Stored Procedure Level +* +* SpCreate.db2 - CLP script to issue CREATE PROCEDURE statements. +* SpDrop.db2 - CLP script to drop stored procedures from the +* catalog. +* SpClient.java - Client application that calls the stored procedures. +* SpServer.java - Stored procedure functions built and run on the +* server. +* bonus_calculate.db2 - CLP script to issue CREATE PROCEDURE for +* Arrays_Sqlpl.java. +* stack_functions.db2 - CLP script to issue CREATE PROCEDURE for +* Array_Stack.java sample. +* Arrays_Sqlpl.java - Client application that calls the SQL stored +* procedure created in bonus_calculate.db2. +* Array_Stack.java - Client application that calls the SQL stored +* procedure created in stack_functions.db2. +* +****************************************************************************** +* +* Java Beans Samples +* +* CreateEmployee.java - How to create an employee record. +* GeneratePayroll.java - How to generate payroll reports by +* department. +* +****************************************************************************** +* +* Java GSS-API Plugin Samples +* +* JCCKerberosPlugin.java - How to implement a GSS-API Plugin that +* does Kerberos authentication using IBM +* DB2 Universal Driver. +* JCCKerberosPluginTest.java - How to use JCCKerberosPlugin to get a +* DB2 Connection using IBM DB2 Universal +* Driver. +* JCCSimpleGSSPlugin.java - How to implement a GSS-API Plugin that +* does userid and password checking using +* IBM DB2 Universal Driver. +* JCCSimpleGSSContext.java - implement a GSSContext to be used by +* JCCSimpleGSSPlugin +* JCCSimpleGSSCrednetial.java - implement a GSSCredential to be used by +* JCCSimpleGSSPlugin +* JCCSimpleGSSException.java - implement a GSSException to be used by +* JCCSimpleGSSPlugin +* JCCSimpleGSSName.java - implement a GSSName to be used by +* JCCSimpleGSSPlugin +* JCCSimpleGSSPluginTest.java - How to use JCCSimpleGSSPlugin to get a +* DB2 Connection using IBM DB2 Universal +* Driver. +* +****************************************************************************** diff --git a/java/jdbc/ScalarFunctions.java b/java/jdbc/ScalarFunctions.java new file mode 100644 index 0000000..b957800 --- /dev/null +++ b/java/jdbc/ScalarFunctions.java @@ -0,0 +1,2437 @@ +//****************************************************************************** +// (c) Copyright IBM Corp. 2008 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose +// of assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the +// above limitations or exclusions may not apply to you. IBM shall not be +// liable for any damages you suffer as a result of using, copying, modifying +// or distributing the Sample, even if IBM has been advised of the possibility +// of such damages. +//****************************************************************************** +// +// SAMPLE FILE NAME: ScalarFunctions.java +// +// PURPOSE :To demonstrate how to use the following scalar functions and +// the special register. +// 1. INITCAP +// 2. LPAD +// 3. RPAD +// 4. TO_CLOB +// 5. TO_DATE +// 6. TO_CHAR +// 7. TO_NUMBER +// 8. DAYNAME +// 9. MONTHNAME +// 10. INSTR +// 11. LOCATE_IN_STRING +// 12. CURRENT LOCALE LC_TIME Register +// 13. TRUNC +// 14. ROUND +// 15. TRUNC_TIMESTAMP +// 16. ROUND_TIMESTAMP +// 17. VARCHAR_FORMAT +// 18. ADD_MONTHS +// 19. LAST_DAY +// +// +// +// PREREQUISITE: +// +// +// INPUTS: NONE +// +// OUTPUT: +// +// OUTPUT FILE: ScalarFunctions.out (available in online documentation) +// +// SQL STATEMENTS USED: +// CREATE TABLE +// INSERT +// SELECT +// VALUES +// TRUNCATE TABLE +// DROP TABLE +// +// SQL ROUTINES USED: +// NONE +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// ************************************************************************* +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// +// http://www.ibm.com/software/data/db2/ad/ +// +// *************************************************************************/ +// SAMPLE DESCRIPTION +// +// /************************************************************************* +// 1. Use of INITCAP Scalar Function. +// 2. Use of INITCAP Scalar Function with accented characters. +// 3. Use of LPAD Scalar Function. +// 4. Use of RPAD Scalar Function. +// 5. Use of TO_CLOB Scalar Function. +// 6. Use of TRUNC and TRUNCATE Scalar Function with numeric value. +// 7. Use of TRUNC and TRUNCATE Scalar Function with datetime value. +// 8. Use of ROUND Scalar Function with numeirc value. +// 9. Use of ROUND Scalar Function with datetime value. +// 10. Use of TRUNC_TIMESTAMP Scalar Function with datetime value. +// 11. Use of ROUND_TIMESTAMP Scalar Function with datetime value. +// 12. Use of TO_DATE Scalar Function. +// 13. Use of TO_CHAR Scalar Function. +// 14. Use of DAYNAME Scalar Function. +// 15. Use of MONTHNAME Scalar Function. +// 16. Use of INSTR Scalar Function. +// 17. Use of LOCATE_IN_STRING Scalar Function. +// 18. Use of CURRENT LOCALE LC_TIME register with TO_CHAR Scalar Function. +// 19. Use of CURRENT LOCALE LC_TIME register with TO_DATE Scalar Function. +// 20. Use of LAST_DAY Scalar Function. +// 21. Use of ADD_MONTHS Scalar Function. +// 22. Use of TO_NUMBER Scalar Function. +/***************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class ScalarFunctions +{ + static Db db; + public static void main(String argv[]) + { + + try + { + System.out.println(); + System.out.println( + "This sample shows how to use the following scalar functions: " + + "\n\t INITCAP \n" + + "\t LPAD \n" + + "\t RPAD \n" + + "\t TO_CLOB \n" + + "\t TO_DATE \n" + + "\t TO_CHAR \n" + + "\t DAYNAME \n" + + "\t MONTHNAME \n" + + "\t INSTR \n" + + "\t LOCATE_IN_STRING \n" + + "\t TO_NUMBER \n" + + "\t CURRENT LOCALE LC_TIME Register \n" + + "\t TRUNC \n" + + "\t ROUND \n" + + "\t TRUNC_TIMESTAMP \n" + + "\t ROUND_TIMESTAMP \n" + + "\t VARCHAR_FORMAT \n" + + "\t ADD_MONTHS \n" + + "\t LAST_DAY \n"); + Connection con = null; + + try + { + + db=new Db(argv); + + } + catch (Exception e) + { + System.out.println(" Error loading DB2 Driver...\n"); + System.out.println(e); + System.exit(1); + } + try + { + con=db.connect(); + con.setAutoCommit(false); + } + catch (Exception e) + { + System.out.println("Error while Connecting to sample database."); + System.err.println(e) ; + System.exit(1); + } + + // Functions calls to demonstrate each of the scalar functions + + // To Create Table + + CreateTable(con); + + /*****************************************************************/ + /* INITCAP */ + /*****************************************************************/ + + InitialCaps(con); + + /*****************************************************************/ + /* LPAD AND RPAD */ + /*****************************************************************/ + + Padding(con); + + /*****************************************************************/ + /* TO_CLOB */ + /*****************************************************************/ + + ToClob(con); + + /*****************************************************************/ + /* TO_DATE */ + /*****************************************************************/ + + ToDate(con); + + /*****************************************************************/ + /* TO_CHAR */ + /*****************************************************************/ + + ToChar(con); + + /*****************************************************************/ + /* TO_NUMBER */ + /*****************************************************************/ + + ToNumber(con); + + /*****************************************************************/ + /* Round */ + /*****************************************************************/ + + UseRound(con); + + /*****************************************************************/ + /* Truncate */ + /*****************************************************************/ + + UseTruncate(con); + + // Drop Table + + DropTable(con); + + // Disconnect from database. + + } + catch (Exception e) + { + System.out.println("Error Msg: "+ e.getMessage()); + } + }// Main + + + //Create table temp_table + + + static void CreateTable(Connection con) + { + try + { + String st="CREATE TABLE temp_table(rowno INTEGER,"+ + "tempdata VARCHAR(30),format VARCHAR(15))"; + + System.out.println("\nCREATE TABLE temp_table ("+ + "rowno INTEGER, "+ + "tempdata VARCHAR(30), "+ + "format VARCHAR(15))\n \n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate(st); + } + catch(Exception e) + { + System.out.print("Unable to Create Table....."+e); + } + }//CreateTable + + // InitCaps + + static void InitialCaps(Connection con) + { + try + { + String name; // Employee's name + + System.out.println("\nSELECT INITCAP "+ + "(Firstnme) FROM Employee"); + System.out.println("\n------------------------------------\n"); + + //Convert first character of each word to uppercase + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT INITCAP (Firstnme) "+ + "FROM Employee"); + while (rs.next()) + { + name = rs.getString(1); + System.out.println(name); + } + rs.close(); + stmt.close(); + + System.out.println("\nVALUES INITCAP "+ + "('THEODORE Q SPENSER is manager')"); + System.out.println("\n------------------------------------\n"); + + Statement stmt1 = con.createStatement(); + ResultSet rs1 = stmt1.executeQuery("VALUES INITCAP "+ + "('THEODORE Q SPENSER is manager')"); + + while (rs1.next()) + { + name = rs1.getString(1); + System.out.println(name); + } + + // INITCAP handles accented characters + System.out.println("\nVALUES INITCAP "+ + "('my name is �liz�beth �atz')"); + System.out.println("\n------------------------------------\n"); + + rs1 = stmt1.executeQuery("VALUES INITCAP "+ + "('my name is �liz�beth �atz')"); + while (rs1.next()) + { + name = rs1.getString(1); + System.out.println(name); + } + + rs1.close(); + stmt1.close(); + + // Commit + con.commit(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + } + } // InitialCaps + + +//Make a string certain length by adding (padding) a specified characters + +static void Padding(Connection con) +{ + try + { + String name; // Employee's name + + System.out.println("\nSELECT LPAD(Lastname, 10,'*') "+ + "AS LastName FROM Employee"); + System.out.println("\n------------------------------------\n"); + + // Make a string certain length by adding (padding) a specified + // characters to the left + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT LPAD(Lastname, 10,'*') "+ + "AS LastName FROM Employee"); + + while (rs.next()) + { + name = rs.getString(1); + System.out.println(name); + } + rs.close(); + stmt.close(); + + System.out.println("\nSELECT RPAD(Firstnme, 20, '.') FROM Employee"); + System.out.println("\n-----------------------------\n"); + + // Make a string certain length by adding (padding) a specified + // characters to the right + + Statement stmt1 = con.createStatement(); + ResultSet rs1 = stmt1.executeQuery("SELECT RPAD(Firstnme, 20, '.')"+ + " FROM Employee"); + + while (rs1.next()) + { + name = rs1.getString(1); + System.out.println(name); + } + rs1.close(); + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try + { + con.rollback(); + } + catch (SQLException sql) + { + System.out.println("Error Msg: "+ sql.getMessage()); + System.out.println("SQLState: "+sql.getSQLState()); + System.out.println("SQLError: "+sql.getErrorCode()); + } + System.exit(1); + } +} // Padding + +//Represent a character string as CLOB type + +static void ToClob(Connection con) +{ + try + { + Clob job; // Employee's Job + + System.out.println("\nSELECT TO_CLOB(Job) FROM Employee"); + System.out.println("\n----------------------------------------------\n"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT TO_CLOB(Job) FROM Employee"); + + while (rs.next()) + { + job = rs.getClob(1); + long jobLength = job.length(); + String jobString = job.getSubString(1, (int)jobLength); + System.out.println(jobString); + } + + /*****************************************************************/ + /* LOCATE_IN_STRING and INSTR */ + /* Returns the starting position of the first occurrence of */ + /* search string within another source string. */ + /*****************************************************************/ + + // Locate character "�" in the given string starting from position 1 + System.out.println("\nVALUES LOCATE_IN_STRING('J�rgen lives "+ + "on Hegelstra�e','�',1,CODEUNITS32)"); + System.out.println("\n----------------------------------------------\n"); + rs=stmt.executeQuery("VALUES LOCATE_IN_STRING('J�rgen lives "+ + "on Hegelstra�e','�',1,CODEUNITS32)"); + + while (rs.next()) + { + int loc=rs.getInt(1); + System.out.println(loc); + } + + // Locate string "position" in the given string. + + System.out.println("\nVALUES LOCATE_IN_STRING('The INSTR function "+ + "returns the starting position of the first "+ + "occurrence of one string within another string',"+ + "'position',1, OCTETS)"); + System.out.println("\n----------------------------------------------\n"); + + rs=stmt.executeQuery("VALUES LOCATE_IN_STRING('The INSTR "+ + "function returns the starting "+ + "position of the first occurrence "+ + "of one string within another string',"+ + "'position',1, OCTETS)"); + + while(rs.next()) + { + int loc1=rs.getInt(1); + System.out.println(loc1); + } + + // Locate the fourth occurrence of character "f" in the given string + System.out.println("\nVALUES INSTR('The INSTR function returns "+ + "the starting position of the first occurrence "+ + "of one string within another string', "+ + "'f',1, 4, OCTETS)"); + System.out.println("\n----------------------------------------------\n"); + + + rs=stmt.executeQuery("VALUES INSTR('The INSTR function returns "+ + "the starting position of the first occurrence "+ + "of one string within another string', "+ + "'f',1, 4, OCTETS)"); + while(rs.next()) + { + int instr1=rs.getInt(1); + System.out.println(instr1); + } + + + // Locate the second occurrence of "string" by searching from the + // end of the given string + + System.out.println("\nVALUES INSTR('The INSTR function returns the "+ + "starting position of the first occurrence of one "+ + "string within another string', "+ + "'string', -1, 2, OCTETS)"); + System.out.println("\n----------------------------------------------\n"); + + rs=stmt.executeQuery("VALUES INSTR('The INSTR function returns the "+ + "starting position of the first occurrence of one "+ + "string within another string', "+ + "'string', -1, 2, OCTETS)"); + + while(rs.next()) + { + int instr2=rs.getInt(1); + System.out.println(instr2); + } + + + rs.close(); + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try + { + con.rollback(); + } + catch (SQLException sql) + { + System.out.println("Error Msg: "+ sql.getMessage()); + System.out.println("SQLState: "+sql.getSQLState()); + System.out.println("SQLError: "+sql.getErrorCode()); + System.exit(1); + } + } +} // ToClob + +//Represent character string as a timestamp + +static void ToDate(Connection con) +{ + try + { + Date tdate; + + // Demonstrate different format elements of TO_DATE function + + Statement stmt0 = con.createStatement(); + // Insert data into temp_table + + stmt0.executeUpdate("INSERT INTO temp_table VALUES "+ + "(1,'1999-12-31 23:59:59', NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES "+ + "(1,'1999-12-31 23:59:59', NULL)\n"); + + System.out.println("\nSELECT TO_DATE(tempdata, 'YYYY-MM-DD HH24:MI:SS') "+ + "FROM temp_table"); + System.out.println("\n------------------------------------\n"); + + ResultSet rs0 = stmt0.executeQuery("SELECT "+ + "TO_DATE(tempdata, 'YYYY-MM-DD HH24:MI:SS') FROM temp_table"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + rs0.close(); + stmt0.close(); + + System.out.println("\nINSERT INTO temp_table VALUES "+ + "(2,'1999-12-31', 'YYYY-MM-DD')\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO temp_table VALUES (2,'1999-12-31',"+ + "'YYYY-MM-DD')"); + + System.out.println("\nSELECT TO_DATE(tempdata, format) "+ + "FROM temp_table WHERE rowno = 2"); + System.out.println("\n------------------------------------\n"); + + ResultSet rs = stmt.executeQuery("SELECT TO_DATE(tempdata, format) "+ + "FROM temp_table WHERE rowno = 2"); + + while (rs.next()) + { + tdate = rs.getDate(1); + System.out.println(tdate); + } + rs.close(); + stmt.close(); + + System.out.println("\nINSERT INTO temp_table VALUES (3,'1999-DEC-31',"+ + "NULL)"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("INSERT INTO temp_table VALUES (3,'1999-DEC-31',"+ + "NULL)"); + System.out.println("\nSELECT TO_DATE(tempdata, "+ + "'YYYY-MON-DD','CLDR 1.5:en_US' ) FROM temp_table WHERE rowno = 3"); + System.out.println("\n------------------------------------\n"); + + ResultSet rs1 = stmt1.executeQuery("SELECT TO_DATE(tempdata, "+ + "'YYYY-MON-DD','CLDR 1.5:en_US' ) FROM temp_table WHERE rowno = 3"); + + while (rs1.next()) + { + tdate = rs1.getDate(1); + System.out.println(tdate); + } + rs1.close(); + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try + { + con.rollback(); + } + catch (SQLException sql) + { + System.out.println("Error Msg: "+ sql.getMessage()); + System.out.println("SQLState: "+sql.getSQLState()); + System.out.println("SQLError: "+sql.getErrorCode()); + } + System.exit(1); + } + } // ToDate + +//Represent timestamp as a character string type + +static void ToChar(Connection con) +{ + try + { + String ttime; + + // Show tablename and its creation time as a String where tablename + // starts with 'empl' + + System.out.println("\n\nSELECT VARCHAR(TABNAME, 20) AS Table_Name, "+ + "TO_CHAR(CREATE_TIME, 'YYYY-MM-DD HH24:MI:SS') AS Creation_Time "+ + "FROM SYSCAT.TABLES WHERE TABNAME LIKE 'EMPL%'\n"); + System.out.println("\n------------------------------------\n"); + + Statement stmt0 = con.createStatement(); + ResultSet rs0 = stmt0.executeQuery("SELECT VARCHAR(TABNAME, 20) AS "+ + "Table_Name, TO_CHAR(CREATE_TIME, 'YYYY-MM-DD HH24:MI:SS') AS "+ + "Creation_Time FROM SYSCAT.TABLES WHERE TABNAME LIKE 'EMPL%'"); + + System.out.println("TableName \t" + "CreationTime"); + + while (rs0.next()) + { + String tabname = rs0.getString(1); + ttime = rs0.getString(2); + System.out.println(tabname + "\t" + ttime); + } + rs0.close(); + stmt0.close(); + + // Demonstrate different format elements of a DATE and a TIMESTAMP + // values with TO_CHAR function + + System.out.println("\nSELECT TO_CHAR( received ) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt2 = con.createStatement(); + ResultSet rs2 = stmt2.executeQuery("SELECT TO_CHAR( received ) "+ + "FROM in_tray"); + + while (rs2.next()) + { + ttime = rs2.getString(1); + System.out.println(ttime); + } + rs2.close(); + stmt2.close(); + + System.out.println("\nSELECT TO_CHAR( received,'FF9' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt3 = con.createStatement(); + ResultSet rs3 = stmt3.executeQuery("SELECT "+ + "TO_CHAR( received,'FF9' ) "+ + "FROM in_tray"); + + while (rs3.next()) + { + ttime = rs3.getString(1); + System.out.println(ttime); + } + rs3.close(); + stmt3.close(); + + System.out.println("\nSELECT TO_CHAR( received,'FF12' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt4 = con.createStatement(); + ResultSet rs4 = stmt4.executeQuery("SELECT "+ + "TO_CHAR( received,'FF12' ) "+ + "FROM in_tray"); + + while (rs4.next()) + { + ttime = rs4.getString(1); + System.out.println(ttime); + } + rs4.close(); + stmt4.close(); + + System.out.println("\nSELECT TO_CHAR( received,'MON', 'de_DE') "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt5 = con.createStatement(); + ResultSet rs5 = stmt5.executeQuery("SELECT "+ + "TO_CHAR( received,'MON', 'de_DE') "+ + "FROM in_tray"); + + while (rs5.next()) + { + ttime = rs5.getString(1); + System.out.println(ttime); + } + rs5.close(); + stmt5.close(); + + + System.out.println("\nSELECT TO_CHAR( received,'DD-YYYY-Month-Day' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt6 = con.createStatement(); + ResultSet rs6 = stmt6.executeQuery("SELECT "+ + "TO_CHAR( received,'DD-YYYY-Month-Day' ) "+ + "FROM in_tray"); + + while (rs6.next()) + { + ttime = rs6.getString(1); + System.out.println(ttime); + } + rs6.close(); + stmt6.close(); + + System.out.println("\nSELECT TO_CHAR( received,'DD-YYYY-MONTH-Day' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt7 = con.createStatement(); + ResultSet rs7 = stmt7.executeQuery("SELECT "+ + "TO_CHAR( received,'DD-YYYY-MONTH-Day' ) "+ + "FROM in_tray"); + + while (rs7.next()) + { + ttime = rs7.getString(1); + System.out.println(ttime); + } + rs7.close(); + stmt7.close(); + + System.out.println("\nSELECT TO_CHAR( received,'DD-YYYY-MONTH-DAY' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt8 = con.createStatement(); + ResultSet rs8 = stmt8.executeQuery("SELECT "+ + "TO_CHAR( received,'DD-YYYY-MONTH-DAY' ) "+ + "FROM in_tray"); + + while (rs8.next()) + { + ttime = rs8.getString(1); + System.out.println(ttime); + } + rs8.close(); + stmt8.close(); + + System.out.println("\nSELECT TO_CHAR( received,'YYYY-MONTH-DD' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt9 = con.createStatement(); + ResultSet rs9 = stmt9.executeQuery("SELECT "+ + "TO_CHAR( received,'YYYY-MONTH-DD' ) "+ + "FROM in_tray"); + + while (rs9.next()) + { + ttime = rs9.getString(1); + System.out.println(ttime); + } + rs9.close(); + stmt9.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'YYYY-Month-DAY-DD' ) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + + Statement stmt00 = con.createStatement(); + rs0 = stmt00.executeQuery("SELECT "+ + "TO_CHAR( received,'YYYY-Month-DAY-DD' ) "+ + "FROM in_tray"); + + while (rs0.next()) + { + ttime = rs0.getString(1); + System.out.println(ttime); + } + rs0.close(); + stmt00.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'DD-YYYY-mon-dy HH-MM-SS' ) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt18 = con.createStatement(); + ResultSet rs18 = stmt18.executeQuery("SELECT "+ + "TO_CHAR( received,'DD-YYYY-mon-dy HH-MM-SS' ) "+ + "FROM in_tray"); + + while (rs18.next()) + { + ttime = rs18.getString(1); + System.out.println(ttime); + } + rs18.close(); + stmt18.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'Dy-YYYY-MON-DD HH12-MM-SS' ) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt19 = con.createStatement(); + ResultSet rs19 = stmt19.executeQuery("SELECT "+ + "TO_CHAR( received,'Dy-YYYY-MON-DD HH12-MM-SS' ) FROM in_tray"); + + while (rs19.next()) + { + ttime = rs19.getString(1); + System.out.println(ttime); + } + rs19.close(); + stmt19.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'D-YYYY-Mon-DAY-DD HH12-MI-SS' ) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt20 = con.createStatement(); + ResultSet rs20 = stmt20.executeQuery("SELECT "+ + "TO_CHAR( received,'D-YYYY-Mon-DAY-DD HH12-MI-SS' ) FROM in_tray"); + + while (rs20.next()) + { + ttime = rs20.getString(1); + System.out.println(ttime); + } + rs20.close(); + stmt20.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'DAY-YYYY-Month-DD HH12-MM-SS' ) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt10 = con.createStatement(); + ResultSet rs10 = stmt10.executeQuery("SELECT "+ + "TO_CHAR( received,'DAY-YYYY-Month-DD HH12-MM-SS' ) FROM in_tray"); + + while (rs10.next()) + { + ttime = rs10.getString(1); + System.out.println(ttime); + } + rs10.close(); + stmt10.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'Day-YYYY-Month-DD HH24-MM-SS' ) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt11 = con.createStatement(); + ResultSet rs11 = stmt11.executeQuery("SELECT "+ + "TO_CHAR( received,'Day-YYYY-Month-DD HH24-MM-SS' ) FROM in_tray"); + + while (rs11.next()) + { + ttime = rs11.getString(1); + System.out.println(ttime); + } + rs11.close(); + stmt11.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'DAY-YYYY-Month-DD HH12-MM-SS PM' ) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt12 = con.createStatement(); + ResultSet rs12 = stmt12.executeQuery("SELECT "+ + "TO_CHAR( received,'DAY-YYYY-Month-DD HH12-MM-SS PM' ) FROM in_tray"); + + while (rs12.next()) + { + ttime = rs12.getString(1); + System.out.println(ttime); + } + rs12.close(); + stmt12.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'DD-YYYY-MONTH-DAY HH24-MM-SS P.M.' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt13 = con.createStatement(); + ResultSet rs13 = stmt13.executeQuery("SELECT "+ + "TO_CHAR( received,'DD-YYYY-MONTH-DAY HH24-MM-SS P.M.' ) "+ + "FROM in_tray"); + + while (rs13.next()) + { + ttime = rs13.getString(1); + System.out.println(ttime); + } + rs13.close(); + stmt13.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'DAY-YYYY-MONTH-DD HH12-MM-SS AM' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt14 = con.createStatement(); + ResultSet rs14 = stmt14.executeQuery("SELECT "+ + "TO_CHAR( received,'DAY-YYYY-MONTH-DD HH12-MM-SS AM' ) "+ + "FROM in_tray"); + + while (rs14.next()) + { + ttime = rs14.getString(1); + System.out.println(ttime); + } + rs14.close(); + stmt14.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'DD-YYYY-Month-day HH12-MM-SS A.M.' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt15 = con.createStatement(); + ResultSet rs15 = stmt15.executeQuery("SELECT "+ + "TO_CHAR( received,'DD-YYYY-Month-day HH12-MM-SS A.M.' ) "+ + "FROM in_tray"); + + while (rs15.next()) + { + ttime = rs15.getString(1); + System.out.println(ttime); + } + rs15.close(); + stmt15.close(); + + System.out.println("\nSELECT "+ + "TO_CHAR( received,'DD-YYYY/MON/DAY', 'en_US' ) "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt16 = con.createStatement(); + ResultSet rs16 = stmt16.executeQuery("SELECT "+ + "TO_CHAR( received,'DD-YYYY/MON/DAY', 'en_US' ) "+ + "FROM in_tray"); + + while (rs16.next()) + { + ttime = rs16.getString(1); + System.out.println(ttime); + } + rs16.close(); + + System.out.println("\nVALUES "+ + "VARCHAR_FORMAT('1988-12-22-14.07.21.136421', 'MON','de_DE')"); + System.out.println("\n-----------------------------------------\n"); + + rs16 = stmt16.executeQuery("VALUES "+ + "VARCHAR_FORMAT('1988-12-22-14.07.21.136421', 'MON','de_DE')"); + + while (rs16.next()) + { + ttime = rs16.getString(1); + System.out.println(ttime); + } + rs16.close(); + + System.out.println("\nVALUES "+ + "VARCHAR_FORMAT('1988-12-22-14.07.21.136421', 'MON','zh_CN')"); + System.out.println("\n-----------------------------------------\n"); + + rs16 = stmt16.executeQuery("VALUES "+ + "VARCHAR_FORMAT('1988-12-22-14.07.21.136421', 'MON','zh_CN')"); + + while (rs16.next()) + { + ttime = rs16.getString(1); + System.out.println(ttime); + } + rs16.close(); + + System.out.println("\nVALUES "+ + "VARCHAR_FORMAT('1988-12-22-14.07.21.136421', 'DAY','de_DE')"); + System.out.println("\n-----------------------------------------\n"); + + rs16 = stmt16.executeQuery("VALUES "+ + "VARCHAR_FORMAT('1988-12-22-14.07.21.136421', 'DAY','de_DE')"); + + while (rs16.next()) + { + ttime = rs16.getString(1); + System.out.println(ttime); + } + rs16.close(); + stmt16.close(); + + + // Get the month from the TIMESTAMP + System.out.println("\nSELECT TO_CHAR( received,'MONTH') "+ + "FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt1 = con.createStatement(); + ResultSet rs1 = stmt1.executeQuery("SELECT "+ + "TO_CHAR( received,'MONTH') from in_tray"); + + while (rs1.next()) + { + ttime = rs1.getString(1); + System.out.println(ttime); + } + rs1.close(); + stmt1.close(); + + // Get the day from the TIMESTAMP + System.out.println("\nSELECT TO_CHAR( received,'Dy') FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + Statement stmt17 = con.createStatement(); + ResultSet rs17 = stmt17.executeQuery("SELECT "+ + "TO_CHAR( received,'Dy') FROM in_tray"); + + while (rs17.next()) + { + ttime = rs17.getString(1); + System.out.println(ttime); + } + + + /*****************************************************************/ + /* DAYNAME */ + /*****************************************************************/ + String day; + + // Present dayname in the French locale + + System.out.println("\nSELECT DAYNAME(received, 'CLDR 1.5:fr_FR')"+ + " FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + rs17=stmt17.executeQuery("SELECT DAYNAME(received, 'CLDR 1.5:fr_FR')"+ + " FROM in_tray"); + while(rs17.next()) + { + day=rs17.getString(1); + System.out.println(day); + } + + // Present dayname in the Chinese locale + System.out.println("\nSELECT DAYNAME(received, 'CLDR 1.5:zh_CN')"+ + " FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + rs17=stmt17.executeQuery("SELECT DAYNAME(received, 'CLDR 1.5:zh_CN')"+ + " FROM in_tray"); + while(rs17.next()) + { + day=rs17.getString(1); + System.out.println(day); + } + + + // Present dayname in the Japanese locale + System.out.println("\nSELECT DAYNAME(received, 'CLDR 1.5:ja_JP')"+ + " FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + rs17=stmt17.executeQuery("SELECT DAYNAME(received, 'CLDR 1.5:ja_JP')" + + " FROM in_tray"); + while(rs17.next()) + { + day=rs17.getString(1); + System.out.println(day); + } + + + // Present dayname in the German locale + System.out.println("\nSELECT DAYNAME(received, 'CLDR 1.5:de_DE')"+ + " FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + rs17=stmt17.executeQuery("SELECT DAYNAME(received, 'CLDR 1.5:de_DE')"+ + " FROM in_tray"); + while(rs17.next()) + { + day=rs17.getString(1); + System.out.println(day); + } + + + + /*****************************************************************/ + /* MONTHNAME */ + /*****************************************************************/ + + // Present Monthname in the Spanish locale + System.out.println("\nSELECT MONTHNAME(received, 'CLDR 1.5:es_ES')"+ + " FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + rs17=stmt17.executeQuery("SELECT MONTHNAME(received, 'CLDR 1.5:es_ES')"+ + " FROM in_tray"); + while(rs17.next()) + { + day=rs17.getString(1); + System.out.println(day); + } + + + // Present Monthname in the Italian locale + System.out.println("\nSELECT MONTHNAME(received, 'CLDR 1.5:it_IT')"+ + " FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + rs17=stmt17.executeQuery("SELECT MONTHNAME(received, 'CLDR 1.5:it_IT')"+ + " FROM in_tray"); + while(rs17.next()) + { + day=rs17.getString(1); + System.out.println(day); + } + + + // Present Monthname in the Japanese locale + System.out.println("\nSELECT MONTHNAME(received, 'CLDR 1.5:ja_JP')"+ + " FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + rs17=stmt17.executeQuery("SELECT MONTHNAME(received, 'CLDR 1.5:ja_JP')"+ + " FROM in_tray"); + while(rs17.next()) + { + day=rs17.getString(1); + System.out.println(day); + } + + + // Present Monthname in the German locale + System.out.println("\nSELECT MONTHNAME(received, 'CLDR 1.5:de_DE')"+ + " FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + rs17=stmt17.executeQuery("SELECT MONTHNAME(received, 'CLDR 1.5:de_DE')"+ + " FROM in_tray"); + while(rs17.next()) + { + day=rs17.getString(1); + System.out.println(day); + } + + rs17.close(); + stmt17.close(); + + /*****************************************************************/ + /* CURRENT LOCALE LC_TIME */ + /* Use of CURRENT LOCALE LC_TIME with TO_CHAR Scalar Function. */ + /*****************************************************************/ + + // Use of the special register CURRENT LOCALE LC_TIME + + // Present a TIMESTAMP value in the French locale + + Statement stm=con.createStatement(); + stm.executeUpdate("SET CURRENT LOCALE LC_TIME = 'CLDR 1.5:fr_FR'"); + + System.out.println("\nSET CURRENT LOCALE LC_TIME = 'CLDR 1.5:fr_FR'\n"); + System.out.println("SELECT TO_CHAR(received) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + ResultSet rst=stm.executeQuery("SELECT TO_CHAR(received) FROM in_tray"); + + while (rst.next()) + { + ttime = rst.getString(1); + System.out.println(ttime); + } + + // Present a TIMESTAMP value in the Japanese locale + + stm.executeUpdate("SET CURRENT LOCALE LC_TIME = 'CLDR 1.5:ja_JP'"); + + System.out.println("\nSET CURRENT LOCALE LC_TIME = 'CLDR 1.5:ja_JP'\n"); + System.out.println("SELECT TO_CHAR(received) FROM in_tray\n"); + System.out.println("\n-----------------------------------------\n"); + + rst=stm.executeQuery("SELECT TO_CHAR(received) FROM in_tray"); + while (rst.next()) + { + ttime = rst.getString(1); + System.out.println(ttime); + } + + // Present a TIMESTAMP value in the Chinese locale + + stm.executeUpdate("SET CURRENT LOCALE LC_TIME = 'CLDR 1.5:zh_CN'"); + + System.out.println("\nSET CURRENT LOCALE LC_TIME = 'CLDR 1.5:zh_CN'\n"); + System.out.println("SELECT TO_CHAR(received) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + + rst=stm.executeQuery("SELECT TO_CHAR(received) FROM in_tray"); + + while (rst.next()) + { + ttime = rst.getString(1); + System.out.println(ttime); + } + + /*****************************************************************/ + /* CURRENT LOCALE LC_TIME */ + /* Use of CURRENT LOCALE LC_TIME with TO_DATE Scalar Function. */ + /*****************************************************************/ + // Present a DATE value in the French locale + + System.out.println("\nSET CURRENT LOCALE LC_TIME = 'CLDR 1.5:fr_FR'"); + + stm.executeUpdate("SET CURRENT LOCALE LC_TIME = 'CLDR 1.5:fr_FR'"); + + // Insert into temp_table + stm.executeUpdate("INSERT INTO temp_table VALUES "+ + "(5,'1999-D�C.-31', 'YYYY-MON-DD')"); + + System.out.println("\nINSERT INTO temp_table VALUES "+ + "(5,'1999-D�C.-31', 'YYYY-MON-DD')"); + System.out.println("\nSELECT TO_DATE(tempdata, format)FROM "+ + "temp_table WHERE rowno = 5"); + System.out.println("\n----------------------------------------\n"); + + rst=stm.executeQuery("SELECT TO_DATE(tempdata, format)FROM "+ + "temp_table WHERE rowno = 5"); + + while (rst.next()) + { + ttime = rst.getString(1); + System.out.println(ttime); + } + + + + // Present a DATE value in the English locale + + stm.executeUpdate("SET CURRENT LOCALE LC_TIME = 'CLDR 1.5:en_US'"); + + // Insert into temp_table + stm.executeUpdate("INSERT INTO temp_table VALUES "+ + "(4,'1999-DEC-31', 'YYYY-MON-DD')"); + + System.out.println("\nSET CURRENT LOCALE LC_TIME = 'CLDR 1.5:en_US'"); + System.out.println("\nINSERT INTO temp_table VALUES "+ + "(4,'1999-DEC-31', 'YYYY-MON-DD')"); + System.out.println("\nSELECT TO_DATE(tempdata, format)FROM "+ + "temp_table WHERE rowno = 4"); + System.out.println("\n-----------------------------------------\n"); + + rst=stm.executeQuery("SELECT TO_DATE(tempdata, format)FROM "+ + "temp_table WHERE rowno = 4"); + while (rst.next()) + { + ttime = rst.getString(1); + System.out.println(ttime); + } + + /*****************************************************************/ + /* CURRENT LOCALE LC_TIME */ + /* Use of CURRENT LOCALE LC_TIME with DAYNAME Scalar Function */ + /* MONTHNAME Scalar Function. */ + /*****************************************************************/ + + // Present a Dayname in the French locale + String dayname; + // SET CURRENT LOCALE + System.out.println("\nSET CURRENT LOCALE LC_TIME = 'CLDR 1.5:fr_FR'\n"); + stm.executeUpdate("SET CURRENT LOCALE LC_TIME = 'CLDR 1.5:fr_FR'"); + System.out.println("\nSELECT DAYNAME(received) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + rst=stm.executeQuery("SELECT DAYNAME(received) FROM in_tray"); + while (rst.next()) + { + dayname = rst.getString(1); + System.out.println(dayname); + } + + + // Present Dayname in the Italian locale + + // SET CURRENT LOCALE + System.out.println("\nSET CURRENT LOCALE LC_TIME = 'CLDR 1.5:it_IT'\n"); + stm.executeUpdate("SET CURRENT LOCALE LC_TIME = 'CLDR 1.5:it_IT'"); + System.out.println("\nSELECT DAYNAME(received) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + rst=stm.executeQuery("SELECT DAYNAME(received) FROM in_tray"); + while (rst.next()) + { + dayname = rst.getString(1); + System.out.println(dayname); + } + + // Returns a character string containing the name of the MONTH for the + // month portion of expression based on the value of LOCALE LC_TIME + + // Present Monthname in the Spanish locale + + // SET CURRENT LOCALE + System.out.println("\nSET CURRENT LOCALE LC_TIME = 'CLDR 1.5:es_ES'\n"); + stm.executeUpdate("SET CURRENT LOCALE LC_TIME = 'CLDR 1.5:es_ES'"); + System.out.println("\nSELECT MONTHNAME(received) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + rst=stm.executeQuery("SELECT MONTHNAME(received) FROM in_tray"); + while (rst.next()) + { + dayname = rst.getString(1); + System.out.println(dayname); + } + + // Present Monthname in the German locale + + // SET CURRENT LOCALE + System.out.println("\nSET CURRENT LOCALE LC_TIME = 'CLDR 1.5:de_DE'\n"); + stm.executeUpdate("SET CURRENT LOCALE LC_TIME = 'CLDR 1.5:de_DE'"); + System.out.println("\nSELECT MONTHNAME(received) FROM in_tray"); + System.out.println("\n-----------------------------------------\n"); + rst=stm.executeQuery("SELECT MONTHNAME(received) FROM in_tray"); + while (rst.next()) + { + dayname = rst.getString(1); + System.out.println(dayname); + } + + /*****************************************************************/ + /* LAST_DAY */ + /*****************************************************************/ + + // Present last day of the month indicated by expression + System.out.println("\n VALUES CURRENT DATE\n"); + System.out.println("\n-----------------------------------------\n"); + + Date tempdate; + + rst=stm.executeQuery("VALUES CURRENT DATE"); + while (rst.next()) + { + tempdate = rst.getDate(1); + System.out.println(tempdate); + } + + System.out.println("\n VALUES LAST_DAY(CURRENT DATE)\n"); + System.out.println("\n-----------------------------------------\n"); + + rst=stm.executeQuery("VALUES LAST_DAY(CURRENT DATE)"); + while (rst.next()) + { + tempdate = rst.getDate(1); + System.out.println(tempdate); + } + + System.out.println("\n SELECT LAST_DAY(DATE(received)) AS lastday FROM in_tray\n"); + System.out.println("\n-----------------------------------------\n"); + + rst=stm.executeQuery("SELECT LAST_DAY(DATE(received)) AS lastday FROM in_tray"); + while (rst.next()) + { + tempdate = rst.getDate(1); + System.out.println(tempdate); + } + + + /*****************************************************************/ + /* ADD_MONTHS */ + /*****************************************************************/ + + // Add number of months in given expression + + // Add 6 months in CURRENT DATE + // Present last day of the month indicated by expression + System.out.println("\n VALUES CURRENT DATE\n"); + System.out.println("\n-----------------------------------------\n"); + + rst=stm.executeQuery("VALUES CURRENT DATE"); + while (rst.next()) + { + tempdate = rst.getDate(1); + System.out.println(tempdate); + } + + System.out.println("\n VALUES ADD_MONTHS(CURRENT DATE, 6)\n"); + System.out.println("\n-----------------------------------------\n"); + + rst=stm.executeQuery("VALUES ADD_MONTHS(CURRENT DATE, 6)"); + while (rst.next()) + { + tempdate = rst.getDate(1); + System.out.println(tempdate); + } + + // Add 5 months + System.out.println("\n SELECT ADD_MONTHS(received, 5) AS new_received FROM in_tray\n"); + System.out.println("\n-----------------------------------------\n"); + + rst=stm.executeQuery("SELECT ADD_MONTHS(received, 5) AS new_received FROM in_tray"); + while (rst.next()) + { + tempdate = rst.getDate(1); + System.out.println(tempdate); + } + + stm.close(); + rst.close(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try + { + con.rollback(); + } + catch (Exception e) + { + System.out.println("Error"+e); + } + System.exit(1); + } +} // ToChar + +// Show string value in DECFLOAT type format. + +static void ToNumber(Connection con) +{ + try + { + float tnumber; + + // Each 9 in the format element represents a digit. + + System.out.println("\nSELECT TO_NUMBER(EmpNo, '999999') "+ + "AS EmpNo FROM Employee\n"); + System.out.println("\n----------------------------------------\n"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT TO_NUMBER(EmpNo, '999999') "+ + "AS EmpNo FROM Employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\nSELECT TO_NUMBER(EmpNo, '000000') AS "+ + "EmpNo FROM employee\n"); + System.out.println("\n-----------------------------------------\n"); + + rs = stmt.executeQuery("SELECT TO_NUMBER(EmpNo, '000000') AS "+ + "EmpNo FROM employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + // TRUNCATE all data from table temp_table + + con.commit(); + stmt.executeUpdate("TRUNCATE TABLE temp_table IMMEDIATE"); + System.out.println("\n--------------------------------------\n"); + + System.out.println("Table Truncated...."); + System.out.println("\n---------------------------------------\n"); + + + // INSERT new data into table temp_table + + System.out.println("\nINSERT INTO temp_table VALUES (1,'123.45',NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (1,'123.45',NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (2,'-123456.78'"+ + " ,NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (2,'-123456.78',NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (3,'+123456.78'," + + "NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (3,'+123456.78',NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (4,'1.23E4',NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (4,'1.23E4',NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (5,'001,234',NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (5,'001,234',NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (6,'1234',NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (6,'1234',NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (7,'1234-',NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (7,'1234-',NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (8,'+1234',NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (8,'+1234',NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (9,'<1234>',NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (9,'<1234>',NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (10,'123,456.78-',"+ + "NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (10,'123,456.78-',"+ + "NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (11,'<123,456.78>',"+ + "NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (11,'<123,456.78>',"+ + "NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (12,'$123,456.78',"+ + "NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (12,'$123,456.78',"+ + "NULL)"); + + System.out.println("\nINSERT INTO temp_table VALUES (13,'+123,456.78',"+ + "NULL)"); + stmt.executeUpdate("INSERT INTO temp_table VALUES (13,'+123,456.78',"+ + "NULL)"); + + // List rows from table temp_table + + System.out.println("\nSELECT * FROM temp_table\n\n"); + System.out.println("---------------------------------------------------"); + + System.out.println("ROWNO \t TEMPDATA \t \t FORMAT\n"); + System.out.println("---------------------------------------------------"); + + rs=stmt.executeQuery("SELECT * FROM temp_table"); + while(rs.next()) + { + System.out.print("\n"+rs.getInt(1)+" \t "); + System.out.print(rs.getString(2)+" \t\t "); + System.out.print(rs.getString(3)+"\n"); + } + + rs.close(); + stmt.close(); + + // MI in the format element is to represent the sign of the string + // If it is a negative number, a trailing minus sign (-) is expected. + // If it is a positive number, an optional trailing space is expected. + + System.out.println("\n\nSELECT TO_NUMBER(tempdata)FROM "+ + "temp_table WHERE rowno = 1"); + System.out.println("\n----------------------------\n"); + + Statement stmt1=con.createStatement(); + ResultSet rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata)FROM "+ + "temp_table WHERE rowno = 1"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata)FROM temp_table "+ + "WHERE rowno = 2"); + System.out.println("\n----------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata)FROM temp_table "+ + "WHERE rowno = 2"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata)FROM temp_table "+ + "WHERE rowno = 3"); + System.out.println("\n-----------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata)FROM temp_table "+ + "WHERE rowno = 3"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata)FROM temp_table "+ + "WHERE rowno = 4"); + System.out.println("\n-----------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata)FROM temp_table "+ + "WHERE rowno = 4"); + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'000,000')FROM "+ + "temp_table WHERE rowno = 5"); + System.out.println("\n------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'000,000')FROM "+ + "temp_table WHERE rowno = 5"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'9999.99')FROM "+ + "temp_table WHERE rowno = 1"); + System.out.println("\n-------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'9999.99')FROM "+ + "temp_table WHERE rowno = 1"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'9999MI')FROM "+ + "temp_table WHERE rowno = 6"); + System.out.println("\n--------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'9999MI')FROM "+ + "temp_table WHERE rowno = 6"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'9999MI')FROM "+ + "temp_table WHERE rowno = 7"); + System.out.println("\n--------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'9999MI')FROM "+ + "temp_table WHERE rowno = 7"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'999999MI')FROM "+ + "temp_table WHERE rowno = 6"); + System.out.println("\n--------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'999999MI')FROM "+ + "temp_table WHERE rowno = 6"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'S9999')FROM "+ + "temp_table WHERE rowno = 8"); + System.out.println("\n----------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'S9999')FROM "+ + "temp_table WHERE rowno = 8"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'9999PR')FROM "+ + "temp_table WHERE rowno = 6"); + System.out.println("\n-----------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'9999PR')FROM "+ + "temp_table WHERE rowno = 6"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'9999PR')FROM "+ + "temp_table WHERE rowno = 9"); + System.out.println("\n------------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'9999PR')FROM "+ + "temp_table WHERE rowno = 9"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'000,000.00MI')FROM "+ + "temp_table WHERE rowno = 10"); + System.out.println("\n--------------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'000,000.00MI')FROM "+ + "temp_table WHERE rowno = 10"); + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'000,000.00PR')FROM "+ + "temp_table WHERE rowno = 11"); + System.out.println("\n--------------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'000,000.00PR')FROM "+ + "temp_table WHERE rowno = 11"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'$999,999.99')FROM "+ + "temp_table WHERE rowno = 12"); + System.out.println("\n---------------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'$999,999.99')FROM "+ + "temp_table WHERE rowno = 12"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'$S000,000.00')FROM "+ + "temp_table WHERE rowno = 12"); + System.out.println("\n--------------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'$S000,000.00')FROM "+ + "temp_table WHERE rowno = 12"); + + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + System.out.println("\n\nSELECT TO_NUMBER(tempdata,'S000,000.00')FROM "+ + "temp_table WHERE rowno = 13"); + System.out.println("\n--------------------------------------\n"); + + rs1=stmt1.executeQuery("SELECT TO_NUMBER(tempdata,'S000,000.00')FROM "+ + "temp_table WHERE rowno = 13"); + while (rs1.next()) + { + tnumber = rs1.getFloat(1); + System.out.println(tnumber); + } + + rs1.close(); + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try + { + con.rollback(); + } + catch (SQLException sql) + { + System.out.println("Error Msg: "+ sql.getMessage()); + System.out.println("SQLState: "+sql.getSQLState()); + System.out.println("SQLError: "+sql.getErrorCode()); + } + System.exit(1); + } + } // ToNumber + +static void UseRound(Connection con) +{ + try + { + float tnumber; + + /*****************************************************************/ + /* ROUND numeric value */ + /*****************************************************************/ + + // Select average salary + System.out.println("\nSELECT AVG(SALARY) FROM employee\n"); + System.out.println("\n----------------------------------------\n"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT AVG(SALARY) FROM employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + // Select average salary rounded 5 places to the right of the + // decimal point + System.out.println("\nSELECT ROUND((AVG(SALARY)), 5) "+ + " FROM employee\n"); + System.out.println("\n-----------------------------------------\n"); + + rs = stmt.executeQuery("SELECT ROUND((AVG(SALARY)), 5) "+ + "FROM employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + // Select average salary rounded 0 places to the right of the + // decimal point + System.out.println("\nSELECT ROUND((AVG(SALARY)), 0) FROM employee\n"); + System.out.println("\n----------------------------------------\n"); + + rs = stmt.executeQuery("SELECT ROUND((AVG(SALARY)), 0) FROM employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + // Select average salary rounded -2 places to the right of the + // decimal point + System.out.println("\nSELECT ROUND((AVG(SALARY)), -2) "+ + " FROM employee\n"); + System.out.println("\n-----------------------------------------\n"); + + rs = stmt.executeQuery("SELECT ROUND((AVG(SALARY)), -2) "+ + "FROM employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + rs.close(); + stmt.close(); + + + /*****************************************************************/ + /* ROUND datetime value */ + /*****************************************************************/ + + // Round DATE and TIME value on the basis of format string + Date tdate; + Time ttime; + + System.out.println("\nSELECT DATE(received) FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + Statement stmt0 = con.createStatement(); + ResultSet rs0 = stmt0.executeQuery("SELECT DATE(received) FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + + System.out.println("\nSELECT ROUND(DATE(received), 'MON') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT ROUND(DATE(received), 'MON') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + + System.out.println("\nSELECT ROUND(DATE(received), 'D') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT ROUND(DATE(received), 'D') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + System.out.println("\nSELECT ROUND(DATE(received), 'Y') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT ROUND(DATE(received), 'Y') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + System.out.println("\nSELECT ROUND(DATE(received), 'WW') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT ROUND(DATE(received), 'WW') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + System.out.println("\nSELECT TIME(received) FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TIME(received) FROM in_tray"); + + while (rs0.next()) + { + ttime = rs0.getTime(1); + System.out.println(ttime); + } + + + System.out.println("\nSELECT ROUND(TIME(received), 'HH') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT ROUND(TIME(received), 'HH') FROM in_tray"); + + while (rs0.next()) + { + ttime = rs0.getTime(1); + System.out.println(ttime); + } + + + System.out.println("\nSELECT ROUND(TIME(received), 'MI') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT ROUND(TIME(received), 'MI') FROM in_tray"); + + while (rs0.next()) + { + ttime = rs0.getTime(1); + System.out.println(ttime); + } + + // ROUND DATE value on the basis of format string and locale + + System.out.println("\nSELECT ROUND(DATE(received), 'DAY', 'zh_CN') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT ROUND(DATE(received), 'DAY', 'zh_CN') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + System.out.println("\nSELECT ROUND(DATE(received), 'D', 'fr_FR') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT ROUND(DATE(received), 'D', 'fr_FR') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + rs0.close(); + stmt0.close(); + + + /*****************************************************************/ + /* ROUND_TIMESTAMP datetime value */ + /*****************************************************************/ + + // ROUND character string on the basis of format string + + Timestamp ttimestamp; + + System.out.println("\nVALUES ROUND_TIMESTAMP('1988-12-22-14.07.21.136421', 'HH')"); + System.out.println("\n------------------------------------\n"); + + Statement stmt1 = con.createStatement(); + ResultSet rs1 = stmt1.executeQuery("VALUES ROUND_TIMESTAMP('1988-12-22-14.07.21.136421', 'HH')"); + + while (rs1.next()) + { + ttimestamp = rs1.getTimestamp(1); + System.out.println(ttimestamp); + } + + + System.out.println("\nVALUES ROUND_TIMESTAMP('1988-12-22-14.07.21.136421', 'MM')"); + System.out.println("\n------------------------------------\n"); + + rs1 = stmt1.executeQuery("VALUES ROUND_TIMESTAMP('1988-12-22-14.07.21.136421', 'MM')"); + + while (rs1.next()) + { + ttimestamp = rs1.getTimestamp(1); + System.out.println(ttimestamp); + } + + rs1.close(); + stmt1.close(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try + { + con.rollback(); + } + catch (SQLException sql) + { + System.out.println("Error Msg: "+ sql.getMessage()); + System.out.println("SQLState: "+sql.getSQLState()); + System.out.println("SQLError: "+sql.getErrorCode()); + } + System.exit(1); + } + } // UseRound + +static void UseTruncate(Connection con) +{ + try + { + float tnumber; + + /*****************************************************************/ + /* TRUNC or TRUNCATE numeric value */ + /*****************************************************************/ + + // Select average salary from employee table + System.out.println("\nSELECT AVG(SALARY) FROM employee\n"); + System.out.println("\n----------------------------------------\n"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT AVG(SALARY) FROM employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + // Select average salary truncated 5 places to the right of the + // decimal point + System.out.println("\nSELECT TRUNCATE((AVG(SALARY)), 5) "+ + " FROM employee\n"); + System.out.println("\n-----------------------------------------\n"); + + rs = stmt.executeQuery("SELECT TRUNCATE((AVG(SALARY)), 5) "+ + "FROM employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + // Select average salary truncated 0 places to the right of the + // decimal point + System.out.println("\nSELECT TRUNCATE((AVG(SALARY)), 0) FROM employee\n"); + System.out.println("\n----------------------------------------\n"); + + rs = stmt.executeQuery("SELECT TRUNCATE((AVG(SALARY))) FROM employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + // Select average salary truncated -2 places to the right of the + // decimal point + System.out.println("\nSELECT TRUNCATE((AVG(SALARY)), -2) "+ + " FROM employee\n"); + System.out.println("\n-----------------------------------------\n"); + + rs = stmt.executeQuery("SELECT TRUNCATE((AVG(SALARY)), -2) "+ + "FROM employee"); + + while (rs.next()) + { + tnumber = rs.getFloat(1); + System.out.println(tnumber); + } + + rs.close(); + stmt.close(); + + + /*****************************************************************/ + /* TRUNC or TRUNCATE datetime value */ + /*****************************************************************/ + + // TRUNCATE DATE and TIME value on the basis of format string + Date tdate; + Time ttime; + + // Select rows from in_tray table + System.out.println("\nSELECT received FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + Statement stmt0 = con.createStatement(); + ResultSet rs0 = stmt0.executeQuery("SELECT received FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + + System.out.println("\nSELECT TRUNC(DATE(received), 'MONTH') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNC(DATE(received), 'MONTH') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + + System.out.println("\nSELECT TRUNCATE(DATE(received), 'DAY') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNCATE(DATE(received), 'DAY') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + System.out.println("\nSELECT TRUNCATE(DATE(received), 'YEAR') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNCATE(DATE(received), 'YEAR') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + System.out.println("\nSELECT TRUNC(DATE(received), 'CC') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNC(DATE(received), 'CC') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + System.out.println("\nSELECT TRUNC(DATE(received), 'Q') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNC(DATE(received), 'Q') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + System.out.println("\nSELECT TRUNCATE(DATE(received), 'I') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNCATE(DATE(received), 'I') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + + + System.out.println("\nSELECT TRUNC(TIME(received), 'HH') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNC(TIME(received), 'HH') FROM in_tray"); + + while (rs0.next()) + { + ttime = rs0.getTime(1); + System.out.println(ttime); + } + + + System.out.println("\nSELECT TRUNC(TIME(received), 'MI') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNC(TIME(received), 'MI') FROM in_tray"); + + while (rs0.next()) + { + ttime = rs0.getTime(1); + System.out.println(ttime); + } + + + System.out.println("\nSELECT TRUNC(TIME(received), 'SS') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNC(TIME(received), 'SS') FROM in_tray"); + + while (rs0.next()) + { + ttime = rs0.getTime(1); + System.out.println(ttime); + } + + // TRUNCATE DATE value on the basis of format string and locale + + System.out.println("\nSELECT TRUNCATE(DATE(received), 'DAY', 'ja_JP') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNCATE(DATE(received), 'DAY', 'ja_JP') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + System.out.println("\nSELECT TRUNCATE(DATE(received), 'D', 'fr_FR') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs0 = stmt0.executeQuery("SELECT TRUNCATE(DATE(received), 'D', 'fr_FR') FROM in_tray"); + + while (rs0.next()) + { + tdate = rs0.getDate(1); + System.out.println(tdate); + } + + rs0.close(); + stmt0.close(); + + + /*****************************************************************/ + /* TRUNC_TIMESTAMP datetime value */ + /*****************************************************************/ + + // Truncate character string on the basis of format string + + Timestamp ttimestamp; + + System.out.println("\nVALUES TRUNC_TIMESTAMP('1988-12-22-14.07.21.136421', 'MONTH')"); + System.out.println("\n------------------------------------\n"); + + Statement stmt1 = con.createStatement(); + ResultSet rs1 = stmt1.executeQuery("VALUES TRUNC_TIMESTAMP('1988-12-22-14.07.21.136421', 'MONTH')"); + + while (rs1.next()) + { + ttimestamp = rs1.getTimestamp(1); + System.out.println(ttimestamp); + } + + + System.out.println("\nVALUES TRUNC_TIMESTAMP('1988-12-25-17.12.30.000000', 'YEAR')"); + System.out.println("\n------------------------------------\n"); + + rs1 = stmt1.executeQuery("VALUES TRUNC_TIMESTAMP('1988-12-25-17.12.30.000000', 'YEAR')"); + + while (rs1.next()) + { + ttimestamp = rs1.getTimestamp(1); + System.out.println(ttimestamp); + } + + System.out.println("\nSELECT TRUNC_TIMESTAMP(received, 'D') FROM in_tray"); + System.out.println("\n------------------------------------\n"); + + rs1 = stmt1.executeQuery("SELECT TRUNC_TIMESTAMP(received, 'D') FROM in_tray"); + + while (rs1.next()) + { + ttimestamp = rs1.getTimestamp(1); + System.out.println(ttimestamp); + } + + + System.out.println("\nVALUES TRUNC_TIMESTAMP('1988-12-25', 'CC')"); + System.out.println("\n------------------------------------\n"); + + rs1 = stmt1.executeQuery("VALUES TRUNC_TIMESTAMP('1988-12-25', 'CC')"); + + while (rs1.next()) + { + ttimestamp = rs1.getTimestamp(1); + System.out.println(ttimestamp); + } + + + System.out.println("\nVALUES TRUNC_TIMESTAMP('1988-12-23', 'Q')"); + System.out.println("\n------------------------------------\n"); + + rs1 = stmt1.executeQuery("VALUES TRUNC_TIMESTAMP('1988-12-23', 'Q')"); + + while (rs1.next()) + { + ttimestamp = rs1.getTimestamp(1); + System.out.println(ttimestamp); + } + + + System.out.println("\nVALUES TRUNC_TIMESTAMP('1988-12-25-17.12.30.000000', 'I')"); + System.out.println("\n------------------------------------\n"); + + rs1 = stmt1.executeQuery("VALUES TRUNC_TIMESTAMP('1988-12-25-17.12.30.000000', 'I')"); + + while (rs1.next()) + { + ttimestamp = rs1.getTimestamp(1); + System.out.println(ttimestamp); + } + + + System.out.println("\nVALUES TRUNC_TIMESTAMP('1988-12-22-14.07.21.136421', 'DAY', 'es_ES')"); + System.out.println("\n------------------------------------\n"); + + rs1 = stmt1.executeQuery("VALUES TRUNC_TIMESTAMP('1988-12-22-14.07.21.136421', 'DAY', 'es_ES')"); + + while (rs1.next()) + { + ttimestamp = rs1.getTimestamp(1); + System.out.println(ttimestamp); + } + + rs1.close(); + stmt1.close(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try + { + con.rollback(); + } + catch (SQLException sql) + { + System.out.println("Error Msg: "+ sql.getMessage()); + System.out.println("SQLState: "+sql.getSQLState()); + System.out.println("SQLError: "+sql.getErrorCode()); + } + System.exit(1); + } + } // UseTruncate + +//Drop table temp_table + +static void DropTable(Connection con) +{ + try + { + String st="DROP TABLE temp_table"; + Statement stmt = con.createStatement(); + stmt.executeUpdate(st); + System.out.println("\n\nDrop table temp_table; \n"); + con.commit(); + db.disconnect(); + } + catch(Exception e) + { + System.out.println("Unable to drop table....."); + } + } //DropTable + +} // ScalarFunctions + diff --git a/java/jdbc/SetIntegrity.java b/java/jdbc/SetIntegrity.java new file mode 100644 index 0000000..9299006 --- /dev/null +++ b/java/jdbc/SetIntegrity.java @@ -0,0 +1,1180 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: SetIntegrity.java +// +// SAMPLE: How to perform online SET INTEGRITY on a table. +// +// This sample: +// 1. Availability of table during SET INTEGRITY after LOAD utility. +// 2. Availability of table during set INTEGRITY after adding a new +// partition is added to the table via the ALTER ATTACH. +// 3. Shows how SET INTEGRITY statement will generate the proper +// values for both generated columns and identity values whenever +// a partition which violates the constraint is attached a data +// partitioned table. +// +// This sample should be run using the following steps: +// 1.Compile the program with the following command: +// javac SetIntegrity.java Util.java +// +// 2.The sample should be run using the following command +// java SetIntegrity +// The fenced user id must be able to create or overwrite files in +// the directory specified.This directory must +// be a full path on the server. The dummy file 'dummy.del' must +// exist before the sample is run. +// +// SQL Statements USED: +// ALTER TABLE +// CREATE TABLE +// DROP TABLE +// EXPORT +// IMPORT +// INSERT +// LOAD +// SELECT +// SET INTEGRITY +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// OUTPUT FILE: SetIntegrity.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//************************************************************************** + +import java.lang.*; +import java.sql.*; + +class SetIntegrity +{ + public static void main(String argv[]) + { + if (argv.length < 1) + { + System.out.println("\n Usage : java SetIntegrity" + + " "); + } + else + { + try + { + Connection con = null; + String path = argv[0]; + + // initialize DB2Driver and establish database connection. + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + System.out.println( + "\nTHIS SAMPLE SHOWS HOW TO PERFORM SET INTEGRITY ON A TABLE."); + + // creates regular DMS tablespaces + dmstspaceCreate(con); + + System.out.println( + "****************************************************"+ + "\nTHE FOLLOWING SCENARIO SHOWS THE AVAILABILITY OF\n " + + " TABLE DURING SET INTEGRITY AFTER LOAD UTILITY\n" + + "*****************************************************"); + + // creates a partitioned table + partitionedTbCreate(con, path); + + System.out.println( + "*****************************************************"+ + "\nTHE FOLLOWING SCENARIO SHOWS THE AVAILABILITY OF " + + "\n TABLE DURING SET INTEGRITY ALONG WITH GENERATE" + + "\n IDENTITY CLAUSE AFTER LAOD\n" + + "*****************************************************\n"); + + // create a temporary table + createtb_Temp(con, path); + createptb_Temp(con, path); + + System.out.println( + "\n*******************************************************"+ + "\nTHE FOLLOWING SCENARIO SHOWS THE AVAILABILITY OF " + + "\n TABLE DURING SET INTEGRITY AFTER ATTACH via ALTER" + + "\n*****************************************************"); + + // alter a table + alterTable(con, path); + + // drop tablespaces + tablespacesDrop(con); + + // disconnect from the 'sample' database + con.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } + } // main + + // creates regular DMS tablespaces + static void dmstspaceCreate(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " CREATE REGULAR TABLESPACE \n" + + "TO CREATE A REGULAR TABLESPACE \n" + + "\nExecute the statement:\n" + + " CREATE REGULAR TABLESPACE dms_tspace"); + + // create regular DMS table space dms_tspace + Statement stmt = con.createStatement(); + String str = ""; + str = "CREATE REGULAR TABLESPACE dms_tspace"; + stmt.executeUpdate(str); + + System.out.println( + "Execute the statement:\n" + + "CREATE REGULAR TABLESPACE dms_tspace1"); + + // create regular DMS table space dms_tspace1 + str = "CREATE REGULAR TABLESPACE dms_tspace1"; + stmt.executeUpdate(str); + + System.out.println( + "Execute the statement:\n" + + "CREATE REGULAR TABLESPACE dms_tspace2"); + + // create regular DMS table space dms_tspace2 + str = "CREATE REGULAR TABLESPACE dms_tspace2"; + stmt.executeUpdate(str); + + System.out.println( + "Execute the statement:\n" + + "CREATE REGULAR TABLESPACE dms_tspace3"); + + // create regular DMS table space dms_tspace3 + str = "CREATE REGULAR TABLESPACE dms_tspace3"; + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // dmstspaceCreate + + // creates a partitioned table with 'part1' in 'dms_tspace1', 'part2' in + // 'dms_tspace2', and 'part3' in 'dms_tspace3' and inserts data into the + // table. The function also shows how SET INTEGRITY can be performed on + // a partitioned table. + static void partitionedTbCreate(Connection con, String path) + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE TABLE \n" + + "TO CREATE A PARTITIONED TABLE \n" + + "\nExecute the statement:\n" + + " CREATE TABLE fact_table (max INTEGER NOT NULL,\n" + + " CONSTRAINT CC CHECK (max>0))\n" + + " PARTITION BY RANGE (max)\n "+ + " (PART part1 STARTING FROM (-1) ENDING (3) IN dms_tspace1,\n" + + " PART part2 STARTING FROM (4) ENDING (6) IN dms_tspace2,\n" + + " PART part3 STARTING FROM (7) ENDING (9) IN dms_tspace3)"); + + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "CREATE TABLE fact_table "; + str = str + "(max INTEGER NOT NULL, CONSTRAINT CC CHECK (max>0))"; + str = str + " PARTITION BY RANGE (max) "; + str = str + "(PART part1 STARTING FROM (-1) ENDING (3) "; + str = str + "IN dms_tspace1, PART part2 STARTING FROM (4) ENDING (6) "; + str = str + "IN dms_tspace2, PART part3 STARTING FROM (7) ENDING (9) "; + str = str + "IN dms_tspace3)"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " INSERT INTO \n" + + "TO INSERT DATA IN A TABLE \n" + + "\nExecute the statement:\n" + + " INSERT INTO fact_table VALUES (1), (2), (3)"); + + // insert data into the table + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "INSERT INTO fact_table VALUES (1), (2), (3)"; + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n"); + + // create a temporary table + System.out.println( + "Execute the statements:\n" + + "CREATE TABLE temp_table (max INT)\n "); + + stmt = con.createStatement(); + str = ""; + + str = "CREATE TABLE temp_table (max INT)"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + System.out.println( + "INSERT INTO temp_table VALUES(4), (5), (6), (7), (0), (-1)"); + + stmt = con.createStatement(); + str = ""; + + str = "INSERT INTO temp_table VALUES(4), (5), (6), (7), (0), (-1)"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + // export data to temporary table + exportData(con, path); + + // load data from temporary table into base table + loadData(con, path); + + // create temporary table to hold exceptions thrown by SET INTEGRITY + // statement. + + System.out.println( + "\nExecute the statement:\n" + + "CREATE TABLE fact_exception (max INTEGER NOT NULL)"); + + stmt = con.createStatement(); + str = ""; + + str = str + "CREATE TABLE fact_exception (max INTEGER NOT NULL)"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " SET INTEGRITY\n" + + "TO TABLE OUT OF CHECK PENDING STATE:\n"); + + System.out.println( + "Execute the statement:" + + "SET INTEGRITY FOR fact_table ALLOW READ ACCESS\n" + + " IMMEDIATE CHECKED FOR EXCEPTION IN fact_table\n" + + " USE fact_exception"); + + stmt = con.createStatement(); + str = ""; + + str =str + "SET INTEGRITY FOR fact_table ALLOW READ ACCESS"; + str =str + " IMMEDIATE CHECKED FOR EXCEPTION IN fact_table"; + str =str + " USE fact_exception"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the contents of 'fact_table'. + try + { + int max = 0; + + System.out.println( + "---------------------------------------------------------\n"); + System.out.println(" SELECT * FROM fact_table"); + System.out.println( + " MAX\n" + + " ------"); + + Statement stmt = con.createStatement(); + // perform a SELECT against the "fact_table" table. + ResultSet rs = stmt.executeQuery("SELECT * FROM fact_table"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + max = rs.getInt(1); + + System.out.println( + " " + + Data.format(max, 3)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the contents of exception table. + + try + { + int max = 0; + + System.out.println(); + System.out.println(" SELECT * FROM fact_exception"); + System.out.println( + " MAX\n" + + " ------"); + + Statement stmt = con.createStatement(); + // perform a SELECT against the "fact_exception" table. + ResultSet rs1 = stmt.executeQuery("SELECT * FROM fact_exception"); + + // retrieve and display the result from the SELECT statement + while (rs1.next()) + { + max = rs1.getInt(1); + + System.out.println( + " " + + Data.format(max, 3)); + } + rs1.close(); + stmt.close(); + System.out.println( + "-----------------------------------------------------------"); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop the tables + try + { + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " DROP \n" + + "TO DROP THE TABLES \n" ); + + System.out.println( + "Execute the statement:\n" + + "DROP TABLE temp_table\n"); + + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "DROP TABLE temp_table"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + System.out.println( + "DROP TABLE fact_exception\n"); + + stmt = con.createStatement(); + str = ""; + + str = str + "DROP TABLE fact_exception"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + System.out.println( + "DROP TABLE fact_table\n"); + + stmt = con.createStatement(); + str = ""; + + str = str + "DROP TABLE fact_table"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + } + + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + } // partitionedTbCreate + + // export data to a temporary table + static void exportData(Connection con, String path) throws SQLException + { + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + int rows_exported = 0; + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " EXPORT \n" + + "TO EXPORT TABLE DATA INTO A FILE \n" + + "\nExecute the statement:\n" + + " EXPORT TO dummy.del OF DEL SELECT * FROM temp_table"); + + // export data into a dummy file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to which the data is to be exported + param = "EXPORT TO " + path + "/dummy.del OF DEL SELECT * FROM temp_table"; + + // set the input parameter + callStmt1.setString(1, param); + System.out.println(); + + // execute export by calling ADMIN_CMD + callStmt1.execute(); + + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if (rs.next()) + { + // the numbers of rows exported + rows_exported = rs.getInt(1); + + // display the output + System.out.println + ("Total number of rows exported : " + rows_exported); + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // exportData + + // load data from temporary table into base table + static void loadData(Connection con, String path) throws SQLException + { + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + int rows_read = 0; + int rows_skipped = 0; + int rows_loaded = 0; + int rows_rejected = 0; + int rows_deleted = 0; + int rows_committed = 0; + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " LOAD \n" + + "TO LOAD THE DATA INTO THE TABLE \n" + + "\nExecute the statement:\n" + + " LOAD FROM dummy.del OF DEL INSERT INTO fact_table"); + + // Load data from file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path of the file from which the data is to be loaded + param = "LOAD FROM " + path + "/dummy.del OF DEL INSERT INTO fact_table"; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if (rs.next()) + { + // retrieve the no of rows read + rows_read = rs.getInt(1); + + // retrieve the no of rows skipped + rows_skipped = rs.getInt(2); + + // retrieve the no of rows loaded + rows_loaded = rs.getInt(3); + + // retrieve the no of rows rejected + rows_rejected = rs.getInt(4); + + // retrieve the no of rows deleted + rows_deleted = rs.getInt(5); + + // retrieve the no of rows committed + rows_committed = rs.getInt(6); + + // display the resultset + System.out.print("\nTotal number of rows read : "); + System.out.println(rows_read); + System.out.print("Total number of rows skipped : "); + System.out.println( rows_skipped); + System.out.print("Total number of rows loaded : "); + System.out.println(rows_loaded); + System.out.print("Total number of rows rejected : "); + System.out.println(rows_rejected); + System.out.print("Total number of rows deleted : "); + System.out.println(rows_deleted); + System.out.print("Total number of rows committed : "); + System.out.println(rows_read); + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // loadData + + // display the contents of table + static void DisplaytbData(Connection con) throws SQLException + { + try + { + int max = 0; + + System.out.println(); + System.out.println(" SELECT * FROM fact_table"); + System.out.println( + " MAX\n" + + " ------"); + + Statement stmt = con.createStatement(); + // perform a SELECT against the "fact_table" table. + ResultSet rs1 = stmt.executeQuery("SELECT * FROM fact_table"); + + // retrieve and display the result from the SELECT statement + while (rs1.next()) + { + max = rs1.getInt(1); + + System.out.println( + " " + + Data.format(max, 6)); + } + rs1.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // DisplaytbData + + // shows the contents of table + static void showData(Connection con) throws SQLException + { + try + { + int max = 0; + int min = 0; + + System.out.println( + "\n-----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " SELECT\n" + + "ON fact_table TABLE.\n"); + } + + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + Statement stmt = con.createStatement(); + ResultSet rs; + int min = 0; + int max = 0; + + System.out.println( + "Execute the statement:\n" + + "SELECT * FROM fact_table\n"); + + System.out.println( + " MIN MAX \n" + + " ----- ------"); + + // perform a SELECT against the "fact_table" table + rs = stmt.executeQuery( + "SELECT * FROM fact_table"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + min = rs.getInt(1); + max = rs.getInt(2); + + System.out.println( + " " + + Data.format(min, 2) + " " + + Data.format(max, 7)); + } + rs.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " DROP \n" + + "TO DROP THE TABLES \n" + + " DROP TABLE fact_table"); + + // drop the tables + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE fact_table"); + + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // showData + + // creates a partitioned table with 'part1' in 'dms_tspace1', 'part2' in + // 'dms_tspace2' and 'part3' in 'dms_tspace3' with GENERATE IDENTITY clause + static void createptb_with_GenerateIdentity(Connection con) + { + try + { + System.out.println( + "USE THE SQL STATEMENT:\n" + + " CREATE\n" + + "TO CREATE A PARTITIONED TABLE WITH GENERATE IDENTITY CLAUSE"); + + System.out.println( + "\nExecute the statement:" + + "\nCREATE TABLE fact_table (min SMALLINT NOT NULL," + + "\n max SMALLINT GENERATED ALWAYS AS IDENTITY," + + "\n CONSTRAINT CC CHECK (min>0)) " + + "\n PARTITION BY RANGE (min)" + + "\n (PART part1 STARTING FROM (1) ENDING (3) IN dms_tspace1," + + "\n PART part2 STARTING FROM (4) ENDING (6) IN dms_tspace2," + + "\n PART part3 STARTING FROM (7) ENDING (9) IN dms_tspace3)\n"); + + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "CREATE TABLE fact_table (min SMALLINT NOT NULL, "; + str = str + " max SMALLINT GENERATED ALWAYS AS IDENTITY,"; + str = str + " CONSTRAINT CC CHECK (min>0)) "; + str = str + " PARTITION BY RANGE (min)"; + str = str + " (PART part1 STARTING FROM (1) ENDING (3) IN dms_tspace1,"; + str = str + " PART part2 STARTING FROM (4) ENDING (6) IN dms_tspace2,"; + str = str + " PART part3 STARTING FROM (7) ENDING (9) IN dms_tspace3)"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // createptb_with_GenerateIdentity + + // creates a temporary table and inserts data into it. This also shows + // SET INTEGRITY operation on 'fact_table' with FORCE GENERATED clause + // to it. + static void createptb_Temp(Connection con, String path) throws SQLException + { + // creates a partitioned table with GENERATE IDENTITY clause + createptb_with_GenerateIdentity(con); + + try + { + // create a temporary table + System.out.println( + "Execute the statements:\n" + + "CREATE TABLE temp_table (max INTEGER)\n "); + + Statement stmt = con.createStatement(); + String str = ""; + + str = "CREATE TABLE temp_table (max INTEGER)"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + System.out.println( + "INSERT INTO temp_table VALUES (1), (2), (3), (4), (5), (6)," + + " (7), (8), (9)"); + + stmt = con.createStatement(); + str = ""; + + str = "INSERT INTO temp_table VALUES(1), (2), (3), (4), (5), (6),"; + str = str + " (7), (8), (9)"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + // export data to a temporary table + exportData(con, path); + + // load data from temporary table into base table + loadData(con, path); + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " SET INTEGRITY \n" + + "To bring the table out of check pending state\n"); + + System.out.println( + "SET INTEGRITY FOR fact_table IMMEDIATE CHECKED FORCE GENERATED"); + + stmt = con.createStatement(); + stmt.executeUpdate( + "SET INTEGRITY FOR fact_table IMMEDIATE CHECKED FORCE GENERATED"); + + // commit the transaction + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // shows the contents of table + showData(con); + } // createptb_Temp + + // creates temporary tables 'attach_part' and 'attach'. Insert data into + // 'attach'. Exports data from 'attach' into 'dummy.del'. Perform LOAD + // to load data from 'dummy.del' into 'attach_part'. Partition is added + // to 'fact_table' and SET INTEGRITY is performed on 'fact_table' to bring + // table out of check pending state. + static void alterTable(Connection con, String path) throws SQLException + { + // creates a partitioned table with GENERATE IDENTITY clause + createptb_with_GenerateIdentity(con); + + // export data to a temporary table + exportData(con, path); + + // load data from temporary table into base table + loadData(con, path); + + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "CREATE TABLE attach_part (min SMALLINT NOT NULL, "; + str = str + " max SMALLINT GENERATED ALWAYS AS IDENTITY,"; + str = str + " CONSTRAINT CC CHECK (min>0))IN dms_tspace1"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + stmt = con.createStatement(); + str = ""; + str = str + "CREATE TABLE attach(min SMALLINT NOT NULL)"; + stmt.executeUpdate(str); + con.commit(); + + str = ""; + str = str + "INSERT INTO attach VALUES (10), (11), (12)"; + stmt.executeUpdate(str); + con.commit(); + + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + stmt = con.createStatement(); + + int rows_exported = 0; + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " EXPORT \n" + + "TO EXPORT TABLE DATA INTO A FILE \n" + + "\nExecute the statement:\n" + + " EXPORT TO dummy.del OF DEL SELECT * FROM attach"); + + // export data into a dummy file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to which the data is to be exported + param = "EXPORT TO " + path + "/dummy.del OF DEL SELECT * FROM attach"; + + // set the input parameter + callStmt1.setString(1, param); + System.out.println(); + + // execute export by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + // retrieve the resultset + if (rs.next()) + { + // the numbers of rows exported + rows_exported = rs.getInt(1); + + // display the output + System.out.println + ("Total number of rows exported : " + rows_exported); + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + stmt = con.createStatement(); + + int rows_read = 0; + int rows_skipped = 0; + int rows_loaded = 0; + int rows_rejected = 0; + int rows_deleted = 0; + int rows_committed = 0; + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " LOAD \n" + + "TO LOAD THE DATA INTO THE TABLE \n" + + "\nExecute the statement:\n" + + " LOAD FROM dummy.del OF DEL INSERT INTO attach_part"); + + // Load data from file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path of the file from which the data is to be loaded + param = "LOAD FROM " + path + "/dummy.del OF DEL INSERT INTO attach_part"; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if (rs.next()) + { + // retrieve the no of rows read + rows_read = rs.getInt(1); + + // retrieve the no of rows skipped + rows_skipped = rs.getInt(2); + + // retrieve the no of rows loaded + rows_loaded = rs.getInt(3); + + // retrieve the no of rows rejected + rows_rejected = rs.getInt(4); + + // retrieve the no of rows deleted + rows_deleted = rs.getInt(5); + + // retrieve the no of rows committed + rows_committed = rs.getInt(6); + + // display the resultset + System.out.print("\nTotal number of rows read : "); + System.out.println(rows_read); + System.out.print("Total number of rows skipped : "); + System.out.println( rows_skipped); + System.out.print("Total number of rows loaded : "); + System.out.println(rows_loaded); + System.out.print("Total number of rows rejected : "); + System.out.println(rows_rejected); + System.out.print("Total number of rows deleted : "); + System.out.println(rows_deleted); + System.out.print("Total number of rows committed : "); + System.out.println(rows_read); + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " ALTER TABLE\n" + + "TO ATTACH PARTITION TO A TABLE\n" + + "\nExecute the statement:\n" + + " ALTER TABLE fact_table ATTACH PARTITION part4\n" + + " STARTING FROM (10) ENDING AT (12)\n" + + " FROM TABLE attach_part\n"); + + stmt = con.createStatement(); + str = ""; + str = str + "ALTER TABLE fact_table ATTACH PARTITION part4"; + str = str + " STARTING FROM (10) ENDING AT (12) FROM TABLE attach_part"; + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + + // The following SET INTEGRITY statement will check the table fact_table + // for constraint violations and at the same time the GENERATE IDENTITY + // along with INCREMENTAL options will generate new identity values + // for attached rows only. + + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " SET INTEGRITY \n" + + "TO BRING TABLE OUT OF CHECK PENDING STATE\n\n" + + "Execute the statement:\n" + + " SET INTEGRITY FOR fact_table GENERATE IDENTITY\n" + + " IMMEDIATE CHECKED INCREMENTAL;"); + + stmt = con.createStatement(); + str = ""; + str = str + "SET INTEGRITY FOR fact_table GENERATE IDENTITY"; + str = str + " IMMEDIATE CHECKED INCREMENTAL"; + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + + // shows the contents of table + showData(con); + + System.out.println( + "\nExecute the statements:\n" + + "DROP TABLE temp_table\n" + + "DROP TABLE attach"); + + stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE temp_table"); + stmt.executeUpdate("DROP TABLE attach"); + con.commit(); + stmt.close(); + + } // alterTable + + // creates temporary table 'temp_table' and inserts data into it. Data is + // exported from 'temp_table' to 'dummy.del' and later loaded into + // 'fact_table'. SET INTEGRITY with GENERATE IDENTITY clause is performed + // on 'fact_table' to generate new identity values for all rows currently + // in the table and all loaded rows. + static void createtb_Temp(Connection con, String path) throws SQLException + { + // creates a partitioned table with GENERATE IDENTITY clause + createptb_with_GenerateIdentity(con); + + try + { + System.out.println( + "\nExecute the statement:" + + "\n CREATE TABLE temp_table (min SMALLINT NOT NULL)"); + + Statement stmt = con.createStatement(); + String str = ""; + + stmt.executeUpdate("CREATE TABLE temp_table (min SMALLINT NOT NULL)"); + + System.out.println( + "\nExecute the statements:\n" + + " INSERT INTO temp_table VALUES (1), (2), (3), (4), (5)\n" + + " INSERT INTO temp_table VALUES (6), (7), (8), (9)"); + + str = str + "INSERT INTO temp_table VALUES (1), (2), (3), (4), (5),"; + str = str + " (6), (7), (8), (9)"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + // export data to a temporary table + exportData(con, path); + + // load data from temporary table into base table + loadData(con, path); + + // The following SET INTEGRITY statement will check the table + // fact_table for constraint violations and at the same time thei + // GENERATE IDENTITY along with NOT INCREMENTAL options will generate + // new identity values for all rows currently in the table and all + // loaded rows. + + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " SET INTEGRITY\n" + + "TO TABLE OUT OF CHECK PENDING STATE:\n" + + "\nExecute the statement:" + + "\n SET INTEGRITY FOR fact_table GENERATE IDENTITY \n" + + " IMMEDIATE CHECKED NOT INCREMENTAL \n"); + + stmt = con.createStatement(); + str = ""; + + str = str + "SET INTEGRITY FOR fact_table GENERATE IDENTITY"; + str = str + " IMMEDIATE CHECKED NOT INCREMENTAL"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + // shows the contents of table + showData(con); + + System.out.println( + "\nExecute the statement:\n" + + " DROP TABLE temp_table\n"); + + stmt = con.createStatement(); + + stmt.executeUpdate("DROP TABLE temp_table"); + + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // createtb_Temp + + // drops a tablespaces + static void tablespacesDrop(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " DROP \n" + + "TO DROP THE TABLESPACES \n" + + "\nExecute the statements:\n" + + " DROP TABLESPACE dms_tspace\n" + + " DROP TABLESPACE dms_tspace1\n" + + " DROP TABLESPACE dms_tspace2\n" + + " DROP TABLESPACE dms_tspace3"); + + // drop the tablespaces + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLESPACE dms_tspace"); + stmt.executeUpdate("DROP TABLESPACE dms_tspace1"); + stmt.executeUpdate("DROP TABLESPACE dms_tspace2"); + stmt.executeUpdate("DROP TABLESPACE dms_tspace3"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tablespacesDrop +} // SetIntegrity diff --git a/java/jdbc/SpClient.java b/java/jdbc/SpClient.java new file mode 100644 index 0000000..51156a1 --- /dev/null +++ b/java/jdbc/SpClient.java @@ -0,0 +1,692 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: SpClient.java +// +// SAMPLE: Call the set of stored procedures implemented in SpServer.java +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file SpServer.java (this will also +// compile the utility file, Util.java, erase the existing +// library/class files and copy the newly compiled class files, +// SpServer.class, from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make SpServer +// 2. Compile the client source file SpClient.java (this will also +// call the script 'spcat' to create and catalog the stored +// procedures): +// nmake/make SpClient +// 3. Run the client SpClient: +// java SpClient +// +// II) If you don't have a compatible make/nmake program on your +// system do the following: +// 1. Compile the utility file and the server source file with: +// javac Util.java +// javac SpServer.java +// 2. Erase the existing library/class files (if exists), +// SpServer.class from the following path, +// $(DB2PATH)\function. +// 3. Copy the class files, SpServer.class from the current +// directory to the $(DB2PATH)\function. +// 4. Catalog the stored procedures in the database with: +// spcat +// 5. Compile SpClient with: +// javac SpClient.java +// 6. Run SpClient with: +// java SpClient +// +// SpClient calls nine methods that call stored procedures: +// (1) callOutLanguage: Calls a stored procedure that returns the +// implementation language of the stored procedure library +// Parameter types used: OUT CHAR(8) +// (2) callOutParameter: Calls a stored procedure that returns median +// salary of employee salaries +// Parameter types used: OUT DOUBLE +// (3) callInParameters: Calls a stored procedure that accepts 3 salary +// values and updates employee salaries in the EMPLOYEE table based +// on these values for a given department. +// Parameter types used: IN DOUBLE +// IN DOUBLE +// IN DOUBLE +// IN CHAR(3) +// (4) callInoutParameter: Calls a stored procedure that accepts an input +// value and returns the median salary of those employees in the +// EMPLOYEE table who earn more than the input value. Demonstrates how +// to use null indicators in a client application. The stored procedure +// has to be implemented in the following parameter styles for it to be +// compatible with this client application. +// Parameter style for a C stored procedure: SQL +// Parameter style for a Java(JDBC/SQLJ) stored procedure: JAVA +// Parameter style for an SQL stored procedure: SQL +// Parameter types used: INOUT DOUBLE +// (5) callClobExtract: Calls a stored procedure that extracts and returns a +// portion of a CLOB data type +// Parameter types used: IN CHAR(6) +// OUT VARCHAR(1000) +// (6) callDecimalType: Calls a stored procedure that passes and receives a +// DECIMAL data type from a stored procedure +// Parameter types used: INOUT DECIMAL +// (7) callAllDataTypes: Calls a stored procedure that uses a variety of +// common data types (not DECIMAL, GRAPHIC, VARGRAPHIC, BLOB, CLOB, +// DBCLOB). This sample shows only a subset of DB2 supported data types. +// For a full listing of DB2 data types, please see the SQL Reference. +// Parameter types used: INOUT SMALLINT +// INOUT INTEGER +// INOUT BIGINT +// INOUT REAL +// INOUT DOUBLE +// OUT CHAR(1) +// OUT CHAR(15) +// OUT VARCHAR(12) +// OUT DATE +// OUT TIME +// (8) callOneResultSet: Calls a stored procedure that returns a result set to +// the client application +// Parameter types used: IN DOUBLE +// (9) callTwoResultSets: Calls a stored procedure that returns two result sets +// to the client application +// Parameter types used: IN DOUBLE +// +// SQL Statements USED: +// CALL +// SELECT +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: SpClient.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + + +import java.sql.*; // JDBC classes +import java.math.BigDecimal; // BigDecimal support for packed decimal type + +class SpClient +{ + static double outMedian = 0; + static Db db; + public static void main(String argv[]) + { + String language = ""; + + Connection con = null; + + try + { + int prt=Integer.parseInt(argv[1]); + javax.sql.DataSource ds=null; + ds=new com.ibm.db2.jcc.DB2SimpleDataSource(); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setServerName(argv[0]); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setPortNumber(prt); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setDatabaseName("sample"); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setDriverType(4); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setTraceFile("jcctrace.txt"); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds).setEnableNamedParameterMarkers(1); + con = ds.getConnection(argv[2],argv[3]); + System.out.println(" Connect to 'sample' database using JDBC Universal type 4 driver."); + con.setAutoCommit(false); + } + catch (Exception e) + { + System.out.println(" Error loading DB2 Driver...\n"); + System.out.println(e); + System.exit(1); + } + + + + try + { + + + System.out.println("HOW TO CALL VARIOUS STORED PROCEDURES.\n"); + + language = callOutLanguage(con); + callOutParameter(con); + callInParameters(con); + + // call INOUT_PARAM stored procedure using the median returned + // by the call to OUT_PARAM + System.out.println("\nCall stored procedure named INOUT_PARAM"); + System.out.println("using the median returned by the call to " + + "OUT_PARAM"); + callInoutParameter(con, outMedian); + + // call INOUT_PARAM stored procedure again in order to depict a + // NOT FOUND error condition + System.out.println("\nCALL stored procedure INOUT_PARAM again"); + System.out.println("with an input value that causes a NOT FOUND error"); + callInoutParameter(con, 99999.99); + + callClobExtract("000140", con); + callDecimalType(con); + callAllDataTypes(con); + callOneResultSet(con); + callTwoResultSets(con); + + // roll back any changes to the database made by this sample + con.rollback(); + con.close(); + System.out.println(); + System.out.println(" Disconnect from 'sample' database."); + } + catch (Exception e) + { + try + { + con.rollback(); + con.close(); + } + catch (Exception x) + { } + + e.printStackTrace(); + } + } // end main + + public static String callOutLanguage(Connection con) + { + String outLang = ""; + try + { + // prepare the CALL statement for OUT_LANGUAGE + String procName = "OUT_LANGUAGE"; + String sql = "CALL " + procName + "(:Typchar)"; + CallableStatement callStmt = con.prepareCall(sql); + + // register the output parameter + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("Typchar", Types.CHAR); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + callStmt.execute(); + + // retrieve output parameters + outLang = callStmt.getString(1); + System.out.println("Stored procedures are implemented in language " + + outLang); + + // clean up resources + callStmt.close(); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + return(outLang); + } // callOutLanguage + + public static void callOutParameter(Connection con) + { + try + { + // prepare the CALL statement for OUT_PARAM + String procName = "OUT_PARAM"; + String sql = "CALL " + procName + "(:Typdouble)"; + CallableStatement callStmt = con.prepareCall(sql); + + // register the output parameter + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("Typdouble", Types.DOUBLE); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + + callStmt.execute(); + + // retrieve output parameters + outMedian = callStmt.getDouble(1); + + System.out.println(procName + " completed successfully"); + System.out.println("Median salary returned from " + procName + " = " + + outMedian); + + // clean up resources + callStmt.close(); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callOutParameter + + + public static void callInParameters(Connection con) throws SQLException + { + try + { + // prepare the CALL statement for IN_PARAMS + String procName = "IN_PARAMS"; + String sql = "CALL " + procName + "(:lowsal, :medsal, :hisal, :dept)"; + CallableStatement callStmt = con.prepareCall(sql); + + // display total salary before calling IN_PARAMS + String query = "SELECT SUM(salary) FROM employee WHERE workdept = :dept"; + PreparedStatement queryStmt = con.prepareStatement(query); + ((com.ibm.db2.jcc.DB2PreparedStatement)queryStmt).setJccStringAtName("dept", "E11"); + ResultSet queryRS = queryStmt.executeQuery(); + queryRS.next(); + double sumSalary = queryRS.getDouble(1); + queryRS.close(); + System.out.println(); + System.out.println("Sum of salaries for dept. E11 = " + + sumSalary + " before " + procName); + + // set input parameters + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccDoubleAtName("lowsal", 15000); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccDoubleAtName("medsal", 20000); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccDoubleAtName("hisal", 25000); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccStringAtName("dept", "E11"); + + // call the stored procedure + System.out.println("Call stored procedure named " + procName); + callStmt.execute(); + + System.out.println(procName + " completed successfully"); + + // display total salary after calling IN_PARAMS + queryRS = queryStmt.executeQuery(); + queryRS.next(); + sumSalary = queryRS.getDouble(1); + queryRS.close(); + System.out.println("Sum of salaries for dept. E11 = " + + sumSalary + " after " + procName); + + // clean up resources + queryStmt.close(); + callStmt.close(); + } + catch (SQLException e) + { + // roll back any UPDATE statements issued before the SQLException + con.rollback(); + System.out.println(e.getMessage()); + } + } // callInParameters + + public static void callInoutParameter(Connection con, double median) + { + try + { + // prepare the CALL statement for INOUT_PARAM + String procName = "INOUT_PARAM"; + String sql = "CALL " + procName + "(:median)"; + CallableStatement callStmt = con.prepareCall(sql); + + // set input parameter to median value passed back by OUT_PARAM + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccDoubleAtName("median", median); + + // register the output parameters + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("median", Types.DOUBLE); + + if (median == 99999.99) + { + System.out.println("\n-- The following error report is " + + "expected! --"); + } + callStmt.execute(); + + // retrieve output parameters + double inoutMedian = callStmt.getDouble(1); + + System.out.println(procName + " completed successfully"); + System.out.println("Median salary returned from " + procName + " = " + + inoutMedian); + + // clean up resources + callStmt.close(); + + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callInoutParameter + + public static void callClobExtract(String empNo, Connection con) + { + String outResume; + try + { + // prepare the CALL statement for CLOB_EXTRACT + String procName = "CLOB_EXTRACT"; + String sql = "CALL " + procName + "(:empNo, :Typvarchar)"; + CallableStatement callStmt = con.prepareCall(sql); + + // set input parameter to median value passed back by OUT_PARAM + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccStringAtName("empNo", empNo); + + // register the output parameters + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("Typvarchar", Types.VARCHAR); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + callStmt.execute(); + + // retrieve output parameters + outResume = callStmt.getString(2); + + System.out.println(procName + " completed successfully"); + System.out.println("Resume section returned for employee " + + empNo + "=\n" + outResume); + + } + catch (Exception e) + { + System.out.println(e.getMessage()); + } + } // callClobExtract + + //************************************************************************* + // PARAMETER STYLE JAVA procedures do not support the DBINFO clause. + // The following PARAMETER STYLES can be used with DBINFO or PROGRAM TYPE + // clauses: + // - DB2SQL + // - GENERAL + // - GENERAL WITH NULLS + // - SQL + // Please see the SpClient implementation for C/C++/CLI language to + // see this functionality. + //************************************************************************* + + //************************************************************************* + // PROGRAM TYPE MAIN is only valid for LANGUAGE C, COBOL or CLR, and + // following PARAMETER STYLE: + // - DB2SQL + // - GENERAL + // - GENERAL WITH NULLS + // - SQL + // Please see the SpClient implementation for C/C++/CLI language to + // see this functionality. + //************************************************************************* + + public static void callDecimalType(Connection con) + { + try + { + // prepare the CALL statement for DECIMAL_TYPE + String procName = "DECIMAL_TYPE"; + String sql = "CALL " + procName + "(:inoutDec)"; + CallableStatement callStmt = con.prepareCall(sql); + + // declare and initialize input variable + BigDecimal inoutDecimal = new BigDecimal("400000.00"); + + // set input parameter + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccBigDecimalAtName("inoutDec", inoutDecimal); + + // register the output parameters + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("inoutDec", Types.DECIMAL, 2); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + callStmt.execute(); + + System.out.println(procName + " completed successfully"); + + // retrieve output parameters + inoutDecimal = callStmt.getBigDecimal(1).setScale( 2 ); + System.out.println("Value of DECIMAL = " + inoutDecimal); + + callStmt.close(); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callDecimalType + + public static void callAllDataTypes(Connection con) + { + try + { + // prepare the CALL statement for ALL_DATA_TYPES + String procName = "ALL_DATA_TYPES"; + String sql = "CALL " + + procName + "(:iosmall, :ioint, :iobigint, :ioreal, :iodouble, :char1, :char2, :varchar, :date, :time)"; + CallableStatement callStmt = con.prepareCall(sql); + + // declare and initialize input variables + short inoutSmallint = 32000; + int inoutInteger = 2147483000; + long inoutBigint = 2147483000; + float inoutReal = 100000; + double inoutDouble = 2500000; + + // declare output variables + String outChar, outChars, outVarchar; + Date outDate; + Time outTime; + + // set input parameters + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccShortAtName("iosmall", inoutSmallint); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccIntAtName("ioint", inoutInteger); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccLongAtName("iobigint", inoutBigint); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccFloatAtName("ioreal", inoutReal); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccDoubleAtName("iodouble", inoutDouble); + + // register the output parameters + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("iosmall", Types.SMALLINT); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("ioint", Types.INTEGER); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("iobigint", Types.BIGINT); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("ioreal", Types.REAL); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("iodouble", Types.DOUBLE); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("char1", Types.CHAR); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("char2", Types.CHAR); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("varchar", Types.VARCHAR); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("date", Types.DATE); + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).registerJccOutParameterAtName("time", Types.TIME); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + callStmt.execute(); + + System.out.println(procName + " completed successfully"); + + // retrieve output parameters + inoutSmallint = callStmt.getShort(1); + inoutInteger = callStmt.getInt(2); + inoutBigint = callStmt.getLong(3); + inoutReal = callStmt.getFloat(4); + inoutDouble = callStmt.getDouble(5); + outChar = callStmt.getString(6); + outChars = callStmt.getString(7); + outVarchar = callStmt.getString(8); + outDate = callStmt.getDate(9); + outTime = callStmt.getTime(10); + + System.out.println("Value of SMALLINT = " + inoutSmallint); + System.out.println("Value of INTEGER = " + inoutInteger); + System.out.println("Value of BIGINT = " + inoutBigint); + System.out.println("Value of REAL = " + inoutReal); + System.out.println("Value of DOUBLE = " + inoutDouble); + System.out.println("Value of CHAR(1) = " + outChar); + System.out.println("Value of CHAR(15) = " + outChars.trim()); + System.out.println("Value of VARCHAR(12) = " + outVarchar.trim()); + System.out.println("Value of DATE = " + outDate); + System.out.println("Value of TIME = " + outTime); + + callStmt.close(); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callAllDataTypes + + public static void callOneResultSet(Connection con) + { + try + { + // prepare the CALL statement for ONE_RESULT_SET + String procName = "ONE_RESULT_SET"; + String sql = "CALL " + procName + "(:outMedian)"; + CallableStatement callStmt = con.prepareCall(sql); + + // set input parameter to median value passed back by OUT_PARAM + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccDoubleAtName("outMedian", outMedian); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + callStmt.execute(); + + System.out.println(procName + " completed successfully"); + ResultSet rs = callStmt.getResultSet(); + fetchAll(rs); + + // close ResultSet and callStmt + rs.close(); + callStmt.close(); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callOneResultSet + + public static void callTwoResultSets(Connection con) + { + try + { + // prepare the CALL statement for TWO_RESULT_SETS + String procName = "TWO_RESULT_SETS"; + String sql = "CALL " + procName + "(:outMedian)"; + CallableStatement callStmt = con.prepareCall(sql); + + // set input parameter to median value passed back by OUT_PARAM + ((com.ibm.db2.jcc.DB2CallableStatement)callStmt).setJccDoubleAtName("outMedian", outMedian); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + callStmt.execute(); + + System.out.println(procName + " completed successfully"); + + System.out.println( + "Result set 1: Employees with salaries greater than " + outMedian); + // get first result set + ResultSet rs = callStmt.getResultSet(); + fetchAll(rs); + + System.out.println(); + System.out.println("Result set 2: Employees with salaries less than " + + outMedian); + // get second result set + callStmt.getMoreResults(); + rs = callStmt.getResultSet(); + fetchAll(rs); + + // close ResultSet and callStmt + rs.close(); + callStmt.close(); + + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callTwoResultSets + + //************************************************************************* + // PARAMETER STYLE GENERAL and GENERAL WITH NULLS can be specified when + // LANGUAGE C, COBOL, or CLR is used. + // Please see the SpClient implementation for CLI language to see this + // functionality. + //************************************************************************* + + // ====================================================== + // Method: fetchAll -- returns all rows from a result set + // ====================================================== + public static void fetchAll(ResultSet rs) + { + try + { + System.out.println( + "============================================================="); + + // retrieve the number, types and properties of the + // resultset's columns + ResultSetMetaData stmtInfo = rs.getMetaData(); + + int numOfColumns = stmtInfo.getColumnCount(); + int r = 0; + + while (rs.next()) + { + r++; + System.out.print("Row: " + r + ": "); + for (int i = 1; i <= numOfColumns; i++) + { + if (i == 3) + { + System.out.print(Data.format(rs.getDouble(i), 7, 2)); + } + else + { + System.out.print(rs.getString(i)); + } + + if (i != numOfColumns) + { + System.out.print(", "); + } + } + System.out.println(); + } + } + catch (Exception e) + { + System.out.println("Error: fetchALL: exception"); + System.out.println(e.getMessage()); + } + } // fetchAll +} // SpServer diff --git a/java/jdbc/SpCreate.db2 b/java/jdbc/SpCreate.db2 new file mode 100644 index 0000000..c6419b2 --- /dev/null +++ b/java/jdbc/SpCreate.db2 @@ -0,0 +1,165 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: SpCreate.db2 +-- +-- SAMPLE: How to catalog the stored procedures contained in SpServer.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +CREATE PROCEDURE OUT_LANGUAGE (OUT LANGUAGE CHAR(8)) +SPECIFIC JDBC_OUT_LANGUAGE +DYNAMIC RESULT SETS 0 +DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'MYJAR:SpServer.outLanguage'@ + +CREATE PROCEDURE OUT_PARAM (OUT medianSalary DOUBLE) +SPECIFIC JDBC_OUT_PARAM +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'MYJAR:SpServer.outParameter'@ + +CREATE PROCEDURE IN_PARAMS ( + IN lowsal DOUBLE, + IN medsal DOUBLE, + IN highsal DOUBLE, + IN department CHAR(3)) +SPECIFIC JDBC_IN_PARAMS +DYNAMIC RESULT SETS 0 +DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +MODIFIES SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'MYJAR:SpServer.inParams'@ + +CREATE PROCEDURE INOUT_PARAM (INOUT medianSalary DOUBLE) +SPECIFIC JDBC_INOUT_PARAM +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +MODIFIES SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'MYJAR:SpServer.inoutParam'@ + +CREATE PROCEDURE CLOB_EXTRACT ( + IN number CHAR(6), + OUT buffer VARCHAR(1000)) +SPECIFIC JDBC_CLOB_EXTRACT +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'MYJAR:SpServer.clobExtract'@ + +CREATE PROCEDURE DECIMAL_TYPE (INOUT decimalIn DECIMAL(10,2)) +SPECIFIC JDBC_DEC_TYPE +DYNAMIC RESULT SETS 0 +DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'MYJAR:SpServer.decimalType'@ + +CREATE PROCEDURE ALL_DATA_TYPES ( + INOUT small SMALLINT, + INOUT intIn INTEGER, + INOUT bigIn BIGINT, + INOUT realIn REAL, + INOUT doubleIn DOUBLE, + OUT charOut CHAR(1), + OUT charsOut CHAR(15), + OUT varcharOut VARCHAR(12), + OUT dateOut DATE, + OUT timeOut TIME) +SPECIFIC JDBC_ALL_DAT_TYPES +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'MYJAR:SpServer.allDataTypes'@ + +CREATE PROCEDURE ONE_RESULT_SET (IN salValue DOUBLE) +SPECIFIC JDBC_ONE_RES_SET +DYNAMIC RESULT SETS 1 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'MYJAR:SpServer.resultSetToClient'@ + +CREATE PROCEDURE TWO_RESULT_SETS (IN salary DOUBLE) +SPECIFIC JDBC_TWO_RES_SETS +DYNAMIC RESULT SETS 2 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'MYJAR:SpServer.twoResultSets'@ + +connect reset@ diff --git a/java/jdbc/SpDrop.db2 b/java/jdbc/SpDrop.db2 new file mode 100644 index 0000000..96334f3 --- /dev/null +++ b/java/jdbc/SpDrop.db2 @@ -0,0 +1,51 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: SpDrop.db2 +-- +-- SAMPLE: How to uncatalog the stored procedures contained in SpServer.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +DROP PROCEDURE OUT_LANGUAGE (CHAR(8))@ + +DROP PROCEDURE OUT_PARAM (DOUBLE)@ + +DROP PROCEDURE IN_PARAMS (DOUBLE, DOUBLE, DOUBLE, CHAR(3))@ + +DROP PROCEDURE INOUT_PARAM (DOUBLE)@ + +DROP PROCEDURE CLOB_EXTRACT (CHAR(6), VARCHAR(1000))@ + +DROP PROCEDURE DECIMAL_TYPE (DECIMAL(10,2))@ + +DROP PROCEDURE ALL_DATA_TYPES (SMALLINT, INTEGER, BIGINT, REAL, DOUBLE, + CHAR(1), CHAR(15), VARCHAR(12), DATE, TIME)@ + +DROP PROCEDURE ONE_RESULT_SET (DOUBLE)@ + +DROP PROCEDURE TWO_RESULT_SETS (DOUBLE)@ + +connect reset@ diff --git a/java/jdbc/SpServer.java b/java/jdbc/SpServer.java new file mode 100644 index 0000000..819c05f --- /dev/null +++ b/java/jdbc/SpServer.java @@ -0,0 +1,944 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: SpServer.java +// +// SAMPLE: Code implementations of various types of stored procedures +// The stored procedures defined in this program are called by the +// client application SpClient.java. Before building and running +// spclient.java, build the shared library by completing the following +// steps: +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file SpServer.java (this will also +// compile the Utility file, Util.java, erase the existing +// library/class files and copy the newly compiled class files, +// SpServer.class, from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make SpServer +// 2. Compile the client source file SpClient.java (this will also +// call the script 'spcat' to create and catalog the stored +// procedures): +// nmake/make SpClient +// 3. Run the client SpClient: +// java SpClient +// +// II) If you don't have a compatible make/nmake program on your +// system do the following: +// 1. Compile the utility file and the server source file with: +// javac Util.java +// javac SpServer.java +// 2. Erase the existing library/class files (if exists), +// SpServer.class from the following path, +// $(DB2PATH)\function. +// 3. Copy the class files, SpServer.class from the current +// directory to the $(DB2PATH)\function. +// 4. Catalog the stored procedures in the database with the script: +// spcat +// 5. Compile SpClient with: +// javac SpClient.java +// 6. Run SpClient with: +// java SpClient +// +// Class SpServer contains nine methods: +// 1. outLanguage: returns the implementation language of the stored +// procedure library +// 2. outParameter: returns median salary of employee salaries +// 3. inParams: accepts 3 salary values and updates employee +// salaries in the EMPLOYEE table based on these values for a +// given department +// 4. inoutParam: accepts an input value and returns the median +// salary of those employees in the EMPLOYEE table who earn more +// than the input value +// 5. clobExtract: returns a section of a CLOB type as a string +// 6. decimalType: manipulates an INOUT DECIMAL parameter +// 7. allDataTypes: uses all of the common data types in a stored +// procedure +// 8. resultSetToClient: returns a result set to the client +// application +// 9. twoResultSets: returns two result sets to the client +// application +// +// SQL Statements USED: +// SELECT +// UPDATE +// +// OUTPUT FILE: SpClient.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; // JDBC classes +import java.io.*; // Input/Output classes +import java.math.BigDecimal; // Packed Decimal class + +/////// +// Java stored procedure is in this class +/////// +public class SpServer +{ + //************************************************************************* + // Stored Procedure: outLanguage + // + // Purpose: Returns the code implementation language of + // routine 'OutLanguage' (as it appears in the + // database catalog) in an output parameter. + // + // Parameters: + // + // IN: (none) + // OUT: outLanguage - the code language of this routine + // + //************************************************************************* + public static void outLanguage(String[] outLanguage) // CHAR(8) + throws SQLException + { + + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + try + { + String procName; + + // initialize variables + procName = "OUT_LANGUAGE"; + + errorLabel = "GET CONNECTION"; + // get caller's connection to the database + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + errorLabel = "SELECT STATEMENT"; + + String query = "SELECT language FROM syscat.procedures " + + "WHERE procname = ? "; + + errorLabel = "PREPARE STATEMENT"; + PreparedStatement stmt = con.prepareStatement(query); + stmt.setString(1, procName); + + errorLabel = "GET LANGUAGE RESULT SET"; + ResultSet rs = stmt.executeQuery(); + + if (!rs.next()) + { + // set errorCode to SQL0100 to indicate data not found + errorLabel = "100 : NO DATA FOUND"; + throw new SQLException(errorLabel); + } + else + { + // move to first row of result set + // rs.next(); + + // set value for the output parameter + outLanguage[0] = rs.getString(1); + } + + // clean up resources + rs.close(); + stmt.close(); + con.close(); + } + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + throw new SQLException( errorCode + " : " + errorLabel + " FAILED" ); + } + } // outLanguage + + //************************************************************************* + // Stored Procedure: outParameter + // + // Purpose: Sorts table STAFF by salary, locates and returns + // the median salary + // + // Parameters: + // + // IN: (none) + // OUT: outMedianSalary - median salary in table STAFF + // + //************************************************************************* + public static void outParameter(double[] outMedianSalary) + throws SQLException + { + + int counter; + int numRecords; + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + try + { + // initialize variables + counter = 0; + + // get caller's connection to the database + errorLabel = "GET CONNECTION"; + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + errorLabel = "SELECT STATEMENT"; + String query = "SELECT COUNT(*) FROM staff"; + + errorLabel = "PREPARE COUNT STATEMENT"; + PreparedStatement stmt1 = con.prepareStatement(query); + + errorLabel = "GET COUNT RESULT SET"; + ResultSet rs1 = stmt1.executeQuery(); + + // move to first row of result set + rs1.next(); + + // set value for the output parameter + errorLabel = "GET NUMBER OF RECORDS"; + numRecords = rs1.getInt(1); + + // clean up first result set + rs1.close(); + stmt1.close(); + + // get salary result set + errorLabel = "SELECT STATEMENT"; + query = "SELECT CAST(salary AS DOUBLE) FROM staff ORDER BY salary"; + + errorLabel = "PREPARE SALARY STATEMENT"; + PreparedStatement stmt2 = con.prepareStatement(query); + + errorLabel = "GET SALARY RESULT SET"; + ResultSet rs2 = stmt2.executeQuery(); + + errorLabel = "MOVE TO NEXT ROW"; + while (counter < (numRecords / 2 + 1)) + { + rs2.next(); + counter++; + } + errorLabel = "GET MEDIAN SALARY"; + outMedianSalary[0] = rs2.getDouble(1); + + // clean up resources + rs2.close(); + stmt2.close(); + con.close(); + + } + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + throw new SQLException( errorCode + " : " + errorLabel + " FAILED" ); + } + } // outParameter + + //************************************************************************* + // Stored Procedure: inParams + // + // Purpose: Updates salaries of employees in department 'inDepartment' + // using inputs inLowSal, inMedSal, inHighSal as + // salary raise/adjustment values. + // + // Parameters: + // + // IN: inLowSal - new salary for low salary employees + // inMedSal - new salary for mid salary employees + // inHighSal - new salary for high salary employees + // inDepartment - department to use in SELECT predicate + // OUT: (none) + // + //************************************************************************* + public static void inParams(double inLowSal, + double inMedSal, + double inHighSal, + String inDepartment) // CHAR(3) + throws SQLException + { + double salary; + String cursorName; + int errorCode; + String errorLabel = null; + + errorCode = 0; // SQLCODE = 0 unless SQLException occurs + + // initialize variables + salary = 0; + cursorName = ""; + + try + { + // get caller's connection to the database + errorLabel = "GET CONNECTION"; + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + errorLabel = "SELECT STATEMENT"; + String query = "SELECT CAST(salary AS DOUBLE) " + + " FROM employee " + + " WHERE workdept = ? " + + " FOR UPDATE"; + + errorLabel = "PREPARE STATEMENT 1"; + PreparedStatement stmt = con.prepareStatement(query); + stmt.setString(1, inDepartment); + errorLabel = "GET RESULT SET"; + ResultSet rs = stmt.executeQuery(); + cursorName = rs.getCursorName(); + + errorLabel = "GET FIRST ROW"; + if (!rs.next()) + { + // set errorCode to SQL0100 to indicate data not found + errorLabel = "100 : NO DATA FOUND"; + throw new SQLException(errorLabel); + } + else + { + boolean foundData = true; + + String updateByValue = "UPDATE employee SET salary = ? " + + " WHERE CURRENT OF " + cursorName; + String updateFinal = "UPDATE employee SET salary = (salary * 1.10)" + + " WHERE CURRENT OF " + cursorName; + + errorLabel = "PREPARE 'stmtByValue'"; + PreparedStatement stmtByValue = con.prepareStatement(updateByValue); + + errorLabel = "PREPARE 'stmtFinal'"; + PreparedStatement stmtFinal = con.prepareStatement(updateFinal); + + while (foundData) + { + errorLabel = "GET SALARY"; + salary = rs.getDouble(1); + if (inLowSal > salary) + { + errorLabel = "UPDATE -- LOW CASE"; + // to update the salary to inLowSal value + stmtByValue.setDouble(1, inLowSal); + stmtByValue.executeUpdate(); + } + else if (inMedSal > salary) + { + errorLabel = "UPDATE -- MEDIUM CASE"; + // to update the salary to inMedSal value + stmtByValue.setDouble(1, inMedSal); + stmtByValue.executeUpdate(); + } + else if (inHighSal > salary) + { + errorLabel = "UPDATE -- HIGH CASE"; + // to update the salary to inHighSal value + stmtByValue.setDouble(1, inHighSal); + stmtByValue.executeUpdate(); + } + else + { + errorLabel = "UPDATE -- FINAL CASE"; + stmtFinal.executeUpdate(); + } + + if (!rs.next()) // if next row is not found + { + foundData = false; + } + } + + stmtByValue.close(); + stmtFinal.close(); + } + + rs.close(); + stmt.close(); + con.close(); + + } + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + if (errorLabel.equalsIgnoreCase("100 : NO DATA FOUND")) + throw new SQLException(sqle.getMessage()); + else + throw new SQLException( errorCode + " : " + errorLabel + " FAILED" ); + } + } // inParams + + //************************************************************************* + // Stored Procedure: inOutParam + // + // Purpose: Calculates the median salary of all salaries in the STAFF + // above table the input median salary. + // + // Parameters: + // + // IN/OUT: inOutMedianSalary - median salary + // The input value is used in a SELECT + // predicate. Its output value is set to the + // median salary. + // + //************************************************************************* + public static void inoutParam(double[] inoutMedianSalary) + throws SQLException + { + int counter; + int numRecords; + double salary; + String cursorName; + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + // initialize variables + counter = 0; + salary = 0; + cursorName = ""; + + try + { + // get the caller's connection to the database + errorLabel = "GET CONNECTION"; + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + errorLabel = "SELECT STATEMENT"; + String query = "SELECT COUNT(*) FROM staff " + + " WHERE CAST(salary AS DOUBLE) > ? "; + + errorLabel = "PREPARE COUNT STATEMENT"; + PreparedStatement stmt1 = con.prepareStatement(query); + stmt1.setDouble(1, inoutMedianSalary[0]); + + errorLabel = "GET COUNT RESULT SET"; + ResultSet rs1 = stmt1.executeQuery(); + + // move to first row of result set + rs1.next(); + + // set value for the output parameter + errorLabel = "GET NUMBER OF RECORDS"; + numRecords = rs1.getInt(1); + + // clean up first result set + rs1.close(); + stmt1.close(); + + if (numRecords == 0) + { + // set errorCode to SQL0100 to indicate data not found + errorLabel = "100 : NO DATA FOUND"; + throw new SQLException(errorLabel); + } + else + { + // get salary result set + query = "SELECT CAST(salary AS DOUBLE) FROM staff " + + " WHERE CAST(salary AS DOUBLE) > ? " + + " ORDER BY salary"; + errorLabel = "PREPARE SALARY STATEMENT FAILED"; + PreparedStatement stmt2 = con.prepareStatement(query); + stmt2.setDouble(1, inoutMedianSalary[0]); + errorLabel = "GET SALARY RESULT SET"; + ResultSet rs2 = stmt2.executeQuery(); + + while (counter < (numRecords / 2 + 1)) + { + errorLabel = "MOVE TO NEXT ROW"; + rs2.next(); + counter++; + } + errorLabel = "GET MEDIAN SALARY"; + inoutMedianSalary[0] = rs2.getDouble(1); + + // clean up resources + rs2.close(); + stmt2.close(); + } + + // close connection + con.close(); + } + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + if (errorLabel.equalsIgnoreCase("100 : NO DATA FOUND")) + throw new SQLException(sqle.getMessage()); + else + throw new SQLException( errorCode + " : " + errorLabel + "FAILED" ); + } + } // inoutParam + + //************************************************************************* + // Stored Procedure: clobExtract + // + // Purpose: Extracts department information from a large object (LOB) + // resume of employee data returns this information + // to the caller in output parameter outDeptInfo. + // + // Parameters: + // + // IN: inEmpNumber - employee number + // OUT: outDeptInfo - department information section of the + // employee's resume + // + //************************************************************************* + public static void clobExtract(String inEmpNumber, // CHAR(6) + String[] outDeptInfo) // VARCHAR(1000) + throws Exception + { + int counter; + int index; + int maximumLength; + byte[] clobBytes; + char[] clobData; + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + try + { + errorLabel = "GET CONNECTION"; + + // get caller's connection to the database + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + errorLabel = "SELECT STATEMENT"; + // choose the employee resume that matches the employee number + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT resume FROM emp_resume " + + " WHERE empno = '" + inEmpNumber + "'" + + " AND resume_format = 'ascii'"); + + if (rs.next()) + { + // copy the CLOB into an array of characters by converting all + // bytes into characters as they are read in + InputStream inStream = rs.getAsciiStream(1); + + // InputStream.available() may not work on larger files + maximumLength = inStream.available(); + clobBytes = new byte[maximumLength]; + clobData = new char[maximumLength]; + + inStream.read(clobBytes); + for (counter = 0; counter < maximumLength; counter++) + { + clobData[counter] = (char)clobBytes[counter]; + } + + String clob = String.valueOf(clobData); + + // copy substring from "Department Info" to "Education" + // into OUT parameter + index = clob.indexOf("Department Info"); + if (index == -1) + { + outDeptInfo[0] = "Resume does not contain a " + + "Department Info section."; + } + else + { + outDeptInfo[0] = clob.substring(clob.indexOf("Department Info"), + clob.indexOf("Education")); + } + } + else + { + outDeptInfo[0] = ("\nEmployee " + inEmpNumber + + " does not have a resume."); + } + rs.close(); + stmt.close(); + } + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + throw new SQLException( errorCode + " : " + errorLabel + "FAILED" ); + } + } // clobExtract + + //************************************************************************* + // PARAMETER STYLE JAVA procedures do not support the DBINFO clause. + // The following PARAMETER STYLES can be used with DBINFO or PROGRAM TYPE + // clauses: + // - DB2SQL + // - GENERAL + // - GENERAL WITH NULLS + // - SQL + // Please see the SpServer implementation for C/C++/CLI language to + // see this functionality. + //************************************************************************* + + //************************************************************************* + // PROGRAM TYPE MAIN is only valid for LANGUAGE C, COBOL or CLR, and + // following PARAMETER STYLE: + // - DB2SQL + // - GENERAL + // - GENERAL WITH NULLS + // - SQL + // Please see the SpServer implementation for C/C++/CLI language to + // see this functionality. + //************************************************************************* + + //************************************************************************* + // Stored Procedure: decimalType + // + // Purpose: Takes in a decimal number as input, divides it by 2 + // and returns the resulting decimal rounded off to 2 + // decimal places. + // + // Parameters: + // + // INOUT: inOutDecimal - DECIMAL(10,2) + // + //************************************************************************* + public static void decimalType(BigDecimal[] inoutDecimal) // DECIMAL(10,2) + throws SQLException + { + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + try + { + // get caller's connection to the database + errorLabel = "GET CONNECTION"; + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + if (inoutDecimal[0].equals(BigDecimal.valueOf(0))) + { + inoutDecimal[0].add(BigDecimal.valueOf(1)); + } + else + { + inoutDecimal[0] = inoutDecimal[0].divide(BigDecimal.valueOf(2), + BigDecimal.ROUND_HALF_UP); + } + + // close our connection + con.close(); + } + + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + throw new SQLException( errorCode + " : DECIMAL_TYPE FAILED" ); + } + } // decimalType + + //************************************************************************* + // Stored Procedure: allDataTypes + // + // Purpose: Take each parameter and set it to a new output value. + // This sample shows only a subset of DB2 supported data types. + // For a full listing of DB2 data types, please see the SQL + // Reference. + // + // Parameters: + // + // INOUT: inOutSmallint, inOutInteger, inOutBigint, inOutReal, + // outDouble + // OUT: outChar, outChars, outVarchar, outDate, outTime + // + //************************************************************************* + public static void allDataTypes(short[] inoutSmallint, + int[] inoutInteger, + long[] inoutBigint, + float[] inoutReal, + double[] inoutDouble, + String[] outChar, // CHAR(1) + String[] outChars, // CHAR(15) + String[] outVarchar, // VARCHAR(13) + Date[] outDate, // DATE + Time[] outTime) // TIME + throws SQLException + { + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + try + { + // get caller's connection to the database + errorLabel = "GET CONNECTION"; + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + if (inoutSmallint[0] == 0) + { + inoutSmallint[0] = 1; + } + else + { + inoutSmallint[0] = (short)(inoutSmallint[0] / 2); + } + + if (inoutInteger[0] == 0) + { + inoutInteger[0] = 1; + } + else + { + inoutInteger[0] = (inoutInteger[0] / 2); + } + + if (inoutBigint[0] == 0) + { + inoutBigint[0] = 1; + } + else + { + inoutBigint[0] = (inoutBigint[0] / 2); + } + + if (inoutReal[0] == 0) + { + inoutReal[0] = 1; + } + else + { + inoutReal[0] = (inoutReal[0] / 2); + } + + if (inoutDouble[0] == 0) + { + inoutDouble[0] = 1; + } + else + { + inoutDouble[0] = (inoutDouble[0] / 2); + } + + errorLabel = "SELECT MIDINIT, LASTNAME ..."; + + // get value of midinit, lastname and firstnme + String query = "SELECT midinit, lastname, firstnme " + + " FROM employee " + + " WHERE empno = '000180' "; + + // create the SQL statement + Statement stmt = con.createStatement(); + + // get the result set + ResultSet rs = stmt.executeQuery(query); + + // move to first row of result set + rs.next(); + + // get the value of the midinit column + outChar[0] = rs.getString(1); + // get the value of the lastname column + outChars[0] = rs.getString(2); + // get the value of the firstnme column + outVarchar[0] = rs.getString(3); + + // clean up resources + rs.close(); + stmt.close(); + + errorLabel = "VALUES(CURRENT DATE)"; + // get current date from DB2 server + query = "VALUES(CURRENT DATE)"; + + // create the SQL statement + stmt = con.createStatement(); + + // get the result set + rs = stmt.executeQuery(query); + + // move to first row of result set + rs.next(); + + // get the date value + outDate[0] = rs.getDate(1); + + // clean up resources + rs.close(); + stmt.close(); + + errorLabel = "VALUES(CURRENT TIME)"; + // get current time from DB2 server + query = "VALUES(CURRENT TIME)"; + + // create the SQL statement + stmt = con.createStatement(); + + // get the result set + rs = stmt.executeQuery(query); + + // move to first row of result set + rs.next(); + + // get the time value + outTime[0] = rs.getTime(1); + + // clean up resources + rs.close(); + stmt.close(); + + // close our connection + con.close(); + } + + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + throw new SQLException( errorCode + " : " + errorLabel + " FAILED" ); + } + } // allDataTypes + + //************************************************************************* + // Stored Procedure: resultSetToClient + // + // Purpose: Returns a result set to the caller that identifies employees + // with salaries greater than the value of input parameter + // inSalaryThreshold. + // + // Parameters: + // + // IN: inSalaryThreshold - salary + // OUT: outRs - ResultSet + // + //************************************************************************* + public static void resultSetToClient(double inSalaryThreshold, + ResultSet[] outRs) + throws SQLException + { + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + try + { + // get caller's connection to the database + errorLabel = "GET CONNECTION"; + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + errorLabel = "SELECT STATEMENT"; + + // set the SQL statement that will return the desired result set + String query = "SELECT name, job, CAST(salary AS DOUBLE) " + + " FROM staff " + + " WHERE salary > ? " + + " ORDER BY salary"; + + // prepare the SQL statement + PreparedStatement stmt = con.prepareStatement(query); + + // set the value of the parameter marker (?) + stmt.setDouble(1, inSalaryThreshold); + + // get the result set that will be returned to the client + outRs[0] = stmt.executeQuery(); + + // to return a result set to the client, do not close ResultSet + con.close(); + } + + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + throw new SQLException( errorCode + " : " + errorLabel + " FAILED" ); + } + } // resultSetToClient + + //************************************************************************* + // Stored Procedure: twoResultSets + // + // Purpose: Return two result sets to the caller. One result set + // consists of employee data of all employees with + // salaries greater than inSalaryThreshold. The other + // result set contains employee data for employees with salaries + // less than inSalaryThreshold. + // + // Parameters: + // + // IN: inSalaryThreshold - salary + // OUT: outRs1 - first ResultSet + // outRs2 - second ResultSet + // + //************************************************************************* + public static void twoResultSets(double inSalaryThreshold, + ResultSet[] outRs1, + ResultSet[] outRs2) + throws SQLException + { + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + try + { + // get caller's connection to the database + errorLabel = "GET CONNECTION"; + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + errorLabel = "SELECT STATEMENT 1"; + + // set the SQL statement that will return the desired result set + String query1 = + "SELECT name, job, CAST(salary AS DOUBLE) FROM staff " + + " WHERE salary > ? " + + " ORDER BY salary"; + + // prepare the SQL statement + PreparedStatement stmt1 = con.prepareStatement(query1); + + // set the value of the parameter marker (?) + stmt1.setDouble(1, inSalaryThreshold); + + // get the result set that will be returned to the client + outRs1[0] = stmt1.executeQuery(); + + errorLabel = "SELECT STATEMENT 2"; + + // set the SQL statement that will return the desired result set + String query2 = + "SELECT name, job, CAST(salary AS DOUBLE) FROM staff " + + " WHERE salary < ? " + + " ORDER BY salary DESC"; + + // prepare the SQL statement + PreparedStatement stmt2 = con.prepareStatement(query2); + + // set the value of the parameter marker (?) + stmt2.setDouble(1, inSalaryThreshold); + + // get the result set that will be returned to the client + outRs2[0] = stmt2.executeQuery(); + + // to return the result sets to the client, do not close the ResultSets + con.close(); + } + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + throw new SQLException( errorCode + " : " + errorLabel + " FAILED" ); + } + } // twoResultSets + + //************************************************************************* + // PARAMETER STYLE GENERAL and GENERAL WITH NULLS can be specified when + // LANGUAGE C, COBOL, or CLR is used. + // Please see the SpClient implementation for C/C++/CLI language to see + // this functionality. + //************************************************************************* + +} // SpServer diff --git a/java/jdbc/TbAST.java b/java/jdbc/TbAST.java new file mode 100644 index 0000000..dce4aa1 --- /dev/null +++ b/java/jdbc/TbAST.java @@ -0,0 +1,376 @@ +//************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +// ************************************************************************* +// +// SOURCE FILE NAME: TbAST.java +// +// SAMPLE: How to use staging table for updating deferred AST +// +// This sample: +// 1. Creates a refresh-deferred summary table +// 2. Creates a staging table for this summary table +// 3. Applies contents of staging table to AST +// 4. Restores the data in a summary table +// +// SQL STATEMENTS USED: +// CREATE SUMMARY TABLE +// DROP +// INSERT +// REFRESH +// SET INTEGRITY +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbAST.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//************************************************************************** + +import java.lang.*; +import java.sql.*; + +class TbAST +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS THE USAGE OF STAGING TABLE TO UPDATE \n" + + "REFRESH DEFERRED AST AND RESTORE DATA IN A SUMMARY TABLE \n" + + "\n-----------------------------------------------------------\n"); + + // connect to database + db.connect(); + + // create a base table, summary table, staging table + createStagingTable(db.con); + + // to show the propagation of changes of base table to + // summary tables through the staging table + System.out.println( + "\n-----------------------------------------------------------\n" + + "To show the propagation of changes from base table to \n" + + "summary tables through the staging table: \n" ); + propagateStagingToAst(db.con); + + // to show restoring of data in a summary table + System.out.println( + "\n------------------------------------------------------------ \n" + + "To show restoring of data in a summary table"); + restoreSummaryTable(db.con); + + // drop the created tables + System.out.println( + "\n------------------------------------------------------------ \n" + + "Drop the created tables"); + dropTables(db.con); + + // disconnect from 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // main + + // Creates base table, summary table and staging table + static void createStagingTable(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + //create base table + System.out.println( + "\nUSE THE SQL STATEMENT: \n" + + " CREATE TABLE \n" + + "To create base table, summary table, staging table\n" + + "\nCreating the base table t\n" + + " CREATE TABLE t \n" + + " (c1 SMALLINT NOT NULL,\n" + + " c2 SMALLINT NOT NULL, \n" + + " c3 SMALLINT, \n" + + " c4 SMALLINT)\n"); + stmt.executeUpdate( + " CREATE TABLE t " + + " (c1 SMALLINT NOT NULL, " + + " c2 SMALLINT NOT NULL, " + + " c3 SMALLINT, " + + " c4 SMALLINT)"); + System.out.println(" COMMIT"); + con.commit(); + + // create summary table + System.out.println( + "\nCreating summary table d_ast \n" + + " CREATE SUMMARY TABLE d_ast AS\n" + + " (SELECT c1, c2, COUNT(*) AS count\n" + + " FROM t\n" + + " GROUP BY c1, c2)\n" + + " DATA INITIALLY DEFERRED\n" + + " REFRESH DEFERRED \n"); + stmt.executeUpdate( + "CREATE SUMMARY TABLE d_ast AS " + + " (SELECT c1, c2, COUNT(*) AS count " + + " FROM t " + + " GROUP BY c1, c2) " + + " DATA INITIALLY DEFERRED " + + " REFRESH DEFERRED "); + System.out.println(" COMMIT"); + con.commit(); + + // create staging table + System.out.println( + "\nCreating the staging table g \n" + + " CREATE TABLE g FOR d_ast PROPAGATE IMMEDIATE"); + stmt.executeUpdate("CREATE TABLE g FOR d_ast PROPAGATE IMMEDIATE"); + System.out.println("\n COMMIT"); + con.commit(); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // createStagingTable + + // Show how to propagate the changes from base table to + // summary tables through the staging table + static void propagateStagingToAst(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "Bring staging table out of pending state \n" + + " SET INTEGRITY FOR g IMMEDIATE CHECKED"); + stmt.executeUpdate("SET INTEGRITY FOR g IMMEDIATE CHECKED"); + con.commit(); + + System.out.println( + "\nRefresh summary table, get it out of pending state. \n" + + " REFRESH TABLE d_ast NOT INCREMENTAL"); + stmt.executeUpdate("REFRESH TABLE d_ast NOT INCREMENTAL"); + con.commit(); + + System.out.println( + "\nInsert data into base table T\n" + + " INSERT INTO t VALUES(1,1,1,1), \n" + + " (2,2,2,2), \n" + + " (1,1,1,1), \n" + + " (3,3,3,3)"); + stmt.executeUpdate( + "INSERT INTO t VALUES(1,1,1,1)," + + " (2,2,2,2)," + + " (1,1,1,1)," + + " (3,3,3,3)"); + con.commit(); + + System.out.println( + "\nDisplay the contents of staging table g.\n" + + "The Staging table contains incremental changes to base table.\n"); + displayTable(con, "g"); + + System.out.println( + "\n\nRefresh the summary table \n" + + " REFRESH TABLE d_ast INCREMENTAL"); + stmt.executeUpdate("REFRESH TABLE d_ast INCREMENTAL"); + con.commit(); + + System.out.println( + "\nDisplay the contents of staging table g \n" + + " NOTE: The staging table is pruned after AST is \n" + + " refreshed. The contents are propagated to AST \n" + + " from the staging table\n"); + displayTable(con, "g"); + + System.out.println( + "\nDisplay the contents of AST\n" + + "Summary table has the changes propagated from staging table\n"); + displayTable(con, "d_ast"); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // propagateStagingToAst + + // Shows how to restore the data in a summary table + static void restoreSummaryTable(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "\nBlock all modifications to the summary table \n" + + "by setting the integrity to off \n" + + " (g is placed in pending and g.CC=N) \n" + + " SET INTEGRITY FOR g OFF"); + stmt.executeUpdate("SET INTEGRITY FOR g OFF"); + con.commit(); + + System.out.println( + "\nExport the query definition in summary table and load \n" + + "directly back to the summary table.\n" + + " (d_ast and g both in pending \n" + + " SET INTEGRITY FOR d_ast OFF CASCADE IMMEDIATE\n"); + stmt.executeUpdate("SET INTEGRITY FOR d_ast OFF CASCADE IMMEDIATE"); + con.commit(); + + System.out.println( + "Prune staging table and place it in normal state\n" + + " (g.CC=F)\n" + + " SET INTEGRITY FOR g IMMEDIATE CHECKED PRUNE\n"); + stmt.executeUpdate("SET INTEGRITY FOR g IMMEDIATE CHECKED PRUNE"); + con.commit(); + + System.out.println( + "Changing staging table state to U \n" + + " (g.CC to U)\n" + + " SET INTEGRITY FOR g STAGING IMMEDIATE UNCHECKED"); + stmt.executeUpdate("SET INTEGRITY FOR g STAGING IMMEDIATE UNCHECKED"); + con.commit(); + + System.out.println( + "\nPlace d_ast in normal and d_ast.CC to U \n" + + " SET INTEGRITY FOR d_ast MATERIALIZED QUERY IMMEDIATE UNCHECKED"); + stmt.executeUpdate( + "SET INTEGRITY FOR d_ast MATERIALIZED QUERY IMMEDIATE UNCHECKED"); + con.commit(); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // restoreSummaryTable + + // Displays the contents of the table being passed as the argument + static void displayTable(Connection con, String tableName) + { + try + { + Statement stmt = con.createStatement(); + String sqlString = null; + ResultSet rs; + int c1 = 0; + int c2 = 0; + int count = 0; + + if (tableName.equals("g")) + { + sqlString = " SELECT c1, c2, count FROM g" ; + } + else if (tableName.equals("d_ast")) + { + sqlString = " SELECT c1, c2, count FROM d_ast" ; + } + + rs = stmt.executeQuery(sqlString); + System.out.println( + sqlString + + "\n\n C1 C2 COUNT " + + "\n ------------------"); + + while (rs.next()) + { + c1 = rs.getInt("c1"); + c2 = rs.getInt("c2"); + count = rs.getInt("count"); + + System.out.println(" " + c1 + " " + c2 + " " + count ); + } + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // displayTable + + // Drops the staging table, summary table and base table + static void dropTables(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "\nDropping a base table implicitly drops summary table defined \n" + + "on it which in turn cascades to dropping its staging table. \n" + + "\nUSE THE SQL STATEMENT:\n" + + " DROP TABLE \n" + + "To drop a table \n\n" + + " DROP TABLE t \n"); + stmt.executeUpdate("DROP TABLE t"); + System.out.println(" COMMIT"); + con.commit(); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // dropTables +} // TbAST diff --git a/java/jdbc/TbCompress.java b/java/jdbc/TbCompress.java new file mode 100644 index 0000000..a71da9f --- /dev/null +++ b/java/jdbc/TbCompress.java @@ -0,0 +1,214 @@ +//************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************** +// +// SOURCE FILE NAME: TbCompress.java +// +// SAMPLE: How to create tables with null and default value compression +// option. +// +// SQL STATEMENTS USED: +// CREATE TABLE +// ALTER TABLE +// DROP TABLE +// +// JAVA 2 CLASSES USED: +// Statement +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbCompress.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//************************************************************************** + +import java.lang.*; +import java.sql.*; + +class TbCompress +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO USE NULL AND DEFAULT VALUE\n" + + "COMPRESSION OPTION AT TABLE LEVEL AND COLUMN LEVEL \n"); + + // connect to database + db.connect(); + + // create a new table + tbCreate(db.con); + + // activate null and default value compression + tbCompress(db.con); + + // drop the table created + tbDrop(db.con); + + // disconnect from 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // main + + // create a new table + static void tbCreate(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + // create base table + System.out.println( + "\n-----------------------------------------------------------\n" + + "USE THE SQL STATEMENT \n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n\n" + + " CREATE TABLE comp_tab(col1 INT NOT NULL WITH DEFAULT,\n" + + " col2 CHAR(7),\n" + + " col3 VARCHAR(7) NOT NULL,\n" + + " col4 DOUBLE) \n"); + stmt.executeUpdate( + "CREATE TABLE comp_tab(col1 INT NOT NULL WITH DEFAULT," + + " col2 CHAR(7)," + + " col3 VARCHAR(7) NOT NULL," + + " col4 DOUBLE)"); + System.out.println(" COMMIT"); + con.commit(); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // tbCreate + + // activate null and default value compression + static void tbCompress(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "\n-----------------------------------------------------------\n" + + "USE THE SQL STATEMENT \n" + + " ALTER TABLE \n" + + "TO ALTER COMPRESSION OPTIONS OF THE TABLE\n\n" + + "To activate VALUE COMPRESSION at table level and COMPRESS \n" + + "SYSTEM DEFAULT at column level \n\n" + + " ALTER TABLE comp_tab ACTIVATE VALUE COMPRESSION \n\n" + + "Rows will be formatted using the new row format on subsequent\n" + + "insert, load and update operation, and NULL values will not be\n" + + "taking up space if applicable.\n"); + + // if the table comp_tab does not have many NULL values, enabling + // compression will result in using more disk space than using + // the old row format + stmt.executeUpdate("ALTER TABLE comp_tab ACTIVATE VALUE COMPRESSION"); + con.commit(); + + System.out.println( + "\nTo save more disk space on system default value for column\n" + + "col1, enter\n" + + "\n ALTER TABLE comp_tab ALTER col1 COMPRESS SYSTEM DEFAULT\n" + + "\nOn subsequent insert, load, and update operations, numerical\n" + + "0 value (occupying 4 bytes of storage) for column col1 will\n" + + "not be saved on disk.\n"); + stmt.executeUpdate("ALTER TABLE comp_tab "+ + " ALTER col1 COMPRESS SYSTEM DEFAULT"); + con.commit(); + + System.out.println( + "\nTo switch the table to use the old format, enter\n\n" + + " ALTER TABLE comp_tab DEACTIVATE VALUE COMPRESSION\n\n" + + "Rows inserted, loaded or updated after the ALTER statement\n" + + "will have old row format."); + stmt.executeUpdate( "ALTER TABLE comp_tab " + + " DEACTIVATE VALUE COMPRESSION"); + con.commit(); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // tbCompress + + // drop the table created + static void tbDrop(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + // drop the table + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT\n" + + " DROP TABLE\n" + + "TO DROP THE TABLE\n\n" + + " DROP TABLE comp_tab\n"); + stmt.executeUpdate("DROP TABLE comp_tab"); + System.out.println("\n COMMIT"); + con.commit(); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e) ; + jdbcExc.handle(); + } + } // tbDrop +} // TbCompress diff --git a/java/jdbc/TbConstr.java b/java/jdbc/TbConstr.java new file mode 100644 index 0000000..01f6726 --- /dev/null +++ b/java/jdbc/TbConstr.java @@ -0,0 +1,1473 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbConstr.java +// +// SAMPLE: How to create, use and drop constraints +// +// SQL Statements USED: +// CREATE TABLE +// DROP TABLE +// DELETE +// COMMIT +// ROLLBACK +// INSERT +// ALTER +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbConstr.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbConstr +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CREATE, USE AND DROP CONSTRAINTS.\n"); + + // connect to the 'sample' database + db.connect(); + + demo_NOT_NULL(db.con); + demo_UNIQUE(db.con); + demo_PRIMARY_KEY(db.con); + demo_CHECK(db.con); + demo_CHECK_INFO(db.con); + demo_WITH_DEFAULT(db.con); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "#####################################################\n" + + "# Create tables for FOREIGN KEY sample functions #\n" + + "#####################################################"); + + FK_TwoTablesCreate(db.con); + + demo_FK_OnInsertShow(db.con); + demo_FK_ON_UPDATE_NO_ACTION(db.con); + demo_FK_ON_UPDATE_RESTRICT(db.con); + demo_FK_ON_DELETE_CASCADE(db.con); + demo_FK_ON_DELETE_SET_NULL(db.con); + demo_FK_ON_DELETE_NO_ACTION(db.con); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "########################################################\n" + + "# Drop tables created for FOREIGN KEY sample functions #\n" + + "########################################################"); + FK_TwoTablesDrop(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // helping function: This function creates two foreign keys + static void FK_TwoTablesCreate(Connection con) + { + try + { + System.out.println(); + System.out.println( + " CREATE TABLE deptmt(deptno CHAR(3) NOT NULL,\n" + + " deptname VARCHAR(20),\n" + + " CONSTRAINT pk_dept\n" + + " PRIMARY KEY(deptno))"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE deptmt(deptno CHAR(3) NOT NULL, " + + " deptname VARCHAR(20), " + + " CONSTRAINT pk_dept " + + " PRIMARY KEY(deptno))"); + stmt.close(); + + System.out.println(); + System.out.println( + " INSERT INTO deptmt VALUES('A00', 'ADMINISTRATION'),\n" + + " ('B00', 'DEVELOPMENT'),\n" + + " ('C00', 'SUPPORT')"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO deptmt VALUES('A00', 'ADMINISTRATION'), " + + " ('B00', 'DEVELOPMENT'), " + + " ('C00', 'SUPPORT') "); + stmt1.close(); + + System.out.println(); + System.out.println( + " CREATE TABLE empl(empno CHAR(4),\n" + + " empname VARCHAR(10),\n" + + " dept_no CHAR(3))"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("CREATE TABLE empl(empno CHAR(4), " + + " empname VARCHAR(10), " + + " dept_no CHAR(3))"); + stmt2.close(); + + System.out.println(); + System.out.println( + " INSERT INTO empl VALUES('0010', 'Smith', 'A00'),\n" + + " ('0020', 'Ngan', 'B00'),\n" + + " ('0030', 'Lu', 'B00'),\n" + + " ('0040', 'Wheeler', 'B00'),\n" + + " ('0050', 'Burke', 'C00'),\n" + + " ('0060', 'Edwards', 'C00'),\n" + + " ('0070', 'Lea', 'C00')"); + + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate( + "INSERT INTO empl VALUES('0010', 'Smith', 'A00'), " + + " ('0020', 'Ngan', 'B00'), " + + " ('0030', 'Lu', 'B00'), " + + " ('0040', 'Wheeler', 'B00'), " + + " ('0050', 'Burke', 'C00'), " + + " ('0060', 'Edwards', 'C00'), " + + " ('0070', 'Lea', 'C00') "); + stmt3.close(); + + System.out.println("\n COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // FK_TwoTablesCreate + + // helping function + static void FK_TwoTablesDisplay(Connection con) + { + try + { + System.out.println(); + System.out.println(" SELECT * FROM deptmt"); + System.out.println(" DEPTNO DEPTNAME\n" + + " ------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM deptmt"); + + while (rs.next()) + { + System.out.println(" " + + Data.format(rs.getString("deptno"),7) + " " + + Data.format(rs.getString("deptname"),20)); + } + rs.close(); + stmt.close(); + + System.out.println(); + System.out.println(" SELECT * FROM empl"); + System.out.println(" EMPNO EMPNAME DEPT_NO\n" + + " ----- ---------- -------"); + + Statement stmt1 = con.createStatement(); + ResultSet rs1 = stmt1.executeQuery("SELECT * FROM empl"); + + while (rs1.next()) + { + System.out.print(" " + + Data.format(rs1.getString("empno"),5) + " " + + Data.format(rs1.getString("empname"),10)); + String deptNo = rs1.getString("dept_no"); + if (deptNo !=null) + { + System.out.print(" " + Data.format(deptNo,3)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + rs1.close(); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // FK_TwoTablesDisplay + + // helping function + static void FK_TwoTablesDrop(Connection con) + { + try + { + System.out.println(); + System.out.println(" DROP TABLE deptmt"); + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE deptmt"); + stmt.close(); + + System.out.println(); + System.out.println(" DROP TABLE empl"); + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("DROP TABLE empl"); + stmt1.close(); + + System.out.println("\n COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // FK_TwoTablesDrop + + + // helping function + static void FK_Create(String ruleClause, Connection con) + { + try + { + System.out.println(); + System.out.println(" ALTER TABLE empl\n" + + " ADD CONSTRAINT fk_dept\n" + + " FOREIGN KEY(dept_no)\n" + + " REFERENCES deptmt(deptno)\n" + + " " + ruleClause); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("ALTER TABLE empl " + + " ADD CONSTRAINT fk_dept " + + " FOREIGN KEY(dept_no) " + + " REFERENCES deptmt(deptno) " + + ruleClause); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // FK_Create + + + // helping function + static void FK_Drop(Connection con) + { + try + { + System.out.println(); + System.out.println(" ALTER TABLE empl DROP CONSTRAINT fk_dept"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("ALTER TABLE empl DROP CONSTRAINT fk_dept"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // FK_Drop + + // This function demonstrates how to use a 'NOT NULL' constraint. + static void demo_NOT_NULL(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " DROP TABLE\n" + + "TO SHOW A 'NOT NULL' CONSTRAINT."); + + // Create a table called empl_sal with a 'NOT NULL' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE empl_sal(lastname VARCHAR(10) NOT NULL,\n" + + " firstname VARCHAR(10),\n" + + " salary DECIMAL(7, 2))"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE empl_sal(lastname VARCHAR(10) NOT NULL, " + + " firstname VARCHAR(10), " + + " salary DECIMAL(7, 2))"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // Insert a row in the table empl_sal with NULL as the lastname. + // This insert will fail with an expected error. + try + { + String strStmt; + System.out.println(); + System.out.println( + " INSERT INTO empl_sal VALUES(NULL, 'PHILIP', 17000.00)"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO empl_sal VALUES(NULL, 'PHILIP', 17000.00) "); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // drop the table empl_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE empl_sal"); + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("DROP TABLE empl_sal"); + stmt2.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demo_NOT_NULL + + // This function demonstrates how to use a 'UNIQUE' constraint. + static void demo_UNIQUE(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ALTER TABLE\n" + + " DROP TABLE\n" + + "TO SHOW A 'UNIQUE' CONSTRAINT."); + + // Create a table called empl_sal with a 'UNIQUE' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE empl_sal(lastname VARCHAR(10) NOT NULL,\n" + + " firstname VARCHAR(10) NOT NULL,\n" + + " salary DECIMAL(7, 2),\n" + + " CONSTRAINT unique_cn\n" + + " UNIQUE(lastname, firstname))"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE empl_sal(lastname VARCHAR(10) NOT NULL, " + + " firstname VARCHAR(10) NOT NULL, " + + " salary DECIMAL(7, 2), " + + " CONSTRAINT unique_cn " + + " UNIQUE(lastname, firstname))"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // Insert two rows into the table empl_sal that have the same lastname + // and firstname values. The insert will fail with an expected error + // because the rows violate the PRIMARY KEY constraint. + try + { + System.out.println(); + System.out.println( + " INSERT INTO empl_sal VALUES('SMITH', 'PHILIP', 17000.00),\n" + + " ('SMITH', 'PHILIP', 21000.00)"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO empl_sal VALUES('SMITH', 'PHILIP', 17000.00), " + + " ('SMITH', 'PHILIP', 21000.00) "); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // drop the 'UNIQUE' constraint on the table empl_sal + try + { + System.out.println(); + System.out.println( + " ALTER TABLE empl_sal DROP CONSTRAINT unique_cn"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "ALTER TABLE empl_sal DROP CONSTRAINT unique_cn "); + stmt2.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop the table empl_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE empl_sal"); + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate("DROP TABLE empl_sal"); + stmt3.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demo_UNIQUE + + // This function demonstrates how to use a 'PRIMARY KEY' constraint. + static void demo_PRIMARY_KEY(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ALTER TABLE\n" + + " DROP TABLE\n" + + "TO SHOW A 'PRIMARY KEY' CONSTRAINT."); + + // Create a table called empl_sal with a 'PRIMARY KEY' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE empl_sal(lastname VARCHAR(10) NOT NULL,\n" + + " firstname VARCHAR(10) NOT NULL,\n" + + " salary DECIMAL(7, 2),\n" + + " CONSTRAINT pk_cn\n" + + " PRIMARY KEY(lastname, firstname))"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE empl_sal(lastname VARCHAR(10) NOT NULL, " + + " firstname VARCHAR(10) NOT NULL, " + + " salary DECIMAL(7, 2), " + + " CONSTRAINT pk_cn " + + " PRIMARY KEY(lastname, firstname))"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // Insert two rows into the table empl_sal that have the same lastname + // and firstname values. The insert will fail with an expected error + // because the rows violate the PRIMARY KEY constraint. + try + { + System.out.println(); + System.out.println( + " INSERT INTO empl_sal VALUES('SMITH', 'PHILIP', 17000.00),\n" + + " ('SMITH', 'PHILIP', 21000.00)"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO empl_sal VALUES('SMITH', 'PHILIP', 17000.00)," + + " ('SMITH', 'PHILIP', 21000.00) "); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // drop the 'PRIMARY KEY' constraint on the table empl_sal + try + { + System.out.println(); + System.out.println(" ALTER TABLE empl_sal DROP CONSTRAINT pk_cn"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("ALTER TABLE empl_sal DROP CONSTRAINT pk_cn"); + stmt2.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop the table empl_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE empl_sal"); + + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate("DROP TABLE empl_sal"); + stmt3.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demo_PRIMARY_KEY + + // This function demonstrates how to use a 'CHECK' constraint. + static void demo_CHECK(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ALTER TABLE\n" + + " DROP TABLE\n" + + "TO SHOW A 'CHECK' CONSTRAINT."); + + // Create a table called empl_sal with a 'CHECK' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE empl_sal(lastname VARCHAR(10),\n" + + " firstname VARCHAR(10),\n" + + " salary DECIMAL(7, 2),\n" + + " CONSTRAINT check_cn\n" + + " CHECK(salary < 25000.00))"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE empl_sal(lastname VARCHAR(10), " + + " firstname VARCHAR(10), " + + " salary DECIMAL(7, 2), " + + " CONSTRAINT check_cn " + + " CHECK(salary < 25000.00))"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // Insert a row in the table empl_sal that violates the rule defined + // in the 'CHECK' constraint. This insert will fail with an expected + // error. + try + { + System.out.println(); + System.out.println( + " INSERT INTO empl_sal VALUES('SMITH', 'PHILIP', 27000.00)"); + + Statement stmt1 = con.createStatement(); + stmt1.execute( + "INSERT INTO empl_sal VALUES('SMITH', 'PHILIP', 27000.00)"); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // drop the 'CHECK' constraint on the table empl_sal + try + { + System.out.println(); + System.out.println(" ALTER TABLE empl_sal DROP CONSTRAINT check_cn"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "ALTER TABLE empl_sal DROP CONSTRAINT check_cn"); + stmt2.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop the table empl_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE empl_sal"); + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate("DROP TABLE empl_sal"); + stmt3.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demo_CHECK + + // This function demonstrates how to use an 'INFORMATIONAL' constraint. + static void demo_CHECK_INFO(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ALTER TABLE\n" + + " DROP TABLE\n" + + "TO SHOW AN 'INFORMATIONAL' CONSTRAINT."); + + // create a table called empl with a 'CHECK' constraint + System.out.println( + "\n CREATE TABLE empl(empno INTEGER NOT NULL PRIMARY KEY,\n" + + " name VARCHAR(10),\n" + + " firstname VARCHAR(20),\n" + + " salary INTEGER CONSTRAINT minsalary\n" + + " CHECK (salary >= 25000)\n" + + " NOT ENFORCED\n" + + " ENABLE QUERY OPTIMIZATION)\n"); + stmt.executeUpdate( + "CREATE TABLE empl(empno INTEGER NOT NULL PRIMARY KEY," + + " name VARCHAR(10)," + + " firstname VARCHAR(20)," + + " salary INTEGER CONSTRAINT minsalary" + + " CHECK (salary >= 25000)" + + " NOT ENFORCED" + + " ENABLE QUERY OPTIMIZATION)"); + + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + // insert data that doesn't satisfy the constraint 'minsalary'. + // database manager does not enforce the constraint for IUD operations + System.out.println( + "\n\nTO SHOW NOT ENFORCED OPTION\n" + + "\n INSERT INTO empl VALUES(1, 'SMITH', 'PHILIP', 1000)\n"); + + stmt.executeUpdate( + "INSERT INTO empl VALUES(1, 'SMITH', 'PHILIP', 1000)"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + // alter the constraint to make it ENFORCED by database manager + System.out.println( + "Alter the constraint to make it ENFORCED by database manager\n" + + "\n ALTER TABLE empl ALTER CHECK minsalary ENFORCED"); + + stmt.executeUpdate( + "ALTER TABLE empl ALTER CHECK minsalary ENFORCED"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + try + { + // delete entries from EMP Table + System.out.println("\n DELETE FROM empl"); + + stmt.executeUpdate("DELETE FROM empl"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + // alter the constraint to make it ENFORCED by database manager + System.out.println( + "\n\nTO SHOW ENFORCED OPTION\n" + + "\n ALTER TABLE empl ALTER CHECK minsalary ENFORCED\n "); + + stmt.executeUpdate("ALTER TABLE empl ALTER CHECK minsalary ENFORCED"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + // insert table with data not conforming to the constraint 'minsalary' + // database manager enforces the constraint for IUD operations + System.out.println( + " INSERT INTO empl VALUES(1, 'SMITH', 'PHILIP', 1000)"); + + stmt.executeUpdate( + "INSERT INTO empl VALUES(1, 'SMITH', 'PHILIP', 1000)"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + try + { + // drop table + System.out.println("\n DROP TABLE empl"); + + stmt.executeUpdate("DROP TABLE empl"); + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demo_CHECK_INFO + + // This function demonstrates how to use a 'WITH DEFAULT' constraint. + static void demo_WITH_DEFAULT(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " DROP TABLE\n" + + "TO SHOW A 'WITH DEFAULT' CONSTRAINT."); + + // Create a table called empl_sal with a 'WITH DEFAULT' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE empl_sal(lastname VARCHAR(10),\n" + + " firstname VARCHAR(10),\n" + + " salary DECIMAL(7, 2) " + + "WITH DEFAULT 17000.00)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE empl_sal(lastname VARCHAR(10), " + + " firstname VARCHAR(10), " + + " salary DECIMAL(7, 2) WITH DEFAULT 17000.00)"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // Insert three rows into the table empl_sal, without any value for the + // the third column. Since the third column is defined with a default + // value of 17000.00, the third column for each of these three rows + // will be set to 17000.00. + try + { + String strStmt; + System.out.println(); + System.out.println(" INSERT INTO empl_sal(lastname, firstname)\n" + + " VALUES('SMITH', 'PHILIP'),\n" + + " ('PARKER', 'JOHN'),\n" + + " ('PEREZ', 'MARIA')"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("INSERT INTO empl_sal(lastname, firstname) " + + " VALUES('SMITH' , 'PHILIP'), " + + " ('PARKER', 'JOHN'), " + + " ('PEREZ' , 'MARIA') "); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // retrieve and display the data in the table empl_sal + try + { + String strStmt; + System.out.println(); + System.out.println(" SELECT * FROM empl_sal"); + System.out.println(" FIRSTNAME LASTNAME SALARY\n" + + " ---------- ---------- --------"); + + Statement stmt2 = con.createStatement(); + ResultSet rs = stmt2.executeQuery("SELECT * FROM empl_sal"); + + while (rs.next()) + { + System.out.println(" " + + Data.format(rs.getString("firstname"),10) + " " + + Data.format(rs.getString("lastname"),10) + " " + + Data.format(rs.getDouble("salary"),7,2)); + } + rs.close(); + stmt2.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop the table empl_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE empl_sal"); + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate("DROP TABLE empl_sal"); + stmt3.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demo_WITH_DEFAULT + + // This function demonstrates how to insert into a foreign key + static void demo_FK_OnInsertShow(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ROLLBACK\n" + + "TO SHOW HOW A FOREIGN KEY WORKS ON INSERT."); + + // display the initial content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // create a foreign key on the 'empl' table that reference the 'deptmt' + // table + FK_Create("", con); + + // insert an entry into the parent table, 'deptmt' + try + { + System.out.println(); + System.out.println(" INSERT INTO deptmt VALUES('D00', 'SALES')"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO deptmt VALUES('D00', 'SALES')"); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // insert an entry into the child table, 'empl' + try + { + System.out.println(); + System.out.println( + " INSERT INTO empl VALUES('0080', 'Pearce', 'E03')"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO empl VALUES('0080', 'Pearce', 'E03')"); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // display the final content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + con.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + } // demo_FK_OnInsertShow + + // This function demonstrates how to use an 'ON UPDATE NO ACTION' + // foreign key + static void demo_FK_ON_UPDATE_NO_ACTION(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " UPDATE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON UPDATE NO ACTION' FOREIGN KEY."); + + // display the initial content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // create an 'ON UPDATE NO ACTION' foreign key + FK_Create("ON UPDATE NO ACTION", con); + + // update parent table + try + { + System.out.println(); + System.out.println( + " UPDATE deptmt SET deptno = 'E01' WHERE deptno = 'A00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE deptmt SET deptno = 'E01' WHERE deptno = 'A00' "); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // update the parent table, 'deptmt' + try + { + System.out.println(); + System.out.println( + " UPDATE deptmt\n" + + " SET deptno = CASE\n" + + " WHEN deptno = 'A00' THEN 'B00'\n" + + " WHEN deptno = 'B00' THEN 'A00'\n" + + " END\n" + + " WHERE deptno = 'A00' OR deptno = 'B00'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "UPDATE deptmt " + + " SET deptno = CASE " + + " WHEN deptno = 'A00' THEN 'B00' " + + " WHEN deptno = 'B00' THEN 'A00' " + + " END " + + " WHERE deptno = 'A00' OR deptno = 'B00' "); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // update the child table, 'empl' + try + { + System.out.println(); + System.out.println( + " UPDATE empl SET dept_no = 'G11' WHERE empname = 'Wheeler'"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "UPDATE empl SET dept_no = 'G11' WHERE empname = 'Wheeler' "); + stmt2.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // display the final content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + con.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + } // demo_FK_ON_UPDATE_NO_ACTION + + // This function demonstrates how to use an 'ON UPDATE RESTRICT' + // foreign key + static void demo_FK_ON_UPDATE_RESTRICT(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " UPDATE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON UPDATE RESTRICT' FOREIGN KEY."); + + // display the initial content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // create an 'ON UPDATE RESTRICT' foreign key + FK_Create("ON UPDATE RESTRICT", con); + + // update the parent table, 'deptmt', with data that violates the 'ON + // UPDATE RESTRICT' foreign key. An error is expected to be returned. + try + { + System.out.println(); + System.out.println( + " UPDATE deptmt SET deptno = 'E01' WHERE deptno = 'A00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE deptmt SET deptno = 'E01' WHERE deptno = 'A00' "); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // update the parent table, 'deptmt', with data that violates the 'ON + // UPDATE RESTRICT' foreign key. An error is expected to be returned. + try + { + System.out.println(); + System.out.println( + " UPDATE deptmt\n" + + " SET deptno = CASE\n" + + " WHEN deptno = 'A00' THEN 'B00'\n" + + " WHEN deptno = 'B00' THEN 'A00'\n" + + " END\n" + + " WHERE deptno = 'A00' OR deptno = 'B00'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "UPDATE deptmt " + + " SET deptno = CASE " + + " WHEN deptno = 'A00' THEN 'B00' " + + " WHEN deptno = 'B00' THEN 'A00' " + + " END " + + " WHERE deptno = 'A00' OR deptno = 'B00' "); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // update the child table, 'empl', with data that violates the 'ON + // UPDATE RESTRICT' foreign key. An error is expected to be returned. + try + { + System.out.println(); + System.out.println( + " UPDATE empl SET dept_no = 'G11' WHERE empname = 'Wheeler'"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "UPDATE empl SET dept_no = 'G11' WHERE empname = 'Wheeler' "); + stmt2.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // display the final content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + con.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + + } // demo_FK_ON_UPDATE_RESTRICT + + // This function demonstrates how to use an 'ON DELETE CASCADE' foreign key + static void demo_FK_ON_DELETE_CASCADE(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " DELETE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON DELETE CASCADE' FOREIGN KEY."); + + // display the initial content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // create an 'ON DELETE CASCADE' foreign key + FK_Create("ON DELETE CASCADE", con); + + // delete from the parent table, 'deptmt' + try + { + System.out.println(); + System.out.println(" DELETE FROM deptmt WHERE deptno = 'C00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DELETE FROM deptmt WHERE deptno = 'C00' "); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // delete from the child table, 'empl' + try + { + System.out.println(); + System.out.println(" DELETE FROM empl WHERE empname = 'Wheeler'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DELETE FROM empl WHERE empname = 'Wheeler' "); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the final content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + con.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + + } // demo_FK_ON_DELETE_CASCADE + + // This function demonstrates how to use an 'ON DELETE SET NULL' + // foreign key + static void demo_FK_ON_DELETE_SET_NULL(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " DELETE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON DELETE SET NULL' FOREIGN KEY."); + + // display the initial content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // create an 'ON DELETE SET NULL' foreign key + FK_Create("ON DELETE SET NULL", con); + + // delete from the parent table, 'deptmt' + try + { + System.out.println(); + System.out.println(" DELETE FROM deptmt WHERE deptno = 'C00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DELETE FROM deptmt WHERE deptno = 'C00' "); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // delete from the child table, 'empl' + try + { + System.out.println(); + System.out.println(" DELETE FROM empl WHERE empname = 'Wheeler'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("DELETE FROM empl WHERE empname = 'Wheeler' "); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the final content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + con.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + + } // demo_FK_ON_DELETE_SET_NULL + + // This function demonstrates how to use an 'ON DELETE NO ACTION' + // foreign key + static void demo_FK_ON_DELETE_NO_ACTION(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " DELETE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON DELETE NO ACTION' FOREIGN KEY."); + + // display the initial content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // create an 'ON DELETE NO ACTION' foreign key + FK_Create("ON DELETE NO ACTION", con); + + // delete from the parent table, 'deptmt' + try + { + System.out.println(); + System.out.println(" DELETE FROM deptmt WHERE deptno = 'C00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DELETE FROM deptmt WHERE deptno = 'C00' "); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + // delete from the child table, 'empl' + try + { + System.out.println(); + System.out.println(" DELETE FROM empl WHERE empname = 'Wheeler'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("DELETE FROM empl WHERE empname = 'Wheeler' "); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the final content of the 'deptmt' and 'empl' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + con.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + } // demo_FK_ON_DELETE_NO_ACTION +} // TbConstr + diff --git a/java/jdbc/TbCreate.java b/java/jdbc/TbCreate.java new file mode 100644 index 0000000..f576679 --- /dev/null +++ b/java/jdbc/TbCreate.java @@ -0,0 +1,169 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbCreate.java +// +// SAMPLE: How to create and drop tables +// +// SQL Statements USED: +// CREATE TABLE +// DROP TABLE +// COMMIT +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbCreate.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbCreate +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + String tableName; + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO CREATE AND DROP TABLES."); + + // connect to the 'sample' database + db.connect(); + + create(db.con); + drop(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // This function demonstrates how to create a table with different + // data types for each column. + static void create(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT\n" + + " CREATE TABLE\n" + + "TO CREATE A TABLE."); + + // create a table called 'tbname' under the schema 'schname' + try + { + System.out.println(); + System.out.println( + " Execute the statement:\n" + + " CREATE TABLE schname.tbname(Col1 SMALLINT,\n" + + " Col2 CHAR(7),\n" + + " Col3 VARCHAR(7),\n" + + " Col4 DEC(9,2),\n" + + " Col5 DATE,\n" + + " Col6 BLOB(5000),\n" + + " Col7 CLOB(5000))"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE schname.tbname(col1 SMALLINT, " + + " col2 CHAR(7), " + + " col3 VARCHAR(7) , " + + " col4 DEC(9,2), " + + " col5 DATE, " + + " col6 BLOB(5000), " + + " col7 CLOB(5000)) "); + stmt.close(); + + // commit the transaction + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // create + + // This function demonstrates how to drop a table in a specific schema + static void drop(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT\n" + + " DROP TABLE\n" + + "TO DROP A TABLE."); + + // drop the table 'tbname' that is under the schema 'schname' + try + { + System.out.println(); + System.out.println(" Execute the statement:\n" + + " DROP TABLE schname.tbname"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE schname.tbname"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // drop +} // TbCreate + diff --git a/java/jdbc/TbGenCol.java b/java/jdbc/TbGenCol.java new file mode 100644 index 0000000..2896883 --- /dev/null +++ b/java/jdbc/TbGenCol.java @@ -0,0 +1,403 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbGenCol.java +// +// SAMPLE: How to use generated columns +// +// This sample demonstrates how to use generated columns. +// It first creates a table and populates it with some data. +// Then, the integrity of the table is set to off and a +// generated column is added to the table. The integrity of +// the table is then set to IMMEDIATE CHECKED FORCE GENERATED +// to refresh the values of the newly added column. Finally, +// an index is created on the generated column to illustrate +// how they can be used to improve query performance. The +// sample drops the table it created before exiting. +// +// SQL STATEMENTS USED: +// CREATE TABLE +// INSERT +// SELECT +// SET INTEGRITY +// ALTER TABLE +// CREATE INDEX +// DROP TABLE +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbGenCol.out (not available in the samples directory). +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbGenCol +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO USE GENERATED COLUMNS."); + + // connect to the 'sample' database + db.connect(); + + createTableWithData(db.con); + addGeneratedColumntoTable(db.con); + createIndexOnGeneratedCol(db.con); + dropTable(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // Helping function: This function display the content of the table + // 'genColClassSchedule'. + static void tbContentDisplay(Connection con, boolean columnadded) + { + try + { + Integer c_id = new Integer(0); + String c_name = null; + String type = null; + String days = null; + String starting = null; + String ending = null; + Integer duration = new Integer(0); + + System.out.println(); + System.out.println( + " SELECT * FROM genColClassSchedule"); + if (columnadded) + { + System.out.println( + " " + + "C_ID C_NAME TYPE DAYS STARTING ENDING DURATION\n" + + " " + + "---- ------------- ----- ----- --------- --------- --------"); + } + else + { + System.out.println( + " C_ID C_NAME TYPE DAYS STARTING ENDING\n" + + " ---- ------------- ----- ----- --------- ---------"); + } + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT * FROM genColClassSchedule"); + + while (rs.next()) + { + c_id = Integer.valueOf(rs.getString(1)); + c_name = rs.getString(2); + type = rs.getString(3); + days = rs.getString(4); + starting = rs.getString(5); + ending = rs.getString(6); + + if (columnadded) + { + duration = Integer.valueOf(rs.getString(7)); + } + + System.out.print(" "+ Data.format(c_id, 4) + " " + + " " + Data.format(c_name, 13) + + " " + Data.format(type, 5) + + " " + Data.format(days, 5) + + " " + Data.format(starting, 9) + + " " + Data.format(ending, 9)); + + if (columnadded) + { + System.out.println(" " + Data.format(duration, 8)); + } + else + { + System.out.println(); + } + } + System.out.println(); + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tbContentDisplay + + // Helping function: This function creates a table called + // 'genColClassSchedule' and inserts some data into the table. + static void createTableWithData(Connection con) { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " INSERT INTO\n" + + "TO CREATE A TABLE WITH DATA"); + + System.out.println(); + System.out.println( + " CREATE TABLE genColClassSchedule(\n" + + " c_id int,\n"+ + " c_name varchar(20),\n"+ + " type varchar(3),\n"+ + " days varchar(3),\n"+ + " start time,\n"+ + " end time)\n"); + + Statement stmt = con.createStatement(); + stmt.execute( + "CREATE TABLE genColClassSchedule(c_id int," + + " c_name varchar(20),"+ + " type varchar(3)," + + " days varchar(3)," + + " start time," + + " end time)"); + + System.out.println( + " INSERT INTO genColClassSchedule \n" + + " VALUES (10,'CMPUT 391','LEC','MWF','14:00:00','14:50:00'),\n" + + " (20,'ENGLISH 101','LEC','MWF','08:00:00','08:50:00'),\n" + + " (30,'MATH 117','LEC','TR','11:00:00','12:20:00'),\n" + + " (40,'CMPUT 391','LAB','T','14:00:00','16:50:00'),\n" + + " (50,'PHYS 102','LEC','MWF','09:00:00','09:50:00')"); + + stmt.executeUpdate( + "INSERT INTO genColClassSchedule " + + "VALUES (10,'CMPUT 391','LEC','MWF','14:00:00','14:50:00'), " + + "(20,'ENGLISH 101','LEC','MWF','08:00:00','08:50:00'), " + + "(30,'MATH 117','LEC','TR','11:00:00','12:20:00'), " + + "(40,'CMPUT 391','LAB','T','14:00:00','16:50:00'), " + + "(50,'PHYS 102','LEC','MWF','09:00:00','09:50:00')"); + + stmt.close(); + con.commit(); + + tbContentDisplay(con,false); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // createTableWithData + + // This function adds a generated column called 'duration' to the table. + static void addGeneratedColumntoTable(Connection con) + { + try + { + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + "TO ADD A GENERATED COLUMN INTO A TABLE"); + + System.out.println(); + System.out.println(" SET INTEGRITY FOR genColClassSchedule OFF\n"); + + Statement stmt = con.createStatement(); + stmt.execute("SET INTEGRITY FOR genColClassSchedule OFF"); + + // the expression (60*hour(end-start)+minute(end-start)) converts + // the decimal result of time arithmetic into minutes + System.out.println( + " ALTER TABLE genColClassSchedule\n" + + " ADD COLUMN DURATION INTEGER\n" + + " GENERATED ALWAYS AS (60*hour(end-start)+minute(end-start))\n"); + + stmt.execute("ALTER TABLE genColClassSchedule " + + "ADD COLUMN DURATION INTEGER " + + "GENERATED ALWAYS AS " + + "(60*hour(end-start)+minute(end-start))"); + + System.out.println( + " SET INTEGRITY FOR genColClassSchedule\n"+ + " IMMEDIATE CHECKED FORCE GENERATED"); + + stmt.execute("SET INTEGRITY FOR genColClassSchedule " + + "IMMEDIATE CHECKED FORCE GENERATED"); + + stmt.close(); + con.commit(); + + tbContentDisplay(con,true); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // addGeneratedColumntoTable + + // This function creates an index on the generated column + static void createIndexOnGeneratedCol(Connection con) + { + try + { + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE INDEX\n" + + "TO CREATE AN INDEX ON THE GENERATED COLUMN"); + + System.out.println(); + System.out.println( + " CREATE INDEX duration_index\n" + + " ON genColClassSchedule (duration)\n"); + + Statement stmt = con.createStatement(); + stmt.execute("CREATE INDEX duration_index " + + "ON genColClassSchedule (duration)"); + + System.out.println( + " SELECT * from genColClassSchedule\n" + + " WHERE (60*hour(end-start)+minute(end-start)) > 60"); + System.out.println( + " " + + "C_ID C_NAME TYPE DAYS STARTING ENDING DURATION\n" + + " " + + "---- ------------- ----- ----- --------- --------- --------"); + + ResultSet rs = stmt.executeQuery("SELECT * from genColClassSchedule " + + "WHERE (60*hour(end-start)" + + " + minute(end-start)) > 60"); + + Integer c_id = new Integer(0); + String c_name = null; + String type = null; + String days = null; + String starting = null; + String ending = null; + Integer duration = new Integer(0); + + while (rs.next()) + { + c_id = Integer.valueOf(rs.getString(1)); + c_name = rs.getString(2); + type = rs.getString(3); + days = rs.getString(4); + starting = rs.getString(5); + ending = rs.getString(6); + duration = Integer.valueOf(rs.getString(7)); + + System.out.println(" "+ Data.format(c_id, 4) + " " + + " " + Data.format(c_name, 13) + + " " + Data.format(type, 5) + + " " + Data.format(days, 5) + + " " + Data.format(starting, 9) + + " " + Data.format(ending, 9) + + " " + Data.format(duration, 8)); + } + rs.close(); + stmt.close(); + + System.out.println(); + System.out.println( + " NOTE:\n" + + " Indexes can be created on generated columns to improve query\n"+ + " performance. If a query predicate contains a clause identical\n"+ + " to the clause used to define the generated column and the\n"+ + " generated column is indexed, the optimizer will use the index.\n"+ + " The SELECT query:\n\n"+ + " SELECT * FROM genColClassSchedule\n" + + " WHERE (60*hour(end-start)+minute(end-start)) > 60\n\n" + + " will, in general, perform better using the indexed generated\n" + + " column than without it. The idea is to add expressions that\n" + + " occur frequently in queries as generated columns and then\n" + + " index them to improve query performance."); + + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // createIndexOnGeneratedCol + + // Helping function: This function drops the table created by this program + static void dropTable(Connection con) { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DROP TABLE\n" + + "TO DROP A TABLE"); + + System.out.println(); + System.out.println(" DROP TABLE genColClassSchedule"); + + Statement stmt = con.createStatement(); + stmt.execute("DROP TABLE genColClassSchedule"); + + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // dropTable +} // TbGenCol diff --git a/java/jdbc/TbIdent.java b/java/jdbc/TbIdent.java new file mode 100644 index 0000000..f2d31a0 --- /dev/null +++ b/java/jdbc/TbIdent.java @@ -0,0 +1,272 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbIdent.java +// +// SAMPLE: How to use Identity Columns +// +// SQL Statements USED: +// CREATE TABLE +// INSERT +// SELECT +// DROP +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbIdent.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import java.lang.*; + +public class TbIdent +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO USE IDENTITY COLUMNS"); + + // connect to the 'sample' database + db.connect(); + + generateAlways(db.con); + generateByDefault(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void generateAlways(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " CREATE TABLE\n" + + " INSERT\n" + + "TO CREATE AN IDENTITY COLUMN WITH VALUE 'GENERATED ALWAYS'\n" + + "AND TO INSERT DATA IN THE TABLE\n"); + + try + { + // Create the table 'building' + System.out.println( + " CREATE TABLE building(\n" + + " bldnum INT GENERATED ALWAYS AS IDENTITY\n" + + " (START WITH 1, INCREMENT BY 1),\n" + + " addr VARCHAR(20),\n" + + " city VARCHAR(10),\n" + + " floor SMALLINT,\n" + + " employees SMALLINT)\n"); + + Statement stmt = con.createStatement(); + + stmt.executeUpdate( + "CREATE TABLE building(bldnum INT GENERATED ALWAYS" + + " AS IDENTITY(START WITH 1, INCREMENT BY 1), " + + " addr VARCHAR(20), " + + " city VARCHAR(10), " + + " floors SMALLINT, " + + " employees SMALLINT) " ); + stmt.close(); + + // Insert data into the table 'building' + System.out.println( + " INSERT INTO building(bldnum, addr, city, floors, employees)\n" + + " VALUES(DEFAULT, '110 Woodpart St', 'Smithville', 3, 10),\n" + + " (DEFAULT, '123 Sesame Ave', 'Jonestown', 16, 13),\n" + + " (DEFAULT, '738 Eglinton Rd', 'Whosburg', 2, 10),\n" + + " (DEFAULT, '832 Lesley Blvd', 'Centertown', 2, 18)\n"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO building(bldnum, addr, city, floors, employees)" + + " VALUES(DEFAULT, '110 Woodpart St', 'Smithville', 3, 10), " + + "(DEFAULT, '123 Sesame Ave', 'Jonestown', 16, 13), " + + "(DEFAULT, '738 Eglinton Rd', 'Whosburg', 2, 10), " + + "(DEFAULT, '832 Lesley Blvd', 'Centertown', 2, 18)"); + + stmt1.close(); + + // Retrieve and display the content of the 'building' table + System.out.println( + " SELECT * FROM building\n" + + " ID ADDRESS CITY FLOORS EMP\n" + + " --- -------------------- ------------ ------ ---\n"); + Statement stmt3 = con.createStatement(); + ResultSet rs = stmt3.executeQuery("SELECT * FROM building"); + + while (rs.next()) + { + System.out.println(" " + + Data.format(rs.getString("bldnum"),3) + " " + + Data.format(rs.getString("addr"),20) + " " + + Data.format(rs.getString("city"),12) + " " + + Data.format(rs.getString("floors"),6) + " " + + Data.format(rs.getString("employees"),4)); + } + + rs.close(); + stmt3.close(); + + // Drop the table 'building' + System.out.println(); + System.out.println(" Dropping the table 'building'\n"); + Statement stmt4 = con.createStatement(); + stmt4.executeUpdate("DROP TABLE building"); + stmt4.close(); + + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // generatedAlways + + static void generateByDefault(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " CREATE TABLE\n" + + " INSERT\n" + + "TO CREATE AN IDENTITY COLUMN WITH VALUE 'GENERATED BY DEFAULT'\n" + + "AND TO INSERT DATA IN THE TABLE\n"); + + try + { + // Create the table 'warehouse' + System.out.println( + " CREATE TABLE warehouse(\n" + + " whnum INT GENERATED BY DEFAULT AS IDENTITY\n" + + " (START WITH1, INCREMENT BY 1),\n" + + " addr VARCHAR(20),\n" + + " city VARCHAR(10),\n" + + " capacity SMALLINT,\n" + + " employees SMALLINT)\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE warehouse(whnum INT GENERATED BY DEFAULT" + + " AS IDENTITY(START WITH 1, INCREMENT BY 1), " + + " addr VARCHAR(20), " + + " city VARCHAR(10), " + + " capacity SMALLINT, " + + " employees SMALLINT) "); + stmt.close(); + + // Insert data into the table 'warehouse' + System.out.println( + " INSERT INTO warehouse(whnum, addr, city, capacity, employees)\n" + + " VALUES(DEFAULT, '92 Bothfield Dr', 'Yorkvile', 23, 100),\n" + + " (DEFAULT, '33 Giant Road', 'Centertown', 100, 22),\n" + + " (3, '8200 Warden Blvd', 'Smithville', 254, 10),\n" + + " (DEFAULT, '53 4th Ave', 'Whosburg', 97, 28)\n"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO warehouse(whnum, addr, city, capacity, employees)" + + " VALUES(DEFAULT, '92 Bothfield Dr', 'Yorkvile', 23, 100), " + + "(DEFAULT, '33 Giant Road', 'Centertown', 100, 22), " + + "(3, '8200 Warden Blvd', 'Smithville', 254, 10), " + + "(DEFAULT, '53 4th Ave', 'Whosburg', 97, 28) "); + + stmt1.close(); + + //Print warhouse Table + System.out.println( + " SELECT * FROM warehouse\n" + + " ID ADDRESS CITY CAPACITY EMP\n" + + " --- -------------------- ------------ -------- ---\n"); + + Statement stmt3 = con.createStatement(); + ResultSet rs = stmt3.executeQuery("SELECT * FROM warehouse"); + + while (rs.next()) + { + System.out.println(" " + + Data.format(rs.getString("whnum"),3) + " " + + Data.format(rs.getString("addr"),20) + " " + + Data.format(rs.getString("city"),12) + " " + + Data.format(rs.getString("capacity"),8) + " " + + Data.format(rs.getString("employees"),4)); + } + + rs.close(); + stmt3.close(); + + System.out.println( + "\n NOTE:\n" + + " An Identity Column with value 'GENERATED BY DEFAULT' may\n" + + " not contain a unique value for each row! To ensure a unique\n" + + " value for each row, define an index on the Identity Column.\n"); + + //Drop warhouse Table + System.out.println(" Dropping the table 'warehouse'"); + Statement stmt4 = con.createStatement(); + stmt4.executeUpdate("DROP TABLE warehouse"); + stmt4.close(); + + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } //generatedByDefault +} diff --git a/java/jdbc/TbInTrig.java b/java/jdbc/TbInTrig.java new file mode 100644 index 0000000..6cb9772 --- /dev/null +++ b/java/jdbc/TbInTrig.java @@ -0,0 +1,881 @@ +//************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************** +// +// SOURCE FILE NAME: TbInTrig.java +// +// SAMPLE: How to use an 'INSTEAD OF' trigger on a view +// +// SQL STATEMENTS USED: +// SELECT +// CREATE TABLE +// DROP +// CREATE TRIGGER +// INSERT +// DELETE +// UPDATE +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbInTrig.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, building, and running DB2 +// applications, visit the DB2 application development website: +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbInTrig +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + " THIS SAMPLE SHOWS HOW TO USE 'INSTEAD OF' TRIGGERS.\n"); + + // connect to the 'sample' database + db.connect(); + + // Create a view 'staffv' of the table 'staff' + CreateViewStaffV(db.con); + + // Demonstrate an UPDATE operation before an INSTEAD OF UPDATE trigger + // is created + NormalUpdate(db.con); + + // Demonstrate the same UPDATE operation after an INSTEAD OF UPDATE + // trigger is created + UpdateWithInsteadOfTrigger(db.con); + + // Demonstrate how to update a number of tables through a common view + // and the use of a set of 'INSTEAD OF' triggers + MutliTableUpdate(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // This method creates a view 'staffv' of the table 'staff' + public static void CreateViewStaffV(Connection conn) + { + try + { + System.out.println( + "\n CREATE A VIEW 'staffv' OF THE TABLE 'staff'\n" + + "\n INVOKE THE STATEMENT:\n" + + "\n CREATE VIEW staffv(ID, NAME, DEPT, JOB, YEARS, SALARY, COMM)"+ + "\n AS SELECT * FROM staff WHERE ID >= 310"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate( + "CREATE VIEW staffv(ID, NAME, DEPT, JOB, YEARS, SALARY, COMM)" + + " AS SELECT * FROM staff WHERE ID >= 310"); + + stmt.close(); + conn.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } + + // Helper method: This method displays the results of a query specified by + // 'selectstmt' on the 'staffv' view + private static void StaffvContentDisplay(Connection conn, + String selectStmt) + { + try + { + int id = 0; + int dept = 0; + double salary = 0.0; + String name = null; + String job = null; + Integer years = new Integer(0); + Double comm = new Double(0.0); + + System.out.println(); + System.out.println(" " + selectStmt + "\n"); + + System.out.println( + " ID NAME DEPT JOB YEARS SALARY COMM\n" + + " --- ------- ---- ----- ----- -------- --------"); + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(selectStmt); + + while (rs.next()) + { + id = rs.getInt(1); + name = rs.getString(2); + dept = rs.getInt(3); + job = rs.getString(4); + + if (rs.getString(5) == null) + { + years = null; + } + else + { + years = Integer.valueOf(rs.getString(5)); + } + salary = rs.getDouble(6); + if (rs.getDouble(7) == 0.0) + { + comm = null; + } + else + { + comm = Double.valueOf(Double.toString(rs.getDouble(7))); + } + + System.out.print(" " + Data.format(id,3) + + " " + Data.format(name,7) + + " " + Data.format(dept,4)); + if (job != null) + { + System.out.print(" " + Data.format(job,5)); + } + else + { + System.out.print(" -"); + } + if (years != null) + { + System.out.print(" " + Data.format(years,5)); + } + else + { + System.out.print(" -"); + } + System.out.print(" " + Data.format(salary,7,2)); + if (comm != null) + { + System.out.print(" " + Data.format(comm,7,2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // StaffvContentDisplay + + // This method demonstrates an UPDATE operation before an + // 'INSTEAD OF UPDATE' trigger is created + public static void InsteadOfUpdateTriggerCreate(Connection conn) + { + try + { + System.out.println( + "\n CREATE AN 'INSTEAD OF UPDATE' TRIGGER CALLED 'staff_raise'"); + + // Create a trigger which apart from the original update, raises the + // salary further based on the number of years the employee has served + System.out.println( + "\n CREATE TRIGGER staff_raise INSTEAD OF UPDATE ON staffv" + + "\n REFERENCING NEW AS n OLD AS o " + + "\n FOR EACH ROW " + + "\n BEGIN ATOMIC " + + "\n VALUES(CASE " + + "\n WHEN n.ID = o.ID THEN 0 " + + "\n ELSE RAISE_ERROR('70002', 'Must not change ID')"+ + "\n END); " + + "\n UPDATE STAFF AS S " + + "\n SET (ID, NAME, DEPT, JOB, YEARS, COMM, SALARY) " + + "\n = (n.ID, n.NAME, n.DEPT, n.JOB, n.YEARS, n.COMM, " + + "\n CASE " + + "\n WHEN n.YEARS IS NULL THEN o.salary " + + "\n WHEN n.YEARS <= 2 THEN n.salary + 500 " + + "\n WHEN n.YEARS <= 4 THEN n.salary + 1000 " + + "\n WHEN n.YEARS <= 6 THEN n.salary + 2000 " + + "\n WHEN n.YEARS <= 8 THEN n.salary + 3500 " + + "\n WHEN n.YEARS <= 10 THEN n.salary + 5500 " + + "\n ELSE n.salary + 6000 " + + "\n END) " + + "\n WHERE n.ID = S.ID; " + + "\n END"); + + Statement stmt = conn.createStatement(); + stmt.execute( + "CREATE TRIGGER staff_raise INSTEAD OF UPDATE ON staffv" + + " REFERENCING NEW AS n OLD AS o " + + " FOR EACH ROW " + + " BEGIN ATOMIC " + + " VALUES(CASE " + + " WHEN n.ID = o.ID THEN 0 " + + " ELSE RAISE_ERROR('70002', 'Must not change ID') " + + " END); " + + " UPDATE STAFF AS S " + + " SET (ID, NAME, DEPT, JOB, YEARS, COMM, SALARY) " + + " = (n.ID, n.NAME, n.DEPT, n.JOB, n.YEARS, n.COMM, " + + " CASE " + + " WHEN n.YEARS IS NULL THEN o.salary " + + " WHEN n.YEARS <= 2 THEN n.salary + 500 " + + " WHEN n.YEARS <= 4 THEN n.salary + 1000 " + + " WHEN n.YEARS <= 6 THEN n.salary + 2000 " + + " WHEN n.YEARS <= 8 THEN n.salary + 3500 " + + " WHEN n.YEARS <= 10 THEN n.salary + 5500 " + + " ELSE n.salary + 6000 " + + " END) " + + " WHERE n.ID = S.ID; " + + " END "); + + stmt.close(); + conn.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // InsteadOfUpdateTriggerCreate + + // This method demonstrates an UPDATE operation before an + // 'INSTEAD OF UPDATE' trigger has been created + public static void NormalUpdate(Connection conn) + { + try + { + String selectString = "SELECT * FROM staffv WHERE ID = 340"; + + System.out.println( + "\n -----------------------------------------------------------" + + "\n USE THE SQL STATEMENTS:\n" + + "\n ROLLBACK" + + "\n UPDATE\n" + + "\n TO DISPLAY THE RESULTS OF AN UPDATE STATEMENT ON THE VIEW" + + " 'staffv'" + + "\n BEFORE AN 'INSTEAD OF UPDATE' TRIGGER IS CREATED."); + + // Display the contents of the row in 'staffv' that is going to be + // updated + System.out.println( + "\n CONTENT OF A ROW IN 'staffv' VIEW BEFORE IT IS UPDATED"); + StaffvContentDisplay(conn, selectString); + + // Update the 'staffv' view + System.out.println( + "\n INVOKE THE STATEMENT:\n" + + "\n UPDATE staffv SET years=4,COMM=50 WHERE ID = 340"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate("UPDATE staffv SET years=4,COMM=50 WHERE ID = 340"); + + // Display the contents of the row in 'staffv' after updating it + System.out.println( + "\n CONTENTS OF THE ROW IN 'staffv' AFTER UPDATING IT"); + StaffvContentDisplay(conn, selectString); + + stmt.close(); + conn.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // NormalUpdate + + // This method demonstrates an UPDATE operation after an + // 'INSTEAD OF UPDATE' trigger has been created + public static void UpdateWithInsteadOfTrigger(Connection conn) + { + try + { + String selectString = "SELECT * FROM staffv WHERE ID = 340"; + + System.out.println( + "\n -----------------------------------------------------------" + + "\n USE THE SQL STATEMENTS:\n" + + "\n CREATE TRIGGER" + + "\n UPDATE" + + "\n ROLLBACK" + + "\n COMMIT\n" + + "\n TO DISPLAY THE RESULTS OF THE SAME UPDATE STATEMENT ON THE" + + " VIEW" + + "\n 'staffv' AFTER CREATING AN 'INSTEAD OF UPDATE' TRIGGER."); + + // Create an 'INSTEAD OF UPDATE' trigger + InsteadOfUpdateTriggerCreate(conn); + + // Display the row to be updated in 'staffv' before an UPDATE statement + // is issued + System.out.println( + "\n CONTENTS OF THE ROW IN 'staffv' BEFORE IT IS UPDATED"); + StaffvContentDisplay(conn, selectString); + + // Issue an UPDATE statement to update the 'staffv' view + System.out.println( + "\n INVOKE THE SAME STATEMENT:\n" + + "\n UPDATE staffv SET years=4,COMM=50 WHERE ID = 340"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate("UPDATE staffv SET years=4,COMM=50 WHERE ID = 340"); + + // Display the contents of the row in 'staffv' after updating it with + // the UPDATE statement + System.out.println( + "\n CONTENTS OF THE ROW IN 'staffv' AFTER INVOKING THE UPDATE" + + " STATEMENT," + + "\n WHICH NOW CAUSES THE 'INSTEAD OF UPDATE' TRIGGER TO FIRE"); + StaffvContentDisplay(conn, selectString); + + // Rollback changes made to the view + conn.rollback(); + + // Drop the trigger + stmt.execute("DROP TRIGGER staff_raise"); + + // Drop the view + stmt.execute("DROP VIEW staffv"); + + stmt.close(); + conn.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } + + // This method creates tables: PERSONS, STUDENTS and EMPLOYEES and + // creates a view called PERSONS_V + private static void CreateTablesAndView(Connection conn) + { + try + { + // Create the table PERSONS + System.out.println( + "\n INVOKE THE STATEMENTS:\n" + + "\n CREATE TABLE PERSONS(ssn INT NOT NULL, name VARCHAR(20)" + + " NOT NULL)"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate( + "CREATE TABLE PERSONS(ssn INT NOT NULL, name VARCHAR(20) NOT NULL)"); + + // Create the table EMPLOYEES + System.out.println( + "\n CREATE TABLE EMPLOYEES(ssn INT NOT NULL," + + "\n company VARCHAR(20) NOT NULL," + + "\n salary DECIMAL(9,2))"); + + stmt.executeUpdate( + "CREATE TABLE EMPLOYEES(ssn INT NOT NULL," + + " company VARCHAR(20) NOT NULL," + + " salary DECIMAL(9,2))"); + + // Create the table STUDENTS + System.out.println( + "\n CREATE TABLE STUDENTS(ssn INT NOT NULL," + + "\n university VARCHAR(20) NOT NULL," + + "\n major VARCHAR(10))"); + + stmt.executeUpdate( + "CREATE TABLE STUDENTS(ssn INT NOT NULL," + + " university VARCHAR(20) NOT NULL," + + " major VARCHAR(10))"); + + // Create the view PERSONS_V + System.out.println( + "\n CREATE VIEW PERSONS_V(ssn, name, company, " + + "\n salary, university, major) " + + "\n AS SELECT P.ssn, name, company, " + + "\n salary, university, major " + + "\n FROM PERSONS P LEFT OUTER JOIN EMPLOYEES E " + + "\n ON P.ssn = E.ssn " + + "\n LEFT OUTER JOIN STUDENTS S " + + "\n ON P.ssn = S.ssn"); + + stmt.executeUpdate( + "CREATE VIEW PERSONS_V(ssn, name, company," + + " salary, university, major)" + + " AS SELECT P.ssn, name, company,salary, university, major" + + " FROM PERSONS P LEFT OUTER JOIN EMPLOYEES E" + + " ON P.ssn = E.ssn" + + " LEFT OUTER JOIN STUDENTS S" + + " ON P.ssn = S.ssn"); + stmt.close(); + conn.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // CreateTablesAndView + + // This method creates INSTEAD OF triggers: INSERT_PERSONS_V, + // UPDATE_PERSONS_V and DELETE_PERSONS_V on the view PERSONS_V + private static void CreatePersonsVTriggers(Connection conn) + { + try + { + // Create the INSTEAD OF INSERT trigger 'INSERT_PERSONS_V' + System.out.println( + "\n CREATE AN 'INSTEAD OF INSERT' TRIGGER CALLED" + + " 'INSERT_PERSONS_V':\n" + + "\n INVOKE THE STATEMENT:"); + + System.out.println( + "\n CREATE TRIGGER INSERT_PERSONS_V " + + "\n INSTEAD OF INSERT ON PERSONS_V " + + "\n REFERENCING NEW AS n FOR EACH ROW " + + "\n BEGIN ATOMIC " + + "\n INSERT INTO PERSONS VALUES (n.ssn, n.name); " + + "\n IF n.university IS NOT NULL THEN " + + "\n INSERT INTO STUDENTS " + + "\n VALUES(n.ssn, n.university, n.major); " + + "\n END IF; " + + "\n IF n.company IS NOT NULL THEN " + + "\n INSERT INTO EMPLOYEES " + + "\n VALUES(n.ssn, n.company, n.salary); " + + "\n END IF; " + + "\n END"); + + Statement stmt = conn.createStatement(); + stmt.execute( + "CREATE TRIGGER INSERT_PERSONS_V " + + " INSTEAD OF INSERT ON PERSONS_V " + + " REFERENCING NEW AS n FOR EACH ROW " + + " BEGIN ATOMIC " + + " INSERT INTO PERSONS VALUES (n.ssn, n.name); " + + " IF n.university IS NOT NULL THEN " + + " INSERT INTO STUDENTS " + + " VALUES(n.ssn, n.university, n.major); " + + " END IF; " + + " IF n.company IS NOT NULL THEN " + + " INSERT INTO EMPLOYEES " + + " VALUES(n.ssn, n.company, n.salary); " + + " END IF; " + + " END "); + + conn.commit(); + + // Create the INSTEAD OF DELETE trigger 'DELETE_PERSONS_V' + System.out.println( + "\n CREATE AN 'INSTEAD OF DELETE' TRIGGER CALLED" + + " 'DELETE_PERSONS_V':\n" + + "\n INVOKE THE STATEMENT:"); + + System.out.println( + "\n CREATE TRIGGER DELETE_PERSONS_V " + + "\n INSTEAD OF DELETE ON PERSONS_V " + + "\n REFERENCING OLD AS o FOR EACH ROW " + + "\n BEGIN ATOMIC " + + "\n DELETE FROM STUDENTS WHERE ssn = o.ssn; " + + "\n DELETE FROM EMPLOYEES WHERE ssn = o.ssn; " + + "\n DELETE FROM PERSONS WHERE ssn = o.ssn; " + + "\n END"); + + stmt.execute( + "CREATE TRIGGER DELETE_PERSONS_V " + + " INSTEAD OF DELETE ON PERSONS_V " + + " REFERENCING OLD AS o FOR EACH ROW " + + " BEGIN ATOMIC " + + " DELETE FROM STUDENTS WHERE ssn = o.ssn; " + + " DELETE FROM EMPLOYEES WHERE ssn = o.ssn; " + + " DELETE FROM PERSONS WHERE ssn = o.ssn; " + + " END "); + + conn.commit(); + + // Create the INSTEAD OF UPDATE trigger 'UPDATE_PERSONS_V' + System.out.println( + "\n CREATE AN 'INSTEAD OF UPDATE' TRIGGER CALLED " + + "'UPDATE_PERSONS_V':\n" + + "\n INVOKE THE STATEMENT:"); + + System.out.println( + "\n CREATE TRIGGER UPDATE_PERSONS_V " + + "\n INSTEAD OF UPDATE ON PERSONS_V " + + "\n REFERENCING OLD AS o NEW AS n " + + "\n FOR EACH ROW " + + "\n BEGIN ATOMIC " + + "\n UPDATE PERSONS " + + "\n SET (ssn, name) = (n.ssn, n.name) " + + "\n WHERE ssn = o.ssn; " + + "\n IF n.university IS NOT NULL " + + "\n AND o.university IS NOT NULL THEN " + + "\n UPDATE STUDENTS " + + "\n SET (ssn, university, major) " + + "\n = (n.ssn, n.university, n.major) " + + "\n WHERE ssn = o.ssn; " + + "\n ELSEIF n.university IS NULL THEN " + + "\n DELETE FROM STUDENTS WHERE ssn = o.ssn; " + + "\n ELSE " + + "\n INSERT INTO STUDENTS " + + "\n VALUES(n.ssn, n.university, n.major); " + + "\n END IF; " + + "\n IF n.company IS NOT NULL " + + "\n AND o.company IS NOT NULL THEN " + + "\n UPDATE EMPLOYEES " + + "\n SET (ssn, company, salary) " + + "\n = (n.ssn, n.company, n.salary) " + + "\n WHERE ssn = o.ssn; " + + "\n ELSEIF n.company IS NULL THEN " + + "\n DELETE FROM EMPLOYEES WHERE ssn = o.ssn; " + + "\n ELSE " + + "\n INSERT INTO EMPLOYEES " + + "\n VALUES(n.ssn, n.company, n.salary); " + + "\n END IF; " + + "\n END"); + + stmt.execute( + "CREATE TRIGGER UPDATE_PERSONS_V " + + " INSTEAD OF UPDATE ON PERSONS_V " + + " REFERENCING OLD AS o NEW AS n " + + " FOR EACH ROW " + + " BEGIN ATOMIC " + + " UPDATE PERSONS " + + " SET (ssn, name) = (n.ssn, n.name) " + + " WHERE ssn = o.ssn; " + + " IF n.university IS NOT NULL " + + " AND o.university IS NOT NULL THEN " + + " UPDATE STUDENTS " + + " SET (ssn, university, major) " + + " = (n.ssn, n.university, n.major) " + + " WHERE ssn = o.ssn; " + + " ELSEIF n.university IS NULL THEN " + + " DELETE FROM STUDENTS WHERE ssn = o.ssn; " + + " ELSE " + + " INSERT INTO STUDENTS " + + " VALUES(n.ssn, n.university, n.major); " + + " END IF; " + + " IF n.company IS NOT NULL " + + " AND o.company IS NOT NULL THEN " + + " UPDATE EMPLOYEES " + + " SET (ssn, company, salary) " + + " = (n.ssn, n.company, n.salary) " + + " WHERE ssn = o.ssn; " + + " ELSEIF n.company IS NULL THEN " + + " DELETE FROM EMPLOYEES WHERE ssn = o.ssn; " + + " ELSE " + + " INSERT INTO EMPLOYEES " + + " VALUES(n.ssn, n.company, n.salary); " + + " END IF; " + + " END"); + + stmt.close(); + conn.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // CreatePersonsVTriggers + + // This method demonstrates how to update a number of tables through a + // common view and the use of a set of 'INSTEAD OF' triggers + public static void MutliTableUpdate(Connection conn) + { + try + { + System.out.println( + "\n -----------------------------------------------------------" + + "\n USE THE SQL STATEMENTS:\n" + + "\n CREATE TABLE" + + "\n CREATE VIEW" + + "\n CREATE TRIGGER" + + "\n INSERT" + + "\n UPDATE" + + "\n DELETE" + + "\n COMMIT" + + "\n ROLLBACK\n"); + + System.out.println( + " TO UPDATE DATA IN TABLES 'PERSONS' 'STUDENTS' AND 'EMPLOYEES'\n" + + " THROUGH A VIEW 'PERSONS_V' USING 'INSTEAD OF' TRIGGERS.\n\n" + + " NOTE: THE VIEW IS NEITHER INSERTABLE, UPDATABLE NOR DELETABLE," + + " SO\n" + + " IN ORDER TO PERFORM THESE TABLE OPERATIONS, A FULL SET OF\n" + + " 'INSTEAD OF' TRIGGERS NEEDS TO BE GENERATED. THE TRIGGERS" + + " MODIFY\n" + + " THE CONTENTS OF EACH TABLE INDIVIDUALLY WHEN AN OPERATION IS\n" + + " ATTEMPTED ON THE VIEW"); + + System.out.println( + "\n CREATE TABLES: 'PERSONS', 'EMPLOYEES' AND 'STUDENTS' AND " + + "CREATE A\n VIEW 'PERSONS_V'"); + + // Create the tables PERSONS, STUDENTS, EMPLOYEES, and the view + // PERSONS_V + CreateTablesAndView(conn); + + // Create the set of INSTEAD OF triggers + CreatePersonsVTriggers(conn); + + // Insert values in tables PERSONS, STUDENTS, and EMPLOYEES by + // inserting the values in the view PERSONS_V. This action will trigger + // the INSTEAD OF INSERT trigger which will then insert the values in + // the individual tables + System.out.println( + "\n INSERT VALUES IN THE TABLES 'PERSONS', 'STUDENTS' AND " + + "'EMPLOYEES'" + + "\n THROUGH THE VIEW 'PERSONS_V'\n" + + "\n INVOKE THE STATEMENT:"); + + System.out.println( + "\n INSERT INTO PERSONS_V" + + "\n VALUES(123456, 'Smith', NULL, NULL, NULL, NULL), " + + "\n (234567, 'Jones', 'Wmart', 20000, NULL, NULL), " + + "\n (345678, 'Miller', NULL, NULL, 'Harvard', 'Math'), " + + "\n (456789, 'McNuts', 'SelfEmp', 60000, 'UCLA', 'CS')"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate( + "INSERT INTO PERSONS_V VALUES " + + " (123456, 'Smith', NULL, NULL, NULL, NULL), " + + " (234567, 'Jones', 'Wmart', 20000, NULL, NULL), " + + " (345678, 'Miller', NULL, NULL, 'Harvard', 'Math'), " + + " (456789, 'McNuts', 'SelfEmp', 60000, 'UCLA', 'CS') "); + + // Display view content after the insertion of rows + System.out.println( + "\n CONTENTS OF 'PERSONS_V' AFTER THE 'INSERT' STATEMENT"); + PersonsVContentDisplay(conn); + + // Update values in tables PERSONS, STUDENTS, and EMPLOYEES by updating + // the values in the view PERSONS_V. This action will trigger the + // INSTEAD OF UPDATE trigger which will then update the values in the + // individual tables + System.out.println( + "\n UPDATE THE TABLES 'PERSONS', 'STUDENTS' AND 'EMPLOYEES'" + + "\n THROUGH THE VIEW 'PERSONS_V'\n" + + "\n INVOKE THE STATEMENTS:"); + + System.out.println( + "\n UPDATE PERSONS_V" + + "\n SET (name, company, salary) =" + + " ('Johnson', 'Mickburgs', 15000)" + + "\n WHERE SSN = 123456\n" + + "\n UPDATE PERSONS_V" + + "\n SET (company, salary, university) = ('IBM', 70000, NULL)" + + "\n WHERE SSN = 345678"); + + stmt.executeUpdate( + "UPDATE PERSONS_V " + + " SET (name, company, salary) = ('Johnson', 'Mickburgs', 15000) " + + " WHERE SSN = 123456"); + + stmt.executeUpdate( + "UPDATE PERSONS_V SET (company, salary, university) " + + " = ('IBM', 70000, NULL) " + + " WHERE SSN = 345678"); + + // Display view content after updating + System.out.println( + "\n CONTENTS OF 'PERSONS_V' AFTER THE 'UPDATE' STATEMENTS"); + PersonsVContentDisplay(conn); + + // Delete rows from tables PERSONS, STUDENTS, and EMPLOYEES by deleting + // the rows in the view PERSONS_V. This action will trigger the INSTEAD + // OF DELETE trigger which will then delete rows from the individual + // tables + System.out.println( + "\n DELETE ROWS FROM THE TABLES 'PERSONS', 'STUDENTS' AND" + + " 'EMPLOYEES'" + + "\n THROUGH THE VIEW 'PERSONS_V'\n" + + "\n INVOKE THE STATEMENT:"); + System.out.println("\n DELETE FROM PERSONS_V WHERE NAME = 'Jones'"); + + stmt.executeUpdate("DELETE FROM PERSONS_V WHERE NAME = 'Jones'"); + + // Display view content after deleting rows + System.out.println( + "\n CONTENTS OF 'PERSONS_V' AFTER THE 'DELETE' STATEMENT"); + PersonsVContentDisplay(conn); + + conn.rollback(); + + // Drop the INSTEAD OF triggers + System.out.println( + "\n DROP TRIGGERS: INSERT_PERSONS_V, DELETE_PERSONS_V, AND " + + "UPDATE_PERSONS_V"); + + stmt.execute("DROP TRIGGER INSERT_PERSONS_V"); + stmt.execute("DROP TRIGGER DELETE_PERSONS_V"); + stmt.execute("DROP TRIGGER UPDATE_PERSONS_V"); + + // Drop the tables PERSONS, STUDENTS, EMPLOYEES and the view PERSONS_V + System.out.println( + " DROP TABLES: PERSONS, STUDENTS, AND EMPLOYEES\n" + + " DROP VIEW: PERSONS_V"); + + stmt.execute("DROP TABLE PERSONS"); + stmt.execute("DROP VIEW PERSONS_V"); + stmt.execute("DROP TABLE STUDENTS"); + stmt.execute("DROP TABLE EMPLOYEES"); + + stmt.close(); + conn.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } + + // This method displays the contents of the 'STAFFV' view + private static void PersonsVContentDisplay(Connection conn) + { + try + { + int ssn = 0; + String name = null; + String company = null; + double salary = 0.0; + String university = null; + String major = null; + + System.out.println( + "\n SELECT * FROM persons_v ORDER BY ssn\n" + + "\n SSN NAME COMPANY SALARY UNIVERSITY MAJOR" + + "\n ------ -------- --------- ---------- ---------- -----"); + + // Declare a CURSOR to store the results of the query + Statement stmt = conn.createStatement(); + ResultSet rs; + rs = stmt.executeQuery( + "SELECT SSN, NAME, COMPANY, SALARY, UNIVERSITY, MAJOR" + + " FROM persons_v ORDER BY ssn"); + while (rs.next()) + { + ssn = rs.getInt(1); + name = rs.getString(2); + if (rs.getString(3) != null) + { + company = rs.getString(3); + } + else + { + company = null; + } + if (rs.getObject(4) != null) + { + salary = rs.getDouble(4); + } + else + { + salary = 0.0; + } + if (rs.getString(5) != null) + { + university = rs.getString(5); + } + else + { + university = null; + } + if (rs.getString(6) != null) + { + major = rs.getString(6); + } + else + { + major = null; + } + + System.out.print(" " + Data.format(ssn,6) + + " " + Data.format(name,8)); + if (company != null) + { + System.out.print(" " + Data.format(company,9)); + } + else + { + System.out.print(" - "); + } + if (salary != 0.0) + { + System.out.print(" " + Data.format(salary,9,2)); + } + else + { + System.out.print(" - "); + } + if (university != null) + { + System.out.print(" " + Data.format(university,10)); + } + else + { + System.out.print(" - "); + } + if (major != null) + { + System.out.print(" " + Data.format(major,5)); + } + else + { + System.out.print(" - "); + } + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // PersonsVContentDisplay +} diff --git a/java/jdbc/TbInfo.java b/java/jdbc/TbInfo.java new file mode 100644 index 0000000..5c1b2dc --- /dev/null +++ b/java/jdbc/TbInfo.java @@ -0,0 +1,202 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbInfo.java +// +// SAMPLE: How to get information about a table +// +// SQL Statements USED: +// SELECT +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbInfo.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; + +class TbInfo +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + String tableName; + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO GET INFORMATION ABOUT A TABLE."); + + // connect to the 'sample' database + db.connect(); + + // call the sample methods + tableName = "STAFF"; + getSchemaName(db.con, tableName); + getColumnInfo(db.con, tableName); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // This function demonstrates how to get the schema name for a table + static void getSchemaName(Connection con, String tableName) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " SELECT\n" + + "TO GET THE SCHEMA NAME OF A TABLE."); + + try + { + // get the schema name for a table + System.out.println(); + System.out.println( + " Execute the statement:\n" + + " SELECT tabschema\n" + + " FROM syscat.tables\n" + + " WHERE tabname = '" + tableName + "'"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT tabschema "+ + " FROM syscat.tables "+ + " WHERE tabname = '"+ tableName + "'"); + + boolean result = rs.next(); + + System.out.println(); + System.out.println(" Table schema name is: " + rs.getString(1)); + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // getSchemaName + + // This function demonstrates how to get the column information for a table + static void getColumnInfo(Connection con, String tableName) + { + String dataColname = ""; + String dataTypename = ""; + int dataLength = 0; + int dataScale = 0; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO GET THE COLUMN INFORMATION OF A TABLE."); + + try + { + // get the column information for a table + System.out.println(); + System.out.println( + " The following SQL statement gets the column information \n"+ + " of the '" + tableName + "' table: \n"); + + System.out.println( + " SELECT colname, typename, length, scale \n" + + " FROM syscat.columns \n" + + " WHERE tabname = '" + tableName + "'\n"); + + System.out.println( + " column name data type data size\n" + + " -------------------- -------------- ----------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT colname, typename, length, scale " + + " FROM syscat.columns " + + " WHERE tabname = '" + tableName + "'\n"); + + if (rs.next() == false) + { + System.out.println(); + System.out.println(" Data not found.\n"); + } + + do + { + dataColname = rs.getString(1); + dataTypename = rs.getString(2); + dataLength = rs.getInt(3); + dataScale = rs.getInt(4); + System.out.print(" " + Data.format(dataColname, 20) + + " " + Data.format(dataTypename, 14) + + " " + dataLength); + if (dataScale != 0) + { + System.out.println("," + dataScale); + } + else + { + System.out.println(); + } + } while (rs.next()); + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // getColumnInfo +} // TbInfo + diff --git a/java/jdbc/TbMerge.java b/java/jdbc/TbMerge.java new file mode 100644 index 0000000..abe4481 --- /dev/null +++ b/java/jdbc/TbMerge.java @@ -0,0 +1,370 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbMerge.java +// +// SAMPLE: How to use the MERGE statement +// +// SQL Statements USED: +// SELECT +// UPDATE +// DELETE +// INSERT +// MERGE +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbMerge.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +public class TbMerge +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + " THIS SAMPLE SHOWS HOW TO USE THE 'MERGE' STATEMENT\n"); + + // connect to the 'sample' database + db.connect(); + + // create the 'empsamp' table + CreateTable(db.con); + + // make changes to the 'empsamp' table + ChangeTable(db.con); + + // apply the changes from table 'empsamp' table to the + // 'staff' table + MergeTables(db.con); + + // drop the 'empsamp' table + Statement stmt = db.con.createStatement(); + stmt.executeUpdate("DROP TABLE empsamp"); + stmt.close(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // This method creates the 'empsamp' table and inserts some values into it + public static void CreateTable(Connection conn) + { + try + { + System.out.println( + "\n -----------------------------------------------------------" + + "\n USE THE SQL STATEMENT:\n" + + " CREATE TABLE\n" + + " TO CREATE A TABLE IN THE SAMPLE DATABASE.\n"); + + // create the table + System.out.println( + "\n Create a table 'EMPSAMP' with attributes:" + + "\n ID SMALLINT NOT NULL," + + "\n NAME VARCHAR(9)," + + "\n DEPT SMALLINT," + + "\n JOB CHAR(5)," + + "\n YEARS SMALLINT," + + "\n SALARY DEC(7,2)," + + "\n COMM DEC(7,2)," + + "\n PRIMARY KEY(ID)"); + Statement stmt = conn.createStatement(); + stmt.executeUpdate( + "CREATE TABLE empsamp(" + + " ID SMALLINT NOT NULL," + + " NAME VARCHAR(9)," + + " DEPT SMALLINT," + + " JOB CHAR(5)," + + " YEARS SMALLINT," + + " SALARY DEC(7,2)," + + " COMM DEC(7,2)," + + " PRIMARY KEY(ID))"); + + // insert some values into the table + System.out.println("\n Insert values into EMPSAMP"); + System.out.println("\n Invoke the statement:\n" + + "\n INSERT INTO empsamp " + + "SELECT * FROM staff WHERE ID >= 310"); + stmt.executeUpdate("INSERT INTO empsamp" + + " SELECT * FROM staff" + + " WHERE ID >= 310"); + stmt.close(); + + // display the final content of the 'empsamp' table + TbContentDisplay(conn, "empsamp"); + + // commit the transaction + conn.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // CreateTable + + // This method makes changes to the 'empsamp' table + public static void ChangeTable(Connection conn) + { + try + { + System.out.println( + "\n -----------------------------------------------------------" + + "\n USE THE SQL STATEMENTS:\n" + + " UPDATE\n" + + " INSERT\n" + + " TO MAKE CHANGES TO THE 'empsamp' TABLE.\n"); + + // display the initial contents of the 'empsamp' table + TbContentDisplay(conn, "empsamp"); + + // make changes and insert values into the 'empsamp' table + System.out.println( + "\n Invoke the statement\n\n" + + " INSERT INTO empsamp(id, name, dept, job, salary)\n" + + " VALUES(380, 'Pearce', 38, 'Clerk', 13217.50),\n" + + " (390, 'Hachey', 38, 'Mgr', 21270.00),\n" + + " (400, 'Wagland', 38, 'Clerk', 14575.00)\n"); + + System.out.println( + "\n Invoke the statements:\n" + + "\n UPDATE empsamp SET job = 'Mgr' WHERE id = 310" + + "\n UPDATE empsamp SET job = 'Sales', salary = 15000.00" + + " WHERE id = 350" + + "\n UPDATE empsamp SET name = '-' WHERE id = 320"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate( + "INSERT INTO empsamp(id, name, dept, job, salary)" + + " VALUES(380, 'Pearce', 38, 'Clerk', 13217.50)," + + " (390, 'Hachey', 38, 'Mgr', 21270.00)," + + " (400, 'Wagland', 38, 'Clerk', 14575.00)"); + + stmt.executeUpdate("UPDATE empsamp SET job = 'Mgr' WHERE id = 310"); + stmt.executeUpdate("UPDATE empsamp " + + " SET job = 'Sales', salary = 15000.00" + + " WHERE id = 350"); + stmt.executeUpdate("UPDATE empsamp SET name = '-' WHERE id = 320"); + stmt.close(); + + // display the content of the final 'empsamp' table + TbContentDisplay(conn, "empsamp"); + + // commit the transaction + conn.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // ChangeTable + + // This method applies the changes from the 'empsamp' table + // to the 'staff' table using the MERGE statement + public static void MergeTables(Connection conn) + { + try + { + System.out.println( + "\n -----------------------------------------------------------" + + "\n USE THE SQL STATEMENT:\n" + + " MERGE\n" + + " TO APPLY CHANGES FROM TABLE 'empsamp' TO TABLE 'staff'\n"); + + // display the initial contents of the 'staff' table + TbContentDisplay(conn, "staff"); + + // apply changes from the 'empsamp' table to the 'staff' table + // with the MERGE statement + System.out.println( + "\n Merge tables" + + "\n Invoke the statement:\n" + + "\n MERGE INTO staff S" + + "\n USING (SELECT * FROM empsamp) E" + + "\n ON (S.id = E.id)" + + "\n WHEN MATCHED AND E.name != '-' THEN" + + "\n UPDATE SET (name, dept, job, years, salary, comm) =" + + "\n (E.name, E.dept, E.job, E.years," + + " E.salary, E.comm)" + + "\n WHEN NOT MATCHED THEN" + + "\n INSERT (id, name, dept, job, years, salary, comm)" + + "\n VALUES (E.id, E.name, E.dept, E.job, E.years," + + " E.salary, E.comm)" + + "\n ELSE" + + "\n IGNORE\n"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate( + "MERGE INTO staff S" + + " USING (SELECT * FROM empsamp) E" + + " ON (S.id = E.id)" + + " WHEN MATCHED AND E.name != '-' THEN" + + " UPDATE SET (name, dept, job, years, salary, comm) =" + + " (E.name, E.dept, E.job, E.years, E.salary, E.comm)" + + " WHEN NOT MATCHED THEN" + + " INSERT (id, name, dept, job, years, salary, comm)" + + " VALUES (E.id, E.name, E.dept, E.job, E.years," + + " E.salary, E.comm)" + + " ELSE" + + " IGNORE"); + + stmt.close(); + + // display the contents of the final 'staff' table + TbContentDisplay(conn, "staff"); + + // rollback the transaction + conn.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // MergeTables + + // helping function: Display the contents of the 'staff' or 'empsamp' table + public static void TbContentDisplay(Connection conn, String tablename) + { + try + { + Integer id = new Integer(0); + String name = null; + Integer dept = new Integer(0); + String job = null; + Integer years = new Integer(0); + Double salary = new Double(0.0); + Double comm = new Double(0.0); + + System.out.println(); + System.out.println( + " SELECT * FROM " + tablename + " WHERE id >= 310\n" + + " ID NAME DEPT JOB YEARS SALARY COMM\n" + + " --- -------- ---- ----- ----- -------- --------"); + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT * FROM " + tablename + " WHERE id >= 310"); + + while (rs.next()) + { + id = Integer.valueOf(rs.getString(1)); + name = rs.getString(2); + dept = Integer.valueOf(rs.getString(3)); + job = rs.getString(4); + if (rs.getString(5) == null) + { + years = null; + } + else + { + years = Integer.valueOf(rs.getString(5)); + } + salary = Double.valueOf(Double.toString(rs.getDouble(6))); + if (rs.getDouble(7) == 0.0) + { + comm = null; + } + else + { + comm = Double.valueOf(Double.toString(rs.getDouble(7))); + } + + System.out.print(" "+Data.format(id, 3) + + " " + Data.format(name, 8) + + " " + Data.format(dept, 4)); + if (job != null) + { + System.out.print(" " + Data.format(job, 5)); + } + else + { + System.out.print(" -"); + } + if (years != null) + { + System.out.print(" " + Data.format(years, 5)); + } + else + { + System.out.print(" -"); + } + + System.out.print(" " + Data.format(salary, 7, 2)); + if (comm != null) + { + System.out.print(" " + Data.format(comm, 7, 2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } // TbContentDisplay + +} // TbMerge diff --git a/java/jdbc/TbMod.java b/java/jdbc/TbMod.java new file mode 100644 index 0000000..0e3e67b --- /dev/null +++ b/java/jdbc/TbMod.java @@ -0,0 +1,1072 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbMod.java +// +// SAMPLE: How to modify table data +// +// SQL Statements USED: +// SELECT +// UPDATE +// DELETE +// ROLLBACK +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// OUTPUT FILE: TbMod.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbMod +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO MODIFY TABLE DATA."); + + // connect to the 'sample' database + db.connect(); + + // different ways to INSERT table data + insertUsingValues(db.con); + insertUsingFullselect(db.con); + + // different ways to UPDATE table data + updateWithoutSubqueries(db.con); + updateUsingSubqueryInSetClause(db.con); + updateUsingSubqueryInWhereClause(db.con); + updateUsingCorrelatedSubqueryInSetClause(db.con); + updateUsingCorrelatedSubqueryInWhereClause(db.con); + positionedUpdateWithoutSubqueries(db.con); + + // Known problem. Bug reported. + // The following two functions does not work properly due to + // CLI Driver Error? Is subquery support? + // e.g.1 "UPDATE staff SET col2 = '1000' WHERE CURRENT OF " + // + cursName + + positionedUpdateUsingSubqueryInSetClause(db.con); + positionedUpdateUsingCorrelatedSubqueryInSetClause(db.con); + + // different ways to DELETE table data + deleteWithoutSubqueries(db.con); + deleteUsingSubqueryInWhereClause(db.con); + deleteUsingCorrelatedSubqueryInWhereClause(db.con); + positionedDelete(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // helping function: Display the content of the 'staff' table + static void staffTbContentDisplay(Connection con) + { + try + { + Integer id = new Integer(0); + String name = null; + Integer dept = new Integer(0); + String job = null; + Integer years = new Integer(0); + Double salary = new Double(0.0); + Double comm = new Double(0.0); + + System.out.println(); + System.out.println( + " SELECT * FROM staff WHERE id >= 310\n" + + " ID NAME DEPT JOB YEARS SALARY COMM\n" + + " --- -------- ---- ----- ----- -------- --------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT * FROM staff WHERE id >= 310"); + + while (rs.next()) + { + id = Integer.valueOf(rs.getString(1)); + name = rs.getString(2); + dept = Integer.valueOf(rs.getString(3)); + job = rs.getString(4); + if (rs.getString(5) == null) + { + years = null; + } + else + { + years = Integer.valueOf(rs.getString(5)); + } + salary = Double.valueOf(Double.toString(rs.getDouble(6))); + if (rs.getDouble(7) == 0.0) + { + comm = null; + } + else + { + comm = Double.valueOf(Double.toString(rs.getDouble(7))); + } + + System.out.print(" "+Data.format(id, 3) + + " " + Data.format(name, 8) + + " " + Data.format(dept, 4)); + if (job != null) + { + System.out.print(" " + Data.format(job, 5)); + } + else + { + System.out.print(" -"); + } + if (years != null) + { + System.out.print(" " + Data.format(years, 5)); + } + else + { + System.out.print(" -"); + } + + System.out.print(" " + Data.format(salary, 7, 2)); + if (comm != null) + { + System.out.print(" " + Data.format(comm, 7, 2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // staffTbContentDisplay + + // helping function: Display part of the content of the 'employee' table + static void employeeTbPartialContentDisplay(Connection con) + { + try + { + String empno = null; + Double salary = new Double(0.0); + String workdept = null; + + System.out.println(); + System.out.println(" SELECT empno, salary, workdept\n" + + " FROM employee\n" + + " WHERE workdept = 'E11'\n" + + " EMPNO SALARY WORKDEPT\n" + + " ------ ---------- --------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT empno, salary, workdept " + + " FROM employee " + + " WHERE workdept = 'E11'"); + + while (rs.next()) + { + empno = rs.getString(1); + salary = Double.valueOf(Double.toString(rs.getDouble(2))); + workdept = rs.getString(3); + + System.out.println(" "+Data.format(empno, 6) + + " " + Data.format(salary, 9, 2) + + " " + Data.format(workdept, 8)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // employeeTbPartialContentDisplay + + // This function demonstrates how to insert table data using VALUES + static void insertUsingValues(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO INSERT TABLE DATA USING VALUES."); + + // display the initial content of the 'staff' table + staffTbContentDisplay(con); + + // INSERT data INTO a table using VALUES + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " INSERT INTO staff(id, name, dept, job, salary)\n" + + " VALUES(380, 'Pearce', 38, 'Clerk', 13217.50),\n" + + " (390, 'Hachey', 38, 'Mgr', 21270.00),\n" + + " (400, 'Wagland', 38, 'Clerk', 14575.00)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO staff(id, name, dept, job, salary) " + + " VALUES(380, 'Pearce', 38, 'Clerk', 13217.50), "+ + " (390, 'Hachey', 38, 'Mgr', 21270.00), " + + " (400, 'Wagland', 38, 'Clerk', 14575.00) "); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // insertUsingValues + + // This function demonstrates how to insert table data using + // FULLSELECT + static void insertUsingFullselect(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO INSERT TABLE DATA USING FULLSELECT."); + + // display the initial content of the 'staff' table + staffTbContentDisplay(con); + + // INSERT data INTO a table using FULLSELECT + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " INSERT INTO staff(id, name, dept, salary)\n" + + " SELECT INTEGER(empno)+100, lastname, 77, salary\n"+ + " FROM employee\n" + + " WHERE INTEGER(empno) >= 310" + + " AND INTEGER(empno) <= 340"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO staff(id, name, dept, salary) " + + " SELECT INTEGER(empno) + 100, lastname, 77, salary " + + " FROM employee " + + " WHERE INTEGER(empno) >= 310" + + " AND INTEGER(empno) <= 340"); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // insertUsingFullselect + + // This function demonstrates how to update table data + static void updateWithoutSubqueries(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // update table data + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff\n" + + " SET salary = salary + 1000\n" + + " WHERE id >= 310 AND dept = 84"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("UPDATE staff " + + " SET salary = salary + 1000 " + + " WHERE id >= 310 AND dept = 84"); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // updateWithoutSubqueries + + // This function demonstrates how to update table data using + // subquery in the SET clause + static void updateUsingSubqueryInSetClause(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA\n" + + "USING SUBQUERY IN 'SET' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // update data of the table 'staff' by using subquery in the SET + // clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff\n" + + " SET salary = (SELECT MIN(salary)\n" + + " FROM staff\n" + + " WHERE id >= 310)\n" + + " WHERE id = 350"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE staff " + + " SET salary = (SELECT MIN(salary) " + + " FROM staff " + + " WHERE id >= 310) " + + " WHERE id = 350"); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // updateUsingSubqueryInSetClause + + // This function demonstrates how to update table data using subquery + // in the WHERE clause. + static void updateUsingSubqueryInWhereClause(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA\n" + + "USING SUBQUERY IN 'WHERE' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // update table data using subquery in WHERE clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff\n" + + " SET comm = 250.00\n" + + " WHERE dept = 84 AND\n" + + " salary < (SELECT AVG(salary)\n" + + " FROM staff\n" + + " WHERE id >= 310 AND dept = 84)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE staff " + + " SET comm = 250.00 " + + " WHERE dept = 84 AND " + + " salary < (SELECT AVG(salary) " + + " FROM staff " + + " WHERE id >= 310 AND dept = 84)"); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // updateUsingSubqueryInWhereClause + + // This function demonstrates how to update table data using + // correlated subquery in the 'SET' clause. + static void updateUsingCorrelatedSubqueryInSetClause(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA\n" + + "USING CORRELATED SUBQUERY IN 'SET' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // update data of the 'staff' table using correlated subquery in + // the 'SET' clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff s1\n" + + " SET comm = 0.01 * (SELECT MIN(salary)\n" + + " FROM staff s2\n" + + " WHERE id >= 310 AND\n" + + " s2.dept = s1.dept)\n" + + " WHERE id >= 340"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE staff s1 " + + " SET comm = 0.01 * (SELECT MIN(salary) " + + " FROM staff s2 " + + " WHERE id >= 310 AND " + + " s2.dept = s1.dept) " + + " WHERE id >= 340 "); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // updateUsingCorrelatedSubqueryInSetClause + + // This function demonstrates how to update table data using + // correlated subquery in the 'WHERE' clause. + static void updateUsingCorrelatedSubqueryInWhereClause(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA\n" + + "USING CORRELATED SUBQUERY IN 'WHERE' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // update data of the 'staff' table using correlated subquery in the + // 'WHERE' clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff s1\n" + + " SET comm = 700\n" + + " WHERE id >= 340 AND\n" + + " salary < (SELECT AVG(salary)\n" + + " FROM staff s2\n" + + " WHERE id >= 310 AND\n" + + " s2.dept = s1.dept)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE staff s1 " + + " SET comm = 700 " + + " WHERE id >= 340 AND " + + " salary < (SELECT AVG(salary) " + + " FROM staff s2 " + + " WHERE id >= 310 AND " + + " s2.dept = s1.dept)"); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // updateUsingCorrelatedSubqueryInWhereClause + + // This function demonstrates how to perform positioned update on a table + static void positionedUpdateWithoutSubqueries(Connection con) + { + try + { + String name = null; + int dept = 0; + String curName = null; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + " UPDATE\n" + + "TO PERFORM POSITIONED UPDATE ON A TABLE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Invoke the statements:\n" + + " get a ResultSet rs for\n" + + " SELECT name, dept\n" + + " FROM staff\n" + + " WHERE id >= 310\n" + + " FOR UPDATE OF comm\n" + + "\n" + + " curName = rs.getCursorName();\n" + + " while (rs.next())\n" + + " {\n" + + " if (dept != 84)\n" + + " {\n"+ + " UPDATE staff\n"+ + " SET comm = NULL\n"+ + " WHERE CURRENT OF curName\n" + + " }\n" + + " }"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT name, dept " + + " FROM staff " + + " WHERE id >= 310 " + + " FOR UPDATE OF comm"); + + curName = rs.getCursorName(); + Statement stmt1 = con.createStatement(); + while (rs.next()) + { + dept = rs.getInt(2); + if (dept != 84) + { + stmt1.executeUpdate("UPDATE staff " + + " SET comm = NULL " + + " WHERE CURRENT OF " + curName); + } + } + stmt1.close(); + rs.close(); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // positionedUpdateWithoutSubqueries + + // This function demonstrates how to perform positioned update on a table + // using subquery in the 'SET' clause. + static void positionedUpdateUsingSubqueryInSetClause(Connection con) + { + try + { + String name = null; + int dept = 0; + String curName = null; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " UPDATE\n" + + " SELECT\n" + + "TO PERFORM POSITIONED UPDATE ON A TABLE\n" + + "USING SUBQUERY IN 'SET' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Invoke the statements:\n" + + " get a ResultSet rs for\n" + + " SELECT name, dept\n" + + " FROM staff\n" + + " WHERE id >= 310\n" + + " FOR UPDATE OF comm\n" + + "\n" + + " curName = rs.getCursorName();\n" + + " while (rs.next())\n" + + " {\n" + + " if (dept != 84)\n" + + " {\n" + + " UPDATE staff\n" + + " SET comm = 0.01 * (SELECT AVG(salary)\n" + + " FROM staff\n" + + " WHERE id >= 310)\n" + + " WHERE CURRENT OF curName\n" + + " }\n" + + " }"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT name, dept " + + " FROM staff " + + " WHERE id >= 310 " + + " FOR UPDATE OF comm"); + + curName = rs.getCursorName(); + Statement stmt1 = con.createStatement(); + while (rs.next()) + { + dept = rs.getInt(2); + if (dept != 84) + { + stmt1.executeUpdate( + "UPDATE staff " + + " SET comm = 0.01 * (SELECT AVG(salary) " + + " FROM staff " + + " WHERE id >= 310) " + + " WHERE CURRENT OF " + curName); + } + } + stmt1.close(); + rs.close(); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // positionedUpdateUsingSubqueryInSetClause + + // This function demonstrates how to perform positioned update on a table + // using correlated subquery in the 'SET' clause + static void + positionedUpdateUsingCorrelatedSubqueryInSetClause(Connection con) + { + try + { + String name = null; + int dept = 0; + String curName = null; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " UPDATE\n" + + " SELECT\n" + + "TO PERFORM POSITIONED UPDATE ON A TABLE\n" + + "USING CORRELATED SUBQUERY IN 'SET' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Invoke the statements:\n" + + " get a ResultSet rs for\n" + + " SELECT name, dept\n" + + " FROM staff\n" + + " WHERE id >= 310\n" + + " FOR UPDATE OF comm\n" + + "\n" + + " curName = rs.getCursorName();\n" + + " while (rs.next())\n" + + " {\n" + + " if (dept != 84)\n" + + " {\n" + + " UPDATE staff s1\n" + + " SET comm = 0.01 * (SELECT AVG(salary)\n"+ + " FROM staff s2\n" + + " WHERE id >= 310 AND\n" + + " s2.dept = s1.dept)\n" + + " WHERE CURRENT OF curName\n" + + " }\n" + + " }"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT name, dept " + + " FROM staff " + + " WHERE id >= 310 " + + " FOR UPDATE OF comm"); + + curName = rs.getCursorName(); + Statement stmt1 = con.createStatement(); + while (rs.next()) + { + dept = rs.getInt(2); + if (dept != 84) + { + stmt1.executeUpdate( + "UPDATE staff s1 " + + " SET comm = 0.01 * (SELECT AVG(salary) " + + " FROM staff s2 " + + " WHERE id >= 310 AND " + + " s2.dept = s1.dept) " + + " WHERE CURRENT OF " + curName); + } + } + stmt1.close(); + rs.close(); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // updateUsingCorrelatedSubqueryInSetClause + + // This function demonstrates how to delete table data + static void deleteWithoutSubqueries(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO DELETE TABLE DATA."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // delete data from the 'staff' table without subqueries + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " DELETE FROM staff WHERE id >= 310 AND salary > 20000 AND job != 'Sales'\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "DELETE FROM staff WHERE id >= 310 AND salary > 20000 AND job != 'Sales'"); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // deleteWithoutSubqueries + + // This function demonstrates how to delete table data using + // subquery in the 'WHERE' clause. + static void deleteUsingSubqueryInWhereClause(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO DELETE TABLE DATA\n" + + "USING SUBQUERY IN 'WHERE' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // display a partial content of the 'employee' table + employeeTbPartialContentDisplay(con); + + // delete data from the 'staff' table using subquery in the 'WHERE' + // clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " DELETE FROM staff\n" + + " WHERE id >= 310 AND\n" + + " job != 'Sales' AND\n" + + " salary > (SELECT AVG(salary)\n" + + " FROM employee\n" + + " WHERE workdept = 'E11')"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "DELETE FROM staff " + + " WHERE id >= 310 AND " + + " job != 'Sales' AND " + + " salary > (SELECT AVG(salary) " + + " FROM employee " + + " WHERE workdept = 'E11')"); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // deleteUsingSubqueryInWhereClause + + // This function demonstrates how to delete table data using + // correlated subquery in the 'WHERE' clause. + static void deleteUsingCorrelatedSubqueryInWhereClause(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO DELETE TABLE DATA\n" + + "USING A CORRELATED SUBQUERY IN 'WHERE' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // delete data from the 'staff' table using correlated subquery in the + // 'WHERE' clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " DELETE FROM staff s1\n" + + " WHERE id >= 310 AND\n" + + " job != 'Sales' AND\n" + + " salary < (SELECT AVG(salary)\n" + + " FROM staff s2\n" + + " WHERE s2.dept = s1.dept)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "DELETE FROM staff s1 " + + " WHERE id >= 310 AND " + + " job != 'Sales' AND " + + " salary < (SELECT AVG(salary) " + + " FROM staff s2 " + + " WHERE s2.dept = s1.dept)"); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // TbDeleteUsingCorrelatedSubqueryInWhereClause + + // This function demonstrates how to perform positioned delete on a table + static void positionedDelete(Connection con) + { + try + { + String name = null; + int dept = 0; + String curName = null; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DELETE\n" + + "TO PERFORM POSITIONED DELETE ON A TABLE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Invoke the statements:\n" + + " get a ResultSet rs for\n" + + " SELECT name, dept FROM staff WHERE id >= 310 AND job != 'Sales' FOR UPDATE\n" + + "\n" + + " curName = rs.getCursorName();\n" + + " while (rs.next())\n" + + " {\n" + + " if (dept != 84)\n" + + " {\n" + + " DELETE FROM staff WHERE CURRENT OF curName\n" + + " }\n" + + " }"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT name, dept FROM staff WHERE id >= 310 AND job != 'Sales' FOR UPDATE"); + + curName = rs.getCursorName(); + Statement stmt1 = con.createStatement(); + while (rs.next()) + { + dept = rs.getInt(2); + if (dept != 84) + { + stmt1.executeUpdate( + "DELETE FROM staff WHERE CURRENT OF " + curName); + } + } + stmt1.close(); + rs.close(); + stmt.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(con); + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction..."); + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // positionedDelete */ +} // TbMod + diff --git a/java/jdbc/TbOnlineInx.java b/java/jdbc/TbOnlineInx.java new file mode 100644 index 0000000..425686e --- /dev/null +++ b/java/jdbc/TbOnlineInx.java @@ -0,0 +1,317 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbOnlineInx.java +// +// SAMPLE: How to create and reorg indexes on a table +// +// SQL STATEMENTS USED: +// INCLUDE +// CREATE INDEX +// DROP INDEX +// REORG +// LOCK +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// File +// FileWriter +// Process +// BufferedReader +// InputStreamReader +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbOnlineInx.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import java.lang.*; +import java.io.*; + +public class TbOnlineInx +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CREATE AND REORG ONLINE INDEXES\n" + + "ON TABLES."); + + // connect to the 'sample' database + db.connect(); + + // create online index on a table + createIndex(db.con); + + // reorg online index on a table + reorgIndex(db.con); + + // drop online index created + dropIndex(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // How to create an index on a table with different levels + // of access to the table like read-write, read-only, no access + static void createIndex(Connection conn) throws Exception + { + + System.out.print( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT\n" + + " CREATE INDEX\n" + + "TO CREATE AN INDEX\n"); + + // create an online index with read-write access to the table + System.out.print( + "\nTo create an index on a table allowing read-write access\n" + + "to the table, use the following SQL command:\n\n" + + " CREATE INDEX index1 ON employee (lastname ASC)\n"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate("CREATE INDEX index1 ON employee (lastname ASC)"); + conn.commit(); + + dropIndex(conn); + + // create an index on a table while allowing only read access to it + System.out.println( + "\nTo create an index on a table allowing only read access\n" + + "to the table, use the following two SQL commands:\n\n" + + " LOCK TABLE employee IN SHARE MODE\n" + + " CREATE INDEX index1 ON employee (lastname ASC)"); + + stmt.executeUpdate("LOCK TABLE employee IN SHARE MODE"); + conn.commit(); + + stmt.executeUpdate("CREATE INDEX index1 ON employee (lastname ASC)"); + conn.commit(); + + dropIndex(conn); + + // create an online index allowing no access to the table + System.out.println( + "\nTo create an index on a table allowing no access to the \n" + + "table (only uncommitted readers allowed), use the \n" + + "following two SQL statements:\n\n" + + " LOCK TABLE employee IN EXCLUSIVE MODE\n" + + " CREATE INDEX index1 ON employee (lastname ASC)"); + + stmt.executeUpdate("LOCK TABLE employee IN EXCLUSIVE MODE"); + conn.commit(); + + stmt.executeUpdate("CREATE INDEX index1 ON employee (lastname ASC)"); + conn.commit(); + + stmt.close(); + } // createIndex + + // Create 3 CLP files for REORG command with write, read and no access, + // respectively. + static void createFiles(Connection conn) throws Exception + { + // get fully qualified name of the table + String tableName = "EMPLOYEE"; + String schemaName = getSchemaName(conn, tableName); + String fullTableName = schemaName + "." + tableName; + + // reorg command has to be executed with three different options, namely, + // 'with write access', 'with read access' and 'with no access' + String[] fileNames = { "ReorgCmdAllowWrite.db2", + "ReorgCmdAllowRead.db2", + "ReorgCmdAllowNone.db2" }; + + String[] options = { " WRITE ACCESS", + " READ ACCESS", + " NO ACCESS" }; + + for (int i = 0; i < 3; i++) + { + // create a CLP file with the REORG command and execute the file + File outputFile = new File(fileNames[i]); + FileWriter out = new FileWriter(outputFile); + + out.write("CONNECT TO SAMPLE;\n"); + out.write("REORG INDEXES ALL FOR TABLE " + fullTableName + + " ALLOW" + options[i] + ";\n"); + out.write("CONNECT RESET;"); + out.close(); + + // on exit, delete the temporary files created + outputFile.deleteOnExit(); + } + } //createFiles + + // How to reorg an index on a table with different levels of + // access to the table like read-write, read-only, no access + static void reorgIndex(Connection conn) + { + System.out.print( + "\n-----------------------------------------------------------\n" + + "\nUSE THE SQL STATEMENT:\n"+ + " REORG\n" + + "TO REORGANIZE A TABLE OR INDEX\n"); + + + String[] fileNames = { "ReorgCmdAllowWrite.db2", + "ReorgCmdAllowRead.db2", + "ReorgCmdAllowNone.db2" }; + + String[] options = { " write access", + " read access", + " no access" }; + try + { + // create 3 files with REORG commands + createFiles(conn); + + for (int i = 0; i < 3; i++) + { + System.out.println( + "\nReorganize the indexes on a table allowing" + options[i] + + "\n-----------------------------------------------------------"); + + String s = null; + String execCmd = "db2 -tvf " + fileNames[i]; + + // execute the command to run the CLP file + Process p = Runtime.getRuntime().exec(execCmd); + + // open streams for the process's input and error + BufferedReader stdInput = new BufferedReader(new + InputStreamReader(p.getInputStream())); + BufferedReader stdError = new BufferedReader(new + InputStreamReader(p.getErrorStream())); + + // read the output from the command and set the output variable with + // the value + while ((s = stdInput.readLine()) != null) + { + System.out.println(s); + } + + // read any errors from the attempted command and set the error + // variable with the value + while ((s = stdError.readLine()) != null) + { + System.out.println(s); + } + + p.destroy(); + + } // for + } // try + + catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + } // reorgIndex + + // How to drop the index on a table + static void dropIndex(Connection conn) + { + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " DROP\n" + + "TO DROP AN INDEX:"); + try + { + // drop the indexes + System.out.println( + " Execute the statement\n" + + " DROP INDEX index1\n" + + "\n-----------------------------------------------------------"); + Statement stmt = conn.createStatement(); + stmt.executeUpdate("DROP INDEX index1"); + conn.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // dropIndex + + // function to get the schema name for a particular table + static String getSchemaName(Connection conn, String tableName) throws Exception + { + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT tabschema "+ + " FROM syscat.tables "+ + " WHERE tabname = '"+ tableName + "'"); + + boolean result = rs.next(); + String schemaName = rs.getString("tabschema"); + rs.close(); + stmt.close(); + + // remove the trailing white space characters from schemaName before + // returning it to the calling function + return schemaName.trim(); + } // getSchemaName +} // TbOnlineInx diff --git a/java/jdbc/TbPriv.java b/java/jdbc/TbPriv.java new file mode 100644 index 0000000..0b7bb90 --- /dev/null +++ b/java/jdbc/TbPriv.java @@ -0,0 +1,225 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbPriv.java +// +// SAMPLE: How to grant, display and revoke privileges on a table +// +// SQL Statements USED: +// GRANT (Table, View, or Nickname Privileges) +// SELECT +// REVOKE (Table, View, or Nickname Privileges) +// COMMIT +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbPriv.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbPriv +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO GRANT, DISPLAY AND REVOKE \n" + + "PRIVILEGES ON A TABLE."); + + // connect to the 'sample' database + db.connect(); + + grant(db.con); + display(db.con); + revoke(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void grant(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " GRANT (Table, View, or Nickname Privileges)\n" + + " COMMIT\n" + + "TO GRANT PRIVILEGES ON A TABLE."); + + System.out.println(); + System.out.println( + " GRANT SELECT, INSERT, UPDATE(salary, comm)\n" + + " ON TABLE staff\n" + + " TO USER user1"); + + try + { + Statement stmt = con.createStatement(); + + stmt.execute("GRANT SELECT, INSERT, UPDATE(salary, comm) " + + " ON TABLE staff" + + " TO USER user1"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // grant + + static void display(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " SELECT\n" + + "TO DISPLAY PRIVILEGES ON A TABLE."); + + System.out.println(); + System.out.println( + " SELECT granteetype, controlauth, alterauth,\n" + + " deleteauth, indexauth, insertauth,\n" + + " selectauth, refauth, updateauth\n" + + " FROM syscat.tabauth\n" + + " WHERE grantee = 'USER1' AND\n" + + " tabname = 'STAFF'"); + + try + { + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT granteetype, controlauth, alterauth, " + + " deleteauth, indexauth, insertauth, " + + " selectauth, refauth, updateauth " + + " FROM syscat.tabauth " + + " WHERE grantee = 'USER1' AND " + + " tabname = 'STAFF' "); + + boolean result = rs.next(); + String granteetype = rs.getString(1); + String controlauth = rs.getString(2); + String alterauth = rs.getString(3); + String deleteauth = rs.getString(4); + String indexauth = rs.getString(5); + String insertauth = rs.getString(6); + String selectauth = rs.getString(7); + String refauth = rs.getString(8); + String updateauth = rs.getString(9); + + rs.close(); + stmt.close(); + + System.out.println(); + System.out.println( + " Grantee Type = " + granteetype + "\n" + + " CONTROL priv. = " + controlauth + "\n" + + " ALTER priv. = " + alterauth + "\n" + + " DELETE priv. = " + deleteauth + "\n" + + " INDEX priv. = " + indexauth + "\n" + + " INSERT priv. = " + insertauth + "\n" + + " SELECT priv. = " + selectauth + "\n" + + " REFERENCES priv. = " + refauth + "\n" + + " UPDATE priv. = " + updateauth); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // display + + static void revoke(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " REVOKE (Table, View, or Nickname Privileges)\n" + + " COMMIT\n" + + "TO REVOKE PRIVILEGES ON A TABLE."); + + System.out.println(); + System.out.println(" REVOKE SELECT, INSERT, UPDATE\n" + + " ON TABLE staff\n" + + " FROM USER user1"); + + try + { + Statement stmt = con.createStatement(); + + stmt.execute("REVOKE SELECT, INSERT, UPDATE " + + " ON TABLE staff" + + " FROM USER user1"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // revoke +} // TbPriv + diff --git a/java/jdbc/TbRead.java b/java/jdbc/TbRead.java new file mode 100644 index 0000000..7374c82 --- /dev/null +++ b/java/jdbc/TbRead.java @@ -0,0 +1,1501 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbRead.java +// +// SAMPLE: How to read table data +// +// SQL Statements USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbRead.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbRead +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO READ TABLE DATA."); + + // connect to the 'sample' database + db.connect(); + + // different ways to read table data + execQuery(db.con); + execPreparedQuery(db.con); + execPreparedQueryWithParam(db.con); + execPreparedQueryWithUnknownOutputColumn(db.con); + + mostSimpleSubselect(db.con); + basicSubselect(db.con); + groupBySubselect(db.con); + subselect(db.con); + rowSubselect(db.con); + fullselect(db.con); + selectStatement(db.con); + + basicSubselectFromMultipleTables(db.con); + basicSubselectFromJoinedTable(db.con); + basicSubselectUsingSubquery(db.con); + basicSubselectUsingCorrelatedSubquery(db.con); + + subselectUsingGroupingSets(db.con); + subselectUsingRollup(db.con); + subselectUsingCube(db.con); + selectUsingQuerySampling(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // helping function + static void OrgTbContentDisplay(Connection con) + { + try + { + int deptnumb = 0; + String deptname = ""; + int manager = 0; + String division = ""; + String location = ""; + + System.out.println(); + System.out.println(" SELECT * FROM org"); + System.out.println( + " DEPTNUMB DEPTNAME MANAGER DIVISION LOCATION\n" + + " -------- -------------- ------- ---------- --------------"); + + Statement stmt = con.createStatement(); + // perform a SELECT against the "org" table in the sample database. + ResultSet rs = stmt.executeQuery("SELECT * FROM org"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + deptnumb = rs.getInt(1); + deptname = rs.getString(2); + manager = rs.getInt(3); + division = rs.getString(4); + location = rs.getString(5); + + System.out.println( + " " + + Data.format(deptnumb, 8) + " " + + Data.format(deptname, 14) + " " + + Data.format(manager, 7) + " " + + Data.format(division, 10) + " " + + Data.format(location, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // OrgTableContentDisplay + + // helping function + static void DepartmentTbContentDisplay(Connection con) + { + try + { + String deptno = ""; + String departmentDeptname = ""; + String mgrno = ""; + String admrdept = ""; + String departmentLocation = ""; + + System.out.println(); + System.out.println( + " SELECT * FROM department"); + System.out.println( + " DEPTNO DEPTNAME MGRNO ADMRDEPT LOCATION"); + System.out.println( + " ------ ---------------------------- ------ -------- --------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM department"); + + while (rs.next()) + { + deptno = rs.getString(1); + departmentDeptname = rs.getString(2); + mgrno = rs.getString(3); + admrdept = rs.getString(4); + departmentLocation = rs.getString(5); + + System.out.print(" " + + Data.format(deptno, 6) + " " + + Data.format(departmentDeptname, 28)); + + if (mgrno != null) + { + System.out.print(" " + Data.format(mgrno, 6)); + } + else + { + System.out.print(" - "); + } + System.out.print(" " + Data.format(admrdept,8)); + if (departmentLocation != null) + { + System.out.print(" " + + Data.format(departmentLocation, 16)); + } + else + { + System.out.print(" - "); + } + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // DepartmentTbContentDisplay + + // helping function + static void EmployeeTbPartialContentDisplay(Connection con) + { + try + { + String job = ""; + int edlevel = 0; + double comm = 0.0; + + System.out.println(); + System.out.println(" Perform:\n" + + " SELECT job, edlevel, comm\n" + + " FROM employee\n" + + " WHERE job IN('DESIGNER', 'FIELDREP')\n" + + "\n" + + " Results:\n" + + " JOB EDLEVEL COMM\n" + + " -------- ------- -----------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT job, edlevel, comm " + + " FROM employee " + + " WHERE job IN('DESIGNER', 'FIELDREP')"); + + while (rs.next()) + { + job = rs.getString(1); + edlevel = rs.getInt(2); + comm = rs.getDouble(3); + + System.out.println(" " + + Data.format(job, 8) + " " + + Data.format(edlevel, 7) + " " + + Data.format(comm, 10, 2)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // EmployeeTbPartialContentDisplay + + static void execQuery(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " Statement\n" + + "TO EXECUTE A QUERY."); + + Statement stmt = con.createStatement(); + + // execute the query + System.out.println(); + System.out.println( + " Execute Statement:\n" + + " SELECT deptnumb, location FROM org WHERE deptnumb < 25"); + + ResultSet rs = stmt.executeQuery( + "SELECT deptnumb, location FROM org WHERE deptnumb < 25 "); + + System.out.println(); + System.out.println(" Results:\n" + + " DEPTNUMB LOCATION\n" + + " -------- --------------"); + + int deptnumb = 0; + String location = ""; + while (rs.next()) + { + deptnumb = rs.getInt(1); + location = rs.getString(2); + + System.out.println(" " + + Data.format(deptnumb, 8) + " " + + Data.format(location, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + static void execPreparedQuery(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " PreparedStatement\n" + + "TO EXECUTE A PREPARED QUERY."); + + Statement stmt = con.createStatement(); + + // prepare the query + System.out.println(); + System.out.println( + " Prepare Statement:\n" + + " SELECT deptnumb, location FROM org WHERE deptnumb < 25"); + + PreparedStatement pstmt = con.prepareStatement( + "SELECT deptnumb, location FROM org WHERE deptnumb < 25 "); + + System.out.println(); + System.out.println(" Execute prepared statement"); + ResultSet rs = pstmt.executeQuery(); + + System.out.println(); + System.out.println(" Results:\n" + + " DEPTNUMB LOCATION\n" + + " -------- --------------"); + + int deptnumb = 0; + String location = ""; + while (rs.next()) + { + deptnumb = rs.getInt(1); + location = rs.getString(2); + + System.out.println(" " + + Data.format(deptnumb, 8) + " " + + Data.format(location, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + static void execPreparedQueryWithParam(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " PreparedStatement\n" + + "TO EXECUTE A PREPARED QUERY WITH PARAMETERS."); + + Statement stmt = con.createStatement(); + + // prepare the query + System.out.println(); + System.out.println( + " Prepare Statement:\n" + + " SELECT deptnumb, location FROM org WHERE deptnumb < ?"); + + PreparedStatement pstmt = con.prepareStatement( + "SELECT deptnumb, location FROM org WHERE deptnumb < ?"); + + System.out.println(); + System.out.println(" Set parameter value: parameter 1 = 25"); + + pstmt.setInt(1, 25); + + System.out.println(); + System.out.println(" Execute prepared statement"); + ResultSet rs = pstmt.executeQuery(); + + System.out.println(); + System.out.println(" Results:\n" + + " DEPTNUMB LOCATION\n" + + " -------- --------------"); + + int deptnumb = 0; + String location = ""; + while (rs.next()) + { + deptnumb = rs.getInt(1); + location = rs.getString(2); + + System.out.println( + " " + + Data.format(deptnumb, 8) + " " + + Data.format(location, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + static void execPreparedQueryWithUnknownOutputColumn(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " PreparedStatement\n" + + "TO EXECUTE A PREPARED QUERY WITH UNKNOWN OUTPUT COLUMNS."); + + Statement stmt = con.createStatement(); + + // prepare the query + System.out.println(); + System.out.println(" Prepare Statement:\n" + + " SELECT * FROM org WHERE deptnumb < 25"); + + PreparedStatement pstmt = con.prepareStatement( + "SELECT * FROM org WHERE deptnumb < 25"); + + System.out.println(); + System.out.println(" Execute prepared statement"); + ResultSet rs = pstmt.executeQuery(); + + ResultSetMetaData rsms = rs.getMetaData(); + int colCount = rsms.getColumnCount(); + int[] colSize = new int[colCount]; + String[] colLabel = new String[colCount]; + String[] colTypeName = new String[colCount]; + + for (int i = 0 ; i < colCount ; i++) + { + colSize[i] = rsms.getColumnDisplaySize(i+1); + colLabel[i] = rsms.getColumnLabel(i+1); + colTypeName[i] = rsms.getColumnTypeName(i+1); + } + + System.out.println(); + System.out.print(" Results:\n" + + " "); + + // print the columns' name + for (int i = 0 ; i < colCount ; i++) + { + System.out.print(colLabel[i] + " "); + int spaceCounter = colLabel[i].length(); + while (spaceCounter < colSize[i]) + { + System.out.print(" "); + spaceCounter++; + } + } + System.out.println(); + + // print the line under each column's name + int[] actualColSize = new int[colCount]; + System.out.print(" "); + for (int i = 0 ; i < colCount ; i++) + { + int dashCounter = 0; + while (dashCounter < colSize[i] || + dashCounter < colLabel[i].length()) + { + System.out.print("-"); + dashCounter++; + } + actualColSize[i] = dashCounter; + System.out.print(" "); + } + System.out.println(); + + // print the result set + while (rs.next()) + { + System.out.print(" "); + + for (int i = 0 ; i < colCount ; i++) + { + // check the TYPE of the column to retrieve the value of + // each column + if (colTypeName[i].equals("SMALLINT")) + { + System.out.print( + Data.format(rs.getInt(i+1), actualColSize[i])); + } + else if (colTypeName[i].equals("VARCHAR")) + { + System.out.print(Data.format(rs.getString(i+1), + actualColSize[i])); + } + else if (colTypeName[i].equals("INTEGER")) + { + Integer tempInteger = new Integer(0); + tempInteger = Integer.valueOf(rs.getString(i+1)); + System.out.print( + Data.format(tempInteger, actualColSize[i])); + } + else if (colTypeName[i].equals("DOUBLE")) + { + Double tempDouble = new Double(0.0); + tempDouble = Double.valueOf( + Double.toString(rs.getDouble(i+1))); + System.out.print( + Data.format(tempDouble, actualColSize[i], 2)); + } + else + { + System.out.println("Error: " + + "Cannot read the column's type"); + } + System.out.print(" "); + } + System.out.println(); + } // end while + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + static void mostSimpleSubselect(Connection con) + { + try + { + int deptnumb = 0; + String deptname = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SIMPLE SUBSELECT."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + System.out.println(); + System.out.println(" Perform:\n" + + " SELECT deptnumb, deptname FROM org\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT deptnumb, deptname FROM org"); + + while (rs.next()) + { + deptnumb = rs.getInt(1); + deptname = rs.getString(2); + + System.out.println(" " + + Data.format(deptnumb, 8) + " " + + Data.format(deptname, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // mostSimpleSubselect + + static void basicSubselect(Connection con) + { + try + { + int deptnumb = 0; + String deptname = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SUBSELECT USING A WHERE CLAUSE."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname FROM org WHERE deptnumb < 30\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT deptnumb, deptname FROM org WHERE deptnumb < 30"); + + while (rs.next()) + { + deptnumb = rs.getInt(1); + deptname = rs.getString(2); + + System.out.println(" " + + Data.format(deptnumb, 8) + " " + + Data.format(deptname, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // basicSubselect + + static void groupBySubselect(Connection con) + { + try + { + String division = ""; + int maxDeptnumb = 0; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A 'GROUP BY' SUBSELECT."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT division, MAX(deptnumb) FROM org GROUP BY division\n" + + "\n" + + " Results:\n" + + " DIVISION MAX(DEPTNUMB)\n" + + " ---------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT division, MAX(deptnumb) FROM org GROUP BY division"); + + while (rs.next()) + { + division = rs.getString(1); + maxDeptnumb = rs.getInt(2); + + System.out.println(" " + + Data.format(division, 10) + " " + + Data.format(maxDeptnumb, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // groupBySubselect + + static void subselect(Connection con) + { + try + { + int maxDeptnumb = 0; + String division = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SUBSELECT."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + System.out.println(); + System.out.println(" Perform:\n" + + " SELECT division, MAX(deptnumb)\n" + + " FROM org\n" + + " WHERE location NOT IN 'New York'\n" + + " GROUP BY division\n" + + " HAVING division LIKE '%%ern'\n" + + "\n" + + " Results:\n" + + " DIVISION MAX(DEPTNUMB)\n" + + " ---------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT division, MAX(deptnumb) " + + " FROM org " + + " WHERE location NOT IN 'New York' " + + " GROUP BY division " + + " HAVING division LIKE '%ern'"); + + while (rs.next()) + { + division = rs.getString(1); + maxDeptnumb = rs.getInt(2); + + System.out.println(" " + Data.format(division, 10) + + " " + Data.format(maxDeptnumb, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // subselect + + static void rowSubselect(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A 'ROW' SUBSELECT."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + System.out.println(); + System.out.println(" Perform:\n" + + " SELECT deptnumb, deptname\n" + + " FROM org\n" + + " WHERE location = 'New York'\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT deptnumb, deptname " + + " FROM org " + + " WHERE location = 'New York' "); + rs.next(); + + int deptnumb = rs.getInt(1); + String deptname = rs.getString(2); + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // rowSubselect + + static void fullselect(Connection con) + { + try + { + int deptnumb = 0; + String deptname = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A FULLSELECT."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + System.out.println(); + System.out.println(" Perform:\n" + + " SELECT deptnumb, deptname\n" + + " FROM org\n" + + " WHERE deptnumb < 20\n" + + " UNION\n" + + " VALUES(7, 'New Deptname')\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT deptnumb, deptname " + + " FROM org " + + " WHERE deptnumb < 20 " + + " UNION " + + " VALUES(7, 'New Deptname')"); + + while (rs.next()) + { + deptnumb = rs.getInt(1); + deptname = rs.getString(2); + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // fullselect + + static void selectStatement(Connection con) + { + try + { + int deptnumb = 0; + String deptname = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SELECT STATEMENT."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + System.out.println(); + System.out.println(" Perform:\n" + + " SELECT deptnumb, deptname\n" + + " FROM org\n" + + " WHERE deptnumb > 30\n" + + " ORDER BY deptname\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- ------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT deptnumb, deptname " + + " FROM org " + + " WHERE deptnumb > 30 " + + " ORDER BY deptname"); + + while (rs.next()) + { + deptnumb = rs.getInt(1); + deptname = rs.getString(2); + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 18)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // selectStatement + + static void basicSubselectFromMultipleTables(Connection con) + { + try + { + int deptnumb = 0; + String deptno = ""; + String orgDeptname = ""; + String departmentDeptname = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SUBSELECT FROM MULTIPLE TABLES."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + // display DEPARTMENT table content + DepartmentTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, o.deptname, deptno, d.deptname\n" + + " FROM org o, department d\n" + + " WHERE deptnumb <= 15 AND deptno LIKE '%%11'\n" + + "\n" + + " Results:\n" + + " DEPTNUMB ORG.DEPTNAME DEPTNO DEPARTMENT.DEPTNAME\n" + + " -------- -------------- ------ -------------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT deptnumb, o.deptname, deptno, d.deptname " + + " FROM org o, department d " + + " WHERE deptnumb <= 15 AND deptno LIKE '%11'"); + + while (rs.next()) + { + deptnumb = rs.getInt(1); + orgDeptname = rs.getString(2); + deptno = rs.getString(3); + departmentDeptname = rs.getString(4); + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(orgDeptname, 14) + + " " + Data.format(deptno, 6) + + " " + Data.format(departmentDeptname, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // TbBasicSelectFromMultipleTables + + static void basicSubselectFromJoinedTable(Connection con) + { + try + { + int deptnumb = 0; + int manager = 0; + String deptno = ""; + String mgrno = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SUBSELECT FROM JOINED TABLES."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + // display DEPARTMENT table content + DepartmentTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, manager, deptno, mgrno\n" + + " FROM org\n" + + " INNER JOIN department\n" + + " ON manager = INTEGER(mgrno)\n" + + " WHERE deptnumb BETWEEN 20 AND 100\n" + + "\n" + + " Results:\n" + + " DEPTNUMB MANAGER DEPTNO MGRNO\n" + + " -------- ------- ------ ------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT deptnumb, manager, deptno, mgrno " + + " FROM org " + + " INNER JOIN department " + + " ON manager = INTEGER(mgrno) " + + " WHERE deptnumb BETWEEN 20 AND 100 "); + + while (rs.next()) + { + deptnumb = rs.getInt(1); + manager = rs.getInt(2); + deptno = rs.getString(3); + mgrno = rs.getString(4); + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(manager, 7) + + " " + Data.format(deptno, 5) + + " " + Data.format(mgrno, 6)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // basicSubselectFromJoinedTable + + static void basicSubselectUsingSubquery(Connection con) + { + try + { + int deptnumb = 0; + String deptname = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SUBSELECT USING SUBQUERY."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname\n" + + " FROM org\n" + + " WHERE deptnumb < (SELECT AVG(deptnumb) FROM org)\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT deptnumb, deptname " + + " FROM org " + + " WHERE deptnumb < (SELECT AVG(deptnumb) FROM org)"); + + while (rs.next()) + { + deptnumb = rs.getInt(1); + deptname = rs.getString(2); + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // basicSubselectUsingSubquery + + static void basicSubselectUsingCorrelatedSubquery(Connection con) + { + try + { + int deptnumb = 0; + String deptname = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SUBSELECT USING CORRELATED SUBQUERY."); + + // display the content of the 'org' table + OrgTbContentDisplay(con); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname\n" + + " FROM org o1\n" + + " WHERE deptnumb > (SELECT AVG(deptnumb)\n" + + " FROM org o2\n" + + " WHERE o2.division = o1.division)\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT deptnumb, deptname " + + " FROM org o1 " + + " WHERE deptnumb > (SELECT AVG(deptnumb) " + + " FROM org o2 " + + " WHERE o2.division = o1.division) "); + + while (rs.next()) + { + deptnumb = rs.getInt(1); + deptname = rs.getString(2); + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // basicSubselectUsingCorrelatedSubquery + + static void subselectUsingGroupingSets(Connection con) + { + try + { + String job = null; + Integer edlevel = new Integer(0); + Double commSum = new Double(0.0); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SUBSELECT USING GROUPING SETS."); + + EmployeeTbPartialContentDisplay(con); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT job, edlevel, SUM(comm)\n" + + " FROM employee\n" + + " WHERE job IN('DESIGNER', 'FIELDREP')\n" + + " GROUP BY GROUPING SETS((job, edlevel), (job))\n" + + "\n" + + " Results:\n" + + " JOB EDLEVEL SUM(COMM)\n" + + " -------- ------- -----------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT job, edlevel, SUM(comm) " + + " FROM employee " + + " WHERE job IN('DESIGNER','FIELDREP') " + + " GROUP BY GROUPING SETS ((job, edlevel),(job))"); + + while (rs.next()) + { + if (rs.getString(1) != null) + { + job = rs.getString(1); + System.out.print(" " + Data.format(job, 8)); + } + else + { + System.out.print(" -"); + } + + if (rs.getString(2) != null) + { + edlevel = Integer.valueOf(rs.getString(2)); + System.out.print(" " + Data.format(edlevel, 7)); + } + else + { + System.out.print(" -"); + } + + if (rs.getDouble(3) != 0.0) + { + commSum = Double.valueOf( + Double.toString(rs.getDouble(3))); + System.out.print(" " + Data.format(commSum, 10, 2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // subselectUsingGroupingSets + + static void subselectUsingRollup(Connection con) + { + try + { + String job = null; + Integer edlevel = new Integer(0); + Double commSum = new Double(0.0); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SUBSELECT USING ROLLUP."); + + EmployeeTbPartialContentDisplay(con); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT job, edlevel, SUM(comm)\n" + + " FROM employee\n" + + " WHERE job IN('DESIGNER', 'FIELDREP')\n" + + " GROUP BY ROLLUP(job, edlevel)\n" + + "\n" + + " Results:\n" + + " JOB EDLEVEL SUM(COMM)\n" + + " -------- ------- -----------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT job, edlevel, SUM(comm) " + + " FROM employee " + + " WHERE job IN('DESIGNER', 'FIELDREP') " + + " GROUP BY ROLLUP(job, edlevel)"); + + while (rs.next()) + { + if (rs.getString(1) != null) + { + job = rs.getString(1); + System.out.print(" " + Data.format(job, 8)); + } + else + { + System.out.print(" -"); + } + + if (rs.getString(2) != null) + { + edlevel = Integer.valueOf(rs.getString(2)); + System.out.print(" " + Data.format(edlevel, 7)); + } + else + { + System.out.print(" -"); + } + + if (rs.getDouble(3) != 0.0) + { + commSum = Double.valueOf( + Double.toString(rs.getDouble(3))); + System.out.print(" " + Data.format(commSum, 10, 2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // subselectUsingRollup + + static void subselectUsingCube(Connection con) + { + try + { + String job = null; + Integer edlevel = new Integer(0); + Double commSum = new Double(0.0); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SUBSELECT USING CUBE."); + + EmployeeTbPartialContentDisplay(con); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT job, edlevel, SUM(comm)\n" + + " FROM employee\n" + + " WHERE job IN('DESIGNER', 'FIELDREP')\n" + + " GROUP BY CUBE(job, edlevel)\n" + + "\n" + + " Results:\n" + + " JOB EDLEVEL SUM(COMM)\n" + + " -------- ------- -----------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT job, edlevel, SUM(comm) " + + " FROM employee " + + " WHERE job IN('DESIGNER', 'FIELDREP') " + + " GROUP BY CUBE(job, edlevel)"); + + while (rs.next()) + { + if (rs.getString(1) != null) + { + job = rs.getString(1); + System.out.print(" " + Data.format(job, 8)); + } + else + { + System.out.print(" -"); + } + + if (rs.getString(2) != null) + { + edlevel = Integer.valueOf(rs.getString(2)); + System.out.print(" " + Data.format(edlevel, 7)); + } + else + { + System.out.print(" -"); + } + + if (rs.getDouble(3) != 0.0) + { + commSum = Double.valueOf( + Double.toString(rs.getDouble(3))); + System.out.print(" " + Data.format(commSum, 10, 2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // subselectUsingCube + + static void selectUsingQuerySampling(Connection con) + { + try + { + float avg = 0.0f; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SELECT USING QUERY SAMPLING "); + + System.out.println( + "\nCOMPUTING AVG(SALARY) WITHOUT SAMPLING \n" + + "\n Perform:\n" + + " SELECT AVG(salary) FROM employee \n" + + "\n Results:\n" + + " AVG SALARY\n" + + " ----------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT AVG(salary) FROM employee"); + + while (rs.next()) + { + avg = rs.getFloat(1); + if (rs.wasNull()) + { + System.out.println(" -"); + } + else + { + System.out.println(" " + avg); + } + } + rs.close(); + + System.out.println( + "\nCOMPUTING AVG(SALARY) WITH QUERY SAMPLING" + + "\n - ROW LEVEL SAMPLING " + + "\n - BLOCK LEVEL SAMPLING \n" + + "\n ROW LEVEL SAMPLING : USE THE KEYWORD 'BERNOULLI'\n" + + "\nFOR A SAMPLING PERCENTAGE OF P, EACH ROW OF THE TABLE IS\n" + + "SELECTED FOR THE INCLUSION IN THE RESULT WITH A PROBABILITY\n" + + "OF P/100, INDEPENDENTLY OF THE OTHER ROWS IN T\n" + + "\n Perform:\n" + + " SELECT AVG(salary) FROM employee TABLESAMPLE BERNOULLI(25)" + + " REPEATABLE(5)\n" + + "\n Results:\n" + + " AVG SALARY\n" + + " ----------"); + + rs = stmt.executeQuery( + "SELECT AVG(salary) FROM employee " + + "TABLESAMPLE BERNOULLI(25) REPEATABLE(5)"); + + while (rs.next()) + { + avg = rs.getFloat(1); + if (rs.wasNull()) + { + System.out.println(" -"); + } + else + { + System.out.println(" " + avg); + } + } + rs.close(); + + System.out.println( + "\n\n BLOCK LEVEL SAMPLING : USE THE KEYWORD 'SYSTEM'\n" + + "\nFOR A SAMPLING PERCENTAGE OF P, EACH ROW OF THE TABLE IS\n" + + "SELECTED FOR INCLUSION IN THE RESULT WITH A PROBABILITY\n" + + "OF P/100, NOT NECESSARILY INDEPENDENTLY OF THE OTHER ROWS\n" + + "IN T, BASED UPON AN IMPLEMENTATION-DEPENDENT ALGORITHM\n" + + "\n Perform:\n" + + " SELECT AVG(salary) FROM employee TABLESAMPLE SYSTEM(50)" + + " REPEATABLE(1234)\n" + + "\n Results:\n" + + " AVG SALARY\n" + + " ----------" ); + + rs = stmt.executeQuery( + "SELECT AVG(salary)FROM employee "+ + "TABLESAMPLE SYSTEM(50) REPEATABLE(1234)"); + + while (rs.next()) + { + avg = rs.getFloat(1); + if (rs.wasNull()) + { + System.out.println(" -"); + } + else + { + System.out.println(" " + avg); + } + } + rs.close(); + + System.out.println( + "\nREPEATABLE CLAUSE ENSURES THAT REPEATED EXECUTIONS OF THAT\n" + + "TABLE REFERENCE WILL RETURN IDENTICAL RESULTS FOR THE SAME \n" + + "VALUE OF THE REPEAT ARGUMENT (IN PARENTHESIS)."); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // selectUsingQuerySampling +} // TbRead diff --git a/java/jdbc/TbRowcompress.java b/java/jdbc/TbRowcompress.java new file mode 100644 index 0000000..0d68634 --- /dev/null +++ b/java/jdbc/TbRowcompress.java @@ -0,0 +1,1141 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: TbRowcompress.java +// +// PURPOSE: To demonstrate row compression and automatic dictionary creation. +// +// Row Compression: +// 1. How to enable the row compression after a table is created. +// 2. How to enable the row compression during table creation. +// 3. Usage of the options to REORG to use the exiting dictionary +// or creating a new dictionary. +// 4. How to estimate the effectiveness of the compression. +// +// Automatic Dictionary Creation: +// 1. When the compression dictionary will automatically be created. +// 2. Automatic dictionary creation with DML commands like INSERT, IMPORT and LOAD. +// 3. How to determine whether a new dictionary should be built or not. +// 4. Automatic dictionary creation for a data partitioned table. +// +// PREREQUISITE: NONE +// +// EXECUTION: i) javac TbRowcompress.java (compile the sample) +// ii) java TbRowcompress.class (run the sample) +// +// INPUTS: NONE +// +// OUTPUTS: successful creation of compression dictionary. +// +// OUTPUT FILE: TbRowcompress.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// CREATE TABLE ... COMPRESS YES +// CREATE PROCEDURE +// CALL +// ALTER TABLE +// DELETE +// DROP TABLE +// EXPORT +// IMPORT +// INSERT +// INSPECT +// LOAD +// REORG +// RUNSTATS +// TERMINATE +// UPDATE +// +// SQL ROUTINES USED: +// SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO +// +// JAVA 2 CLASSES USED: +// Statement +// CallableStatement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// ************************************************************************* +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +// *************************************************************************/ // +// SAMPLE DESCRIPTION +// +// /************************************************************************* +// +// ************************************************************************* +// 1. ROW COMPRESSION +// 2. AUTOMATIC DICTIONARY CREATION +// *************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbRowcompress +{ + public static void main(String argv[]) + { + if (argv.length < 1) + { + System.out.println("\n Usage : java TbRowcompress" + + " "); + } + else + { + try + { + Connection con = null; + String path = argv[0]; + + // initialize DB2Driver and establish database connection. + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + System.out.println( + "This sample demonstrates row compression and automatic dictionary creation."); + + // ************************************************************************* + // 1. ROW COMPRESSION + // ************************************************************************* + + // to Load table data into a file. + getLoadData(con, path); + + // to Enable Row compression on table. + enableRowCompressionForTables(con, path); + + // to disable row compression on tables. + disableRowCompressionForTables(con, path); + + // to inspect the compression. + inspectCompression(con, path); + + // ************************************************************************* + // 2. AUTOMATIC DICTIONARY CREATION + // ************************************************************************* + + // to demonstrate automatic dictionary creation + AutomaticDictionaryCreation(con, path); + + // close the connection + con.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } + } // main + + static void getLoadData(Connection con, String path) throws SQLException + { + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + int rows_exported = 0; + + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n" + + "\n Perform:\n" + + " CREATE TABLE temp(empno INT, sal INT)"); + + // create a temporary table + stmt.executeUpdate("CREATE TABLE temp(empno INT, sal INT)"); + + // insert data into the table and export the data in order to obtain + // dummy.del file in the required format for load. + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO temp"); + + // insert data into the table + stmt = con.createStatement(); + for(int count=1; count< 1000; count++) + { + stmt.executeUpdate("INSERT INTO temp VALUES(100, 20000)"); + stmt.executeUpdate("INSERT INTO temp VALUES(200, 30000)"); + stmt.executeUpdate("INSERT INTO temp VALUES(100, 30500)"); + stmt.executeUpdate("INSERT INTO temp VALUES(300, 20000)"); + stmt.executeUpdate("INSERT INTO temp VALUES(400, 30000)"); + } + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " EXPORT \n" + + "TO EXPORT TABLE DATA INTO A FILE \n" + + "\n Perform:\n" + + " EXPORT TO dummy.del OF DEL SELECT * FROM temp"); + + // export data into a dummy file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to which the data is to be exported + param = "EXPORT TO " + path + "dummy.del OF DEL SELECT * FROM temp" ; + + // set the input parameter + callStmt1.setString(1, param); + System.out.println(); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if( rs.next()) + { + // the numbers of rows exported + rows_exported = rs.getInt(1); + + // display the output + System.out.println + ("Total number of rows exported : " + rows_exported); + } + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " DROP \n" + + "TO DROP THE TABLE \n" + + "\n Perform:\n" + + " DROP TABLE temp"); + + // drop the temporary table + stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE temp"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // getLoadData + + static void enableRowCompressionForTables + (Connection con, String path) throws SQLException + { + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + int rows_read = 0; + int rows_skipped = 0; + int rows_loaded = 0; + int rows_rejected = 0; + int rows_deleted = 0; + int rows_committed = 0; + + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n" + + "\n Perform:\n" + + " CREATE TABLE empl(emp_no INT, salary INT)"); + + // create a table without enabling row compression at the time of + // table creation + stmt = con.createStatement(); + stmt.executeUpdate("CREATE TABLE empl(emp_no INT, salary INT)"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " IMPORT \n" + + "TO IMPORT THE DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " IMPORT FROM dummy.del OF DEL INSERT INTO empl"); + + // import data from file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to be loaded + param = "IMPORT FROM " + path + "dummy.del OF DEL INSERT INTO empl" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if( rs.next()) + { + // retrieve the no of rows read + rows_read = rs.getInt(1); + // retrieve the no of rows skipped + rows_skipped = rs.getInt(2); + // retrieve the no of rows loaded + rows_loaded = rs.getInt(3); + // retrieve the no of rows rejected + rows_rejected = rs.getInt(4); + // retrieve the no of rows deleted + rows_deleted = rs.getInt(5); + // retrieve the no of rows committed + rows_committed = rs.getInt(6); + + // display the resultset + System.out.print("\nTotal number of rows read : "); + System.out.println(rows_read); + System.out.print("Total number of rows skipped : "); + System.out.println( rows_skipped); + System.out.print("Total number of rows loaded : "); + System.out.println(rows_loaded); + System.out.print("Total number of rows rejected : "); + System.out.println(rows_rejected); + System.out.print("Total number of rows deleted : "); + System.out.println(rows_deleted); + System.out.print("Total number of rows committed : "); + System.out.println(rows_read); + } + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO ENABLE ROW COMPRESSION \n" + + "\n Perform:\n" + + " ALTER TABLE empl COMPRESS YES"); + + // enable row compression + stmt = con.createStatement(); + stmt.executeUpdate("ALTER TABLE empl COMPRESS YES"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " REORG \n" + + "TO COMPRESS ROWS \n" + + "\n Perform:\n" + + " REORG TABLE empl"); + + // perform non-inplace reorg to compress rows and to retain + // existing dictionary + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + param = "REORG TABLE empl" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " DROP \n" + + "TO DROP THE TABLE \n" + + "\n Perform:\n" + + " DROP TABLE empl"); + + // drop the temporary table + stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE empl"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // enableRowCompressionForTables + + static void disableRowCompressionForTables + (Connection con, String path) throws SQLException + { + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + int rows_read = 0; + int rows_skipped = 0; + int rows_loaded = 0; + int rows_rejected = 0; + int rows_deleted = 0; + int rows_committed = 0; + + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " CREATE \n" + + "TO CREATE A TABLE \n" + + "\n Perform:\n" + + " CREATE TABLE empl(emp_no INT, salary INT) COMPRESS YES"); + + // create a table enabling compression initially + stmt = con.createStatement(); + stmt.executeUpdate + ("CREATE TABLE empl(emp_no INT, salary INT) COMPRESS YES"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " IMPORT \n" + + "TO IMPORT THE DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " IMPORT FROM dummy.del OF DEL INSERT INTO empl"); + + // load data into table + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to be loaded + param = "IMPORT FROM " + path + "dummy.del OF DEL INSERT INTO empl" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if( rs.next()) + { + // retrieve the no of rows read + rows_read = rs.getInt(1); + // retrieve the no of rows skipped + rows_skipped = rs.getInt(2); + // retrieve the no of rows loaded + rows_loaded = rs.getInt(3); + // retrieve the no of rows rejected + rows_rejected = rs.getInt(4); + // retrieve the no of rows deleted + rows_deleted = rs.getInt(5); + // retrieve the no of rows committed + rows_committed = rs.getInt(6); + + // display the resultset + System.out.print("\nTotal number of rows read : "); + System.out.println(rows_read); + System.out.print("Total number of rows skipped : "); + System.out.println( rows_skipped); + System.out.print("Total number of rows loaded : "); + System.out.println(rows_loaded); + System.out.print("Total number of rows rejected : "); + System.out.println(rows_rejected); + System.out.print("Total number of rows deleted : "); + System.out.println(rows_deleted); + System.out.print("Total number of rows committed : "); + System.out.println(rows_read); + } + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " REORG \n" + + "TO COMPRESS ROWS \n" + + "\n Perform:\n" + + " REORG TABLE empl"); + + // perform reorg to compress rows + param = "REORG TABLE empl" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + " UPDATE \n" + + " DELETE \n" + + "TO INSERT, UPDATE OR DELETE DATA IN TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl VALUES(400, 30000)\n" + + " UPDATE empl SET salary = salary + 1000\n" + + " DELETE FROM empl WHERE emp_no = 200"); + + // perform modifications on table + stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO empl VALUES(400, 30000)"); + stmt.executeUpdate("UPDATE empl SET salary = salary + 1000"); + stmt.executeUpdate("DELETE FROM empl WHERE emp_no = 200"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO DISABLE ROW COMPRESSION FOR THE TABLE \n" + + "\n Perform:\n" + + " ALTER TABLE empl COMPRESS NO"); + + // disable row compression for the table + stmt = con.createStatement(); + stmt.executeUpdate("ALTER TABLE empl COMPRESS NO"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " REORG TABLE \n" + + "TO REORG THE TABLE AND REMOVE EXISTING DICTIONARY \n" + + "\n Perform:\n" + + " REORG TABLE empl RESETDICTIONARY"); + + // Perform reorg to remove existing dictionary. + // New dictionary will be created and all the rows processed + // by the reorg are decompressed. + param = "REORG TABLE empl RESETDICTIONARY" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " DROP \n" + + "TO DROP THE TABLE \n" + + "\n Perform:\n" + + " DROP TABLE empl"); + + // drop the table + stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE empl"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // disableRowCompressionForTables + + static void inspectCompression + (Connection con, String path) throws SQLException + { + try + { + String sql = null; + String param = null; + String str = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + CallableStatement callStmt1 = null; + + int emp_no = 0; + int sal = 0; + + int rows_read = 0; + int rows_skipped = 0; + int rows_loaded = 0; + int rows_rejected = 0; + int rows_deleted = 0; + int rows_committed = 0; + + int avgrowsize = 0; + int avgcompressedrowsize = 0; + int pctpagessaved = 0; + int avgrowcompressionratio = 0; + int pctrowscompressed = 0; + + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n" + + "\n Perform:\n" + + " CREATE TABLE empl(emp_no INT, salary INT)"); + + // create a table + stmt = con.createStatement(); + stmt.executeUpdate("CREATE TABLE empl(emp_no INT, salary INT)"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " IMPORT \n" + + "TO IMPORT DATA INTO TABLE \n" + + "\n Perform:\n" + + " IMPORT FROM dummy.del OF DEL INSERT INTO empl"); + + // import data into the table + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to be loaded + param = "IMPORT FROM " + path + "dummy.del OF DEL INSERT INTO empl" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if( rs.next()) + { + // retrieve the no of rows read + rows_read = rs.getInt(1); + // retrieve the no of rows skipped + rows_skipped = rs.getInt(2); + // retrieve the no of rows loaded + rows_loaded = rs.getInt(3); + // retrieve the no of rows rejected + rows_rejected = rs.getInt(4); + // retrieve the no of rows deleted + rows_deleted = rs.getInt(5); + // retrieve the no of rows committed + rows_committed = rs.getInt(6); + + // display the resultset + System.out.print("\nTotal number of rows read : "); + System.out.println(rows_read); + System.out.print("Total number of rows skipped : "); + System.out.println( rows_skipped); + System.out.print("Total number of rows loaded : "); + System.out.println(rows_loaded); + System.out.print("Total number of rows rejected : "); + System.out.println(rows_rejected); + System.out.print("Total number of rows deleted : "); + System.out.println(rows_deleted); + System.out.print("Total number of rows committed : "); + System.out.println(rows_read); + } + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO ENABLE COMPRESSION \n" + + "\n Perform:\n" + + " ALTER TABLE empl COMPRESS YES"); + + // enable row compression for the table + stmt = con.createStatement(); + stmt.executeUpdate("ALTER TABLE empl COMPRESS YES"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl VALUES(400, 30000)"); + + // insert some data into the table + stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO empl VALUES(400, 30000)"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSPECT \n" + + "TO ESTIMATE THE EFFECTIVENESS OF COMPRESSION \n" + + "\n Perform:\n" + + " INSPECT ROWCOMPESTIMATE TABLE NAME empl RESULTS KEEP result"); + + // Perform inspect to estimate the effectiveness of compression. + // Inspect has to be run before the REORG utility. + // Inspect allows you to look over tablespaces and tables for their + // architectural integrity. + // 'result' file contains percentage of bytes saved from compression, + // Percentage of rows ineligible for compression due to small row size, + // Compression dictionary size, Expansion dictionary size etc. + // To view the contents of 'result' file perform + // db2inspf result result.out; This formats the 'result' file to + // readable form. + + String execCmd = "db2 INSPECT ROWCOMPESTIMATE TABLE NAME empl" + + " RESULTS KEEP result"; + + // execute the command + Process p1 = Runtime.getRuntime().exec(execCmd); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " REORG \n" + + "TO REORG THE TABLE \n" + + "\n Perform:\n" + + " REORG TABLE empl"); + + // perform reorg on the table + + param = "REORG TABLE empl" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl VALUES(500, 40000)"); + + // all the rows will be compressed including the one inserted + // after reorg + stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO empl VALUES(500, 40000)"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO DISABLE THE COMPRESSION \n" + + "\n Perform:\n" + + " ALTER TABLE empl COMPRESS NO"); + + // disable row compression for the table. + // rows inserted after this will be non-compressed. + stmt = con.createStatement(); + stmt.executeUpdate("ALTER TABLE empl COMPRESS NO"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl VALUES(600, 40500)"); + + // add one row of data to the table + stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO empl VALUES(600, 40500)"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO ENABLE THE COMPRESSION \n" + + "\n Perform:\n" + + " ALTER TABLE empl COMPRESS YES"); + + // enable the row compression for the table + stmt = con.createStatement(); + stmt.executeUpdate("ALTER TABLE empl COMPRESS YES"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl VALUES(700, 40600)"); + + // add one row of data to the table + stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO empl VALUES(700, 40600)"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " RUNSTATS \n" + + "TO MEASURE THE EFFECTIVENESS OF COMPRESSION \n" + + "\n Perform:\n" + + " RUNSTATS ON TABLE EMPL"); + + // Perform runstats to measure the effectiveness of compression using + // compression related catalog fields. New columns will be updated to + // catalog table after runstats if performed on a compressed table. + + // get fully qualified name of the table + String tableName = "EMPL"; + String schemaName = getSchemaName(con, tableName); + String fullTableName = schemaName + "." + tableName; + + param = "RUNSTATS ON TABLE " + fullTableName; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + + System.out.println(); + System.out.println( + "SELECT avgrowsize, avgcompressedrowsize, pctpagessaved,\n" + + " avgrowcompressionratio, pctrowscompressed\n" + + " FROM SYSCAT.TABLES WHERE tabname = 'EMPL'"); + System.out.println( + "\n AvRowSize AvCmprsdRowSize PerPgSaved AvgRowCmprRatio" + + " PerRowsCmprsd\n" + + " --------- --------------- ---------- ---------------" + + " -------------"); + + stmt = con.createStatement(); + // perform a SELECT against the "SYSCAT.TABLES" table. + str = "SELECT avgrowsize, avgcompressedrowsize, pctpagessaved, " + + "avgrowcompressionratio, pctrowscompressed from " + + "SYSCAT.TABLES WHERE tabname = 'EMPL'"; + rs = stmt.executeQuery(str); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + avgrowsize = rs.getInt(1); + avgcompressedrowsize = rs.getInt(2); + pctpagessaved = rs.getInt(3); + avgrowcompressionratio = rs.getInt(4); + pctrowscompressed = rs.getInt(5); + + System.out.println( + " " + Data.format(avgrowsize, 4) + + " " + Data.format(avgcompressedrowsize, 11) + + " " + Data.format(pctpagessaved, 9) + + " " + Data.format(avgrowcompressionratio, 9) + + " " + Data.format(pctrowscompressed, 13)); + + } + rs.close(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " DROP \n" + + "TO DROP THE TABLE \n" + + "\n Perform:\n" + + " DROP TABLE empl"); + + // drop the temporary table + stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE empl"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // inspectCompression + + + static void AutomaticDictionaryCreation + (Connection con, String path) throws SQLException + { + try + { + String sql = ""; + String param = ""; + String tabschema = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + int rows_read = 0; + int rows_skipped = 0; + int rows_loaded = 0; + int rows_rejected = 0; + int rows_deleted = 0; + int rows_committed = 0; + + String dictbuilder = ""; + long compressdictsize = 0; + long expanddictsize = 0; + int pagessavedpercent = 0; + int bytessavedpercent = 0; + + System.out.println( + "\n ---------------------------------------------------------------------------" + + "\n USE THE SQL STATEMENTS:\n" + + " CREATE \n" + + "TO CREATE A TABLE \n" + + "\n Perform:\n" + + " CREATE TABLE emptable(emp_no INT, name VARCHAR(120),joindate DATE) COMPRESS YES"); + + // create the table enabling compression initially + stmt = con.createStatement(); + stmt.executeUpdate + ("CREATE TABLE emptable(emp_no INT, name VARCHAR(120),joindate DATE) COMPRESS YES"); + + tabschema = getSchemaName(con, "EMPTABLE"); + // insert data into the table and export the data in order to obtain + // dummy.del file in the required format for load. + + System.out.println("\n Insert data into the table until the table size threshold is breached"); + + // insert data into the table + stmt = con.createStatement(); + + for(int count=1; count< 8000; count++) + { + stmt.executeUpdate("INSERT INTO emptable VALUES(10, 'Padma Kota', '2001-12-02')"); + stmt.executeUpdate("INSERT INTO emptable VALUES(30, 'Doug Foulds', '1898-08-08')"); + stmt.executeUpdate("INSERT INTO emptable VALUES(50, 'Kathy Smith', '2006-12-02')"); + stmt.executeUpdate("INSERT INTO emptable VALUES(75, 'Brad Cassels', '1984-04-06')"); + stmt.executeUpdate("INSERT INTO emptable VALUES(90, 'Kelly Booch', '2003-12-02')"); + } + + stmt = con.createStatement(); + // perform a SELECT against the table function SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO. + String str = "SELECT dict_builder, compress_dict_size, expand_dict_size, pages_saved_percent, bytes_saved_percent FROM table(sysproc.admin_get_tab_compress_info('" + tabschema +"','EMPTABLE','REPORT')) as temp"; + rs = stmt.executeQuery(str); + + // retrieve and display the result from the SELECT statement + if (rs.next()) + { + + dictbuilder = rs.getString(1); + compressdictsize = rs.getLong(2); + expanddictsize = rs.getLong(3); + pagessavedpercent = rs.getInt(4); + bytessavedpercent = rs.getInt(5); + + System.out.println( + " " + "dict_builder" + + " " + "compress_dict_size" + + " " + "expand_dict_size" + + " " + "pages_saved_percent" + + " " + "bytes_saved_percent"); + + System.out.println( + " " + dictbuilder + + " " + compressdictsize + + " " + expanddictsize + + " " + pagessavedpercent + + " " + bytessavedpercent); + + } + rs.close(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " EXPORT \n" + + "TO EXPORT TABLE DATA INTO A FILE \n" + + "\n Perform:\n" + + " EXPORT TO data.del OF DEL SELECT * FROM emptable"); + + // export data into a dummy file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to which the data is to be exported + param = "EXPORT TO " + path + "data1.del OF DEL SELECT * FROM emptable" ; + + // set the input parameter + callStmt1.setString(1, param); + System.out.println(); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if( rs.next()) + { + // the numbers of rows exported + int rows_exported = rs.getInt(1); + + // display the output + System.out.println + ("Total number of rows exported : " + rows_exported); + } + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " DROP \n" + + "TO DROP THE TABLE \n" + + "\n Perform:\n" + + " DROP TABLE emptable"); + + // drop the temporary table + stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE emptable"); + + con.commit(); + + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " CREATE \n" + + "TO CREATE A TABLE \n" + + "\n Perform:\n" + + " CREATE TABLE emptable(emp_no INT, name VARCHAR(120),joindate DATE) COMPRESS YES"); + + // create a table enabling compression initially + stmt = con.createStatement(); + stmt.executeUpdate + ("CREATE TABLE emptable(emp_no INT, name VARCHAR(120),joindate DATE) COMPRESS YES"); + + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " IMPORT \n" + + "TO IMPORT THE DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " IMPORT FROM data1.del OF DEL INSERT INTO emptable"); + + // load data into table + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to be loaded + param = "IMPORT FROM " + path + "data1.del OF DEL INSERT INTO emptable" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if( rs.next()) + { + // retrieve the no of rows read + rows_read = rs.getInt(1); + // retrieve the no of rows skipped + rows_skipped = rs.getInt(2); + // retrieve the no of rows loaded + rows_loaded = rs.getInt(3); + // retrieve the no of rows rejected + rows_rejected = rs.getInt(4); + // retrieve the no of rows deleted + rows_deleted = rs.getInt(5); + // retrieve the no of rows committed + rows_committed = rs.getInt(6); + + // display the resultset + System.out.print("\nTotal number of rows read : "); + System.out.println(rows_read); + System.out.print("Total number of rows skipped : "); + System.out.println( rows_skipped); + System.out.print("Total number of rows loaded : "); + System.out.println(rows_loaded); + System.out.print("Total number of rows rejected : "); + System.out.println(rows_rejected); + System.out.print("Total number of rows deleted : "); + System.out.println(rows_deleted); + System.out.print("Total number of rows committed : "); + System.out.println(rows_read); + } + + // perform a SELECT against the table function SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO. + str = "SELECT dict_builder, compress_dict_size, expand_dict_size, pages_saved_percent, bytes_saved_percent FROM table(sysproc.admin_get_tab_compress_info('" + tabschema +"','EMPTABLE','REPORT')) as temp"; + rs = stmt.executeQuery(str); + + // retrieve and display the result from the SELECT statement + if (rs.next()) + { + + dictbuilder = rs.getString(1); + compressdictsize = rs.getLong(2); + expanddictsize = rs.getLong(3); + pagessavedpercent = rs.getInt(4); + bytessavedpercent = rs.getInt(5); + + System.out.println( + " " + "dict_builder" + + " " + "compress_dict_size" + + " " + "expand_dict_size" + + " " + "pages_saved_percent" + + " " + "bytes_saved_percent"); + + System.out.println( + " " + dictbuilder + + " " + compressdictsize + + " " + expanddictsize + + " " + pagessavedpercent + + " " + bytessavedpercent); + + } + rs.close(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " DROP \n" + + "TO DROP THE TABLE \n" + + "\n Perform:\n" + + " DROP TABLE emptable"); + + // drop the table + stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE emptable"); + + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + // function to get the schema name for a particular table + static String getSchemaName + (Connection conn, String tableName) throws Exception + { + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT tabschema "+ + " FROM syscat.tables "+ + " WHERE tabname = '"+ tableName + "'"); + boolean result = rs.next(); + String schemaName = rs.getString(1); + + rs.close(); + stmt.close(); + + // remove the trailing white space characters from schemaName before + // returning it to the calling function + return schemaName.trim(); + } // getSchemaName +} // TbRowcompress diff --git a/java/jdbc/TbRunstats.java b/java/jdbc/TbRunstats.java new file mode 100644 index 0000000..c7728a3 --- /dev/null +++ b/java/jdbc/TbRunstats.java @@ -0,0 +1,181 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbRunstats.java +// +// SAMPLE: How to perform runstats on a table +// +// SQL STATEMENTS USED: +// SELECT +// CONNECT +// RUNSTATS +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// File +// FileWriter +// Process +// BufferedReader +// InputStreamReader +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbRunstats.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import java.lang.*; +import java.io.*; + +public class TbRunstats +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + // connect to the 'sample' database + db.connect(); + + // call tbRunstats that updates the statistics of employee table + tbRunstats(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // call runstats on 'employee' table to update its statistics + static void tbRunstats(Connection conn) throws Exception + { + System.out.print( + "\n-----------------------------------------------------------\n" + + "\nUSE THE SQL STATEMENT:\n"+ + " RUNSTATS\n" + + "TO UPDATE TABLE STATISTICS.\n"); + + // get fully qualified name of the table + String tableName = "EMPLOYEE"; + String schemaName = getSchemaName(conn, tableName); + String fullTableName = schemaName + "." + tableName; + + try + { + // store the CLP commands in a file and execute the file + File outputFile = new File("RunstatsCmd.db2"); + FileWriter out = new FileWriter(outputFile); + + String cmd = "RUNSTATS ON TABLE "+ fullTableName + + " WITH DISTRIBUTION ON KEY COLUMNS" + + " DEFAULT NUM_FREQVALUES 30 NUM_QUANTILES -1" + + " ALLOW READ ACCESS"; + + out.write("CONNECT TO SAMPLE;\n"); + out.write(cmd + ";\n"); + out.write("CONNECT RESET;\n"); + + out.close(); + + Process p = Runtime.getRuntime().exec("db2 -vtf RunstatsCmd.db2"); + + // open streams for the process's input and error + BufferedReader stdInput = new BufferedReader(new + InputStreamReader(p.getInputStream())); + BufferedReader stdError = new BufferedReader(new + InputStreamReader(p.getErrorStream())); + String s; + + // read the output from the command and set the output variable with + // the value + while ((s = stdInput.readLine()) != null) + { + System.out.println(s); + } + + // read any errors from the attempted command and set the error + // variable with the value + while ((s = stdError.readLine()) != null) + { + System.out.println(s); + } + + // destroy the process created + p.destroy(); + + // delete the temporary file created + outputFile.deleteOnExit(); + } + catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + } // tbRunstats + + // function to get the schema name for a particular table + static String getSchemaName(Connection conn, String tableName) throws Exception + { + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT tabschema "+ + " FROM syscat.tables "+ + " WHERE tabname = '"+ tableName + "'"); + + boolean result = rs.next(); + String schemaName = rs.getString("tabschema"); + rs.close(); + stmt.close(); + + // remove the trailing white space characters from schemaName before + // returning it to the calling function + return schemaName.trim(); + } // getSchemaName +} // TbRunstats diff --git a/java/jdbc/TbSel.java b/java/jdbc/TbSel.java new file mode 100644 index 0000000..15f8f44 --- /dev/null +++ b/java/jdbc/TbSel.java @@ -0,0 +1,570 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbSel.java +// +// SAMPLE: How to select from each of: insert, update, delete. +// +// SQL Statements USED: +// INCLUDE +// CREATE TABLE +// INSERT +// SELECT FROM INSERT +// SELECT FROM UPDATE +// SELECT FROM DELETE +// PREPARE +// DROP TABLE +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbSel.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbSel +{ + static Db db; + public static void main(String argv[]) + { + Connection con = null; + + try + { + int prt=Integer.parseInt(argv[1]); + javax.sql.DataSource ds=null; + ds=new com.ibm.db2.jcc.DB2SimpleDataSource(); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setServerName(argv[0]); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setPortNumber(prt); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setDatabaseName("sample"); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setDriverType(4); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setTraceFile("jcctrace.txt"); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds).setEnableNamedParameterMarkers(1); + con = ds.getConnection(argv[2],argv[3]); + System.out.println(" Connect to 'sample' database using JDBC Universal type 4 driver."); + con.setAutoCommit(false); + } + catch (Exception e) + { + System.out.println(" Error loading DB2 Driver...\n"); + System.out.println(e); + System.exit(1); + } + + try + { + + + System.out.println(); + System.out.println( + "THIS EXAMPLE SHOWS HOW TO SELECT FROM EACH OF: " + + "INSERT, UPDATE, DELETE.\n"); + + + + Create(con); + Print(con); + Buy_Company(con); + Print(con); + Drop(con); + + // Disconnect from database. + con.close(); + System.out.println(); + System.out.println(" Disconnect from 'sample' database."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // Main + + /* The Create function creates and populates the tables used by the + sample. + */ + static void Create(Connection con) + { + try + { + + /* The context for this sample is that of a Company B taking over + a Company A. This sample illustrates how company B incorporates + data from table company_b into table company_a. + */ + + System.out.println( + "\nCREATE TABLE company_a \n" + + " (ID SMALLINT NOT NULL UNIQUE, \n" + + " NAME VARCHAR(9), \n" + + " DEPARTMENT SMALLINT, \n" + + " JOB CHAR(5), \n" + + " YEARS SMALLINT, \n" + + " SALARY DECIMAL(7,2))\n"); + + // Company A is being bought out. + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE company_a " + + "(ID SMALLINT NOT NULL UNIQUE, " + + "NAME VARCHAR(9), " + + "DEPARTMENT SMALLINT, " + + "JOB CHAR(5), " + + "YEARS SMALLINT, " + + " SALARY DECIMAL(7,2))"); + stmt.close(); + + System.out.println( + "CREATE TABLE company_b \n" + + " (ID SMALLINT GENERATED BY DEFAULT AS IDENTITY (START WITH 2000, " + + "INCREMENT BY 1) NOT NULL, \n" + + " NAME VARCHAR(9), \n" + + " DEPARTMENT SMALLINT, \n" + + " JOB CHAR(5), \n" + + " YEARS SMALLINT, \n" + + " SALARY DECIMAL(7,2), \n" + + " BENEFITS VARCHAR(50), \n" + + " OLD_ID SMALLINT)\n"); + + // Company B is buying out Company A. This table has a few + // additional columns and differences from the previous table. + // Specifically, the ID column is generated. + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "CREATE TABLE company_b " + + "(ID SMALLINT GENERATED BY DEFAULT AS IDENTITY (START WITH 2000, " + + "INCREMENT BY 1) NOT NULL, " + + "NAME VARCHAR(9), " + + "DEPARTMENT SMALLINT, " + + "JOB CHAR(5), " + + "YEARS SMALLINT, " + + "SALARY DECIMAL(7,2), " + + "BENEFITS VARCHAR(50), " + + "OLD_ID SMALLINT)"); + stmt1.close(); + + System.out.println( + "CREATE TABLE salary_change \n" + + " (ID SMALLINT NOT NULL UNIQUE, \n" + + " OLD_SALARY DECIMAL(7,2), \n" + + " SALARY DECIMAL(7,2))\n"); + + // This table can be used by the management of Company B to see how + // much of a raise they gave to employees from Company A for joining + // Company B (in a dollar amount, as opposed to a 5% increase). + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "CREATE TABLE salary_change " + + "(ID SMALLINT NOT NULL UNIQUE, " + + "OLD_SALARY DECIMAL(7,2), " + + "SALARY DECIMAL(7,2))"); + stmt2.close(); + + System.out.println( + "INSERT INTO company_a VALUES(5275, 'Sanders', 20, 'Mgr', 15, " + + "18357.50), \n" + + " (5265, 'Pernal', 20, 'Sales', NULL, 18171.25), \n" + + " (5791, 'O''Brien', 38, 'Sales', 9, 18006.00)\n"); + + // Populate table company_a with data. + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate( + "INSERT INTO company_a VALUES(5275, 'Sanders', 20, 'Mgr', 15, " + + "18357.50), " + + "(5265, 'Pernal', 20, 'Sales', NULL, 18171.25), " + + "(5791, 'O''Brien', 38, 'Sales', 9, 18006.00)"); + stmt3.close(); + + System.out.println( + "INSERT INTO company_b VALUES " + + " (default, 'Naughton', 38, 'Clerk', NULL, 12954.75, " + + "'No Benefits', NULL), \n" + + " (default, 'Yamaguchi', 42, 'Clerk', 5, 10505.00, " + + "'Basic Health Coverage', NULL), \n" + + " (default, 'Fraye', 51, 'Mgr', 8, 21150.00, " + + "'Basic Health Coverage', NULL), \n" + + " (default, 'Williams', 51, 'Sales', 10, 19456.50, " + + "'Advanced Health Coverage', NULL), \n" + + " (default, 'Molinare', 10, 'Mgr', 15, 22959.20, " + + "'Advanced Health Coverage and Pension Plan', NULL)"); + + // Populate table company_b with data. + Statement stmt4 = con.createStatement(); + stmt4.executeUpdate( + "INSERT INTO company_b VALUES " + + "(default, 'Naughton', 38, 'Clerk', NULL, 12954.75, " + + "'No Benefits', NULL), " + + "(default, 'Yamaguchi', 42, 'Clerk', 5, 10505.00, " + + "'Basic Health Coverage', NULL), " + + "(default, 'Fraye', 51, 'Mgr', 8, 21150.00, " + + "'Basic Health Coverage', NULL), " + + "(default, 'Williams', 51, 'Sales', 10, 19456.50, " + + "'Advanced Health Coverage', NULL), " + + "(default, 'Molinare', 10, 'Mgr', 15, 22959.20, " + + "'Advanced Health Coverage and Pension Plan', NULL)"); + stmt4.close(); + + // Commit + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // Create + + /* The Buy_Company function encapsulates the table updates after Company + B takes over Company A. Each employees from table company_a is + allocated a benefits package. The employee data is moved into table + company_b. Each employee's salary is increased by 5%. The old and + new salaries are recorded in a table salary_change. + */ + static void Buy_Company(Connection con) + { + try + { + int id; // Employee's ID + int department; // Employee's department + int years; // Number of years employee has + // worked with the company + int new_id = 0; // Employee's new ID when they + // switch companies + + String name; // Employee's name + String job; // Employee's job title + String benefits = new String(); // Employee's benefits + + double salary; // Employee's current salary + double old_salary; // Employee's old salary + + /* The following SELECT statement references a DELETE statement in its + FROM clause. It deletes all rows from company_a, selecting all + deleted rows into the ResultSet rs. + */ + Statement stmt = con.createStatement(); + ResultSet rs = + stmt.executeQuery("SELECT ID, NAME, DEPARTMENT, JOB, YEARS, SALARY " + + "FROM OLD TABLE (DELETE FROM company_a)"); + while(rs.next()) + { + id = rs.getInt(1); + name = rs.getString(2); + department = rs.getInt(3); + job = rs.getString(4); + years = rs.getInt(5); + salary = rs.getDouble(6); + + /* The following if statement sets the new employee's benefits based + on their years of experience. + */ + if(years > 14) + benefits = "Advanced Health Coverage and Pension Plan"; + else if(years > 9) + benefits = "Advanced Health Coverage"; + else if(years > 4) + benefits = "Basic Health Coverage"; + else + benefits = "No Benefits"; + + /* The following SELECT statement references an INSERT statement in + its FROM clause. It inserts an employee record from host + variables into table company_b. The current employee ID from the + ResultSet is selected into the host variable new_id. The + keywords FROM FINAL TABLE determine that the value in new_id is + the value of ID after the INSERT statement is complete. + + Note that the ID column in table company_b is generated and + without the SELECT statement an additional query would have to be + made in order to retrieve the employee's ID number. + */ + PreparedStatement stmt1 = con.prepareStatement( + "SELECT ID " + + "FROM FINAL TABLE (INSERT INTO company_b " + + "VALUES(default, :name, :dept, :job, :yrs, :sal, :benefits, :id))"); + + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt1).setJccStringAtName ("name", name); + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt1).setJccIntAtName("dept",department); + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt1).setJccStringAtName("job",job); + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt1).setJccIntAtName("yrs",years); + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt1).setJccDoubleAtName("sal",salary); + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt1).setJccStringAtName("benefits",benefits); + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt1).setJccIntAtName("id",id); + + + + ResultSet rs1 = stmt1.executeQuery(); + rs1.next(); + + new_id = rs1.getInt(1); + + stmt1.close(); + rs1.close(); + + /* The following SELECT statement references an UPDATE statement in + its FROM clause. It updates an employee's salary by giving them + a 5% raise. The employee's id, old salary and current salary are + all read into host varibles via a ResultSet for later use in this + function. + + The INCLUDE statement works by creating a temporary column to + keep track of the old salary. This temporary column is only + available for this statement and is gone once the statement + completes. The only way to keep this data after the statement + completes is to read it into a host variable. + */ + PreparedStatement stmt2 = con.prepareStatement( + "SELECT ID, OLD_SALARY, SALARY " + + "FROM FINAL TABLE (UPDATE company_b INCLUDE " + + "(OLD_SALARY DECIMAL(7,2)) " + + "SET OLD_SALARY = SALARY, " + + " SALARY = SALARY * 1.05 " + + "WHERE ID = :nwID)"); + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt2).setJccIntAtName("nwID", new_id); + + ResultSet rs2 = stmt2.executeQuery(); + rs2.next(); + + id = rs2.getInt(1); + old_salary = rs2.getDouble(2); + salary = rs2.getDouble(3); + + stmt2.close(); + rs2.close(); + + /* This INSERT statement inserts an employee's id, old salary and + current salary into the salary_change table. + */ + PreparedStatement stmt3 = con.prepareStatement( + "INSERT INTO salary_change VALUES(:id, :old_sal, :sal)"); + + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt3).setJccIntAtName("id", id); + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt3).setJccDoubleAtName("old_sal", old_salary); + ((com.ibm.db2.jcc.DB2PreparedStatement)stmt3).setJccDoubleAtName("sal", salary); + stmt3.execute(); + stmt3.close(); + } + rs.close(); + stmt.close(); + + /* The following DELETE statement references a SELECT statement in its + FROM clause. It lays off the highest paid manager. This DELETE + statement removes the manager from the table company_b. + */ + PreparedStatement stmt4 = con.prepareStatement( + "DELETE FROM (SELECT * FROM company_b ORDER BY SALARY DESC FETCH " + + "FIRST ROW ONLY)"); + stmt4.execute(); + stmt4.close(); + + /* The following UPDATE statement references a SELECT statement in its + FROM clause. It gives the most senior employee a $10000 bonus. + This UPDATE statement raises the employee's salary in the table + company_b. + */ + PreparedStatement stmt5 = con.prepareStatement( + "UPDATE (SELECT MAX(YEARS) OVER() AS max_years, " + + "YEARS, " + + "SALARY" + + " FROM company_b) " + + " SET SALARY = SALARY + 10000 " + + " WHERE max_years = YEARS"); + stmt5.execute(); + stmt5.close(); + + // Commit + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // Buy_Company + + /* The Print function outputs the data in the tables: company_a, + company_b and salary_change. For each table, a while loop and + ResultSet are used to fetch and display row data. + */ + static void Print(Connection con) + { + try + { + int id; // Employee's ID + int department; // Employee's department + int years; // Number of years employee has worked with + // the company + int new_id = 0; // Employee's new ID when they switch + // companies + + String name; // Employee's name + String job; // Employee's job title + String benefits = new String(); // Employee's benefits + + double salary; // Employee's current salary + double old_salary; // Employee's old salary + + System.out.println("\nSELECT * FROM company_a\n"); + System.out.println( + "ID NAME DEPARTMENT JOB YEARS SALARY\n" + + "------ --------- ---------- ----- ------ ---------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM company_a"); + + while (rs.next()) + { + id = rs.getInt(1); + name = rs.getString(2); + department = rs.getInt(3); + job = rs.getString(4); + years = rs.getInt(5); + salary = rs.getDouble(6); + + System.out.println( + Data.format(id, 6) + " " + + Data.format(name, 9) + " " + + Data.format(department, 10) + " " + + Data.format(job, 5) + " " + + Data.format(years, 6) + " " + + Data.format(String.valueOf(salary), 9)); + } + rs.close(); + stmt.close(); + + System.out.println(); + System.out.println("SELECT * FROM company_b\n"); + System.out.println( + "ID NAME DEPARTMENT JOB YEARS SALARY \nBENEFITS OLD_ID\n" + + "------ --------- ---------- ----- ------ --------- \n-------------------------------------------------- ------"); + + Statement stmt1 = con.createStatement(); + ResultSet rs1 = stmt1.executeQuery("SELECT * FROM company_b"); + + while (rs1.next()) + { + new_id = rs1.getInt(1); + name = rs1.getString(2); + department = rs1.getInt(3); + job = rs1.getString(4); + years = rs1.getInt(5); + salary = rs1.getDouble(6); + benefits = rs1.getString(7); + id = rs1.getInt(8); + + System.out.println( + Data.format(new_id, 6) + " " + + Data.format(name, 9) + " " + + Data.format(department, 10) + " " + + Data.format(job, 5) + " " + + Data.format(years, 6) + " " + + Data.format(String.valueOf(salary), 9) + "\n" + + Data.format(benefits, 50) + " " + + Data.format(id, 6) + "\n"); + } + rs1.close(); + stmt1.close(); + + System.out.println("SELECT * FROM salary_change\n"); + System.out.println( + "ID OLD_SALARY SALARY\n" + + "------ ---------- ---------"); + + Statement stmt2 = con.createStatement(); + ResultSet rs2 = stmt2.executeQuery("SELECT * FROM salary_change"); + + while (rs2.next()) + { + id = rs2.getInt(1); + old_salary = rs2.getDouble(2); + salary = rs2.getDouble(3); + + System.out.println( + Data.format(id, 6) + " " + + Data.format(String.valueOf(old_salary), 11) + " " + + Data.format(String.valueOf(salary), 9)); + } + rs2.close(); + stmt2.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // Print + + /* The Drop function drops the tables used by this sample. */ + static void Drop(Connection con) + { + try + { + System.out.println(); + System.out.println("DROP TABLE company_a\n"); + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE company_a"); + stmt.close(); + + System.out.println("DROP TABLE company_b\n"); + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("DROP TABLE company_b"); + stmt1.close(); + + System.out.println("DROP TABLE salary_change"); + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("DROP TABLE salary_change"); + stmt2.close(); + + // Commit + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // Drop +} // TbSel + diff --git a/java/jdbc/TbTemp.java b/java/jdbc/TbTemp.java new file mode 100644 index 0000000..ce0d02e --- /dev/null +++ b/java/jdbc/TbTemp.java @@ -0,0 +1,503 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbTemp.java +// +// SAMPLE: How to use Declared Temporary Table +// +// This sample: +// 1. Creates a user temporary table space required for declared +// temporary tables +// 2. Creates and populates a declared temporary table +// 3. Shows that the declared temporary table exists after a commit +// and shows the declared temporary table's use in a procedure +// 4. Shows that the temporary table can be recreated with the same +// name using the "with replace" option and without "not logged" +// clause, to enable logging. +// 5. Shows the creation of an index on the temporary table. +// 6. Show the usage of "describe" command to obtain information +// regarding the tempraroy table. +// 7. Shows that the temporary table is implicitly dropped with a +// disconnect from the database +// 8. Drops the user temporary table space +// +// To Run on the Command line: +// javac TbTemp.java +// java TbTemp [dbUserName][password] +// +// This sample assumes that the database specified by databaseAlias +// contains a table named "department" and that the table's structure +// is the same as the one for the department table in the SAMPLE +// database. +// +// The following objects are made and later removed: +// (If objects with these names already exist, an error message will +// be printed out.) +// 1. a user temporary tablespace named usertemp1 +// 2. a declared global temporary table named temptb1 +// +// +// SQL STATEMENTS USED: +// CREATE USER TEMPORARY TABLESPACE +// DECLARE GLOBAL TEMPORARY TABLE +// INSERT +// DROP TABLESPACE +// +// JAVA 2 CLASSES USED: +// Statement +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbTemp.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import java.lang.*; +import java.io.*; + +public class TbTemp +{ + public static void main (String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("HOW TO USE DECLARED TEMPORARY TABLES.\n"); + + // connect to the 'sample' database + db.connect(); + + // make sure a user temporary table space exists before creating + // the table + createTablespace(db.con); + + // show how to make a declared temporary table + declareTempTable(db.con); + + // show that the temporary table exists in ShowAfterCommit() even + // though it was declared in declareTempTable(). The temporary table + // is accessible to the whole session as the connection still exists + // at this point. Show that the temporary table exists after a commit. + showAfterCommit(db.con); + + // declare the temporary table again. The old one will be dropped and + // a new one will be made. + recreateTempTableWithLogging(db.con); + db.con.commit(); + + // create an index for the global temporary table + createIndex(db.con); + + // use the ResultSetMetaData to describe the temp table + describeTemporaryTable(db.con); + + // disconnect from the 'sample' database. This implicitly drops the + // temporary table. Alternatively, an explicit drop statement could + // have been used. + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + try + { + Db db = new Db(argv); + + // connect to the 'sample' database + db.connect(); + dropTablespace(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // Create a user temporary tablespace for the temp table. A user + // temporary tablespace is required for temp tables and none are created + // at database creation time. + static void createTablespace(Connection conn) throws SQLException + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " CREATE USER TEMPORARY TABLESPACE \n" + + "TO MAKE A USER TEMPORARY TABLESPACE FOR THE TEMP TABLE \n" + + "IN A DIRECTORY CALLED usertemp, RELATIVE TO THE DATABASE" + + "\n Perform:\n" + + " CREATE USER TEMPORARY TABLESPACE usertemp1"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate("CREATE USER TEMPORARY TABLESPACE usertemp1"); + conn.commit(); + stmt.close(); + } // createTableSpace() + + // Declare a temporary table with the same columns as the one for the + // database's department table. Populate the temporary table and + // show the contents. + static void declareTempTable(Connection conn) throws Exception + { + // Declare the declared temporary table. It is created empty. + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " DECLARE GLOBAL TEMPORARY TABLE\n" + + "TO MAKE A GLOBAL DECLARED TEMPORARY TABLE WITH THE SAME \n" + + "COLUMNS AS THE DEPARTMENT TABLE." + + "\n Perform:\n" + + " DECLARE GLOBAL TEMPORARY TABLE temptb1 \n" + + " LIKE department \n" + + " NOT LOGGED\n"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate("DECLARE GLOBAL TEMPORARY TABLE temptb1 " + + " LIKE department " + + " NOT LOGGED " + + " IN usertemp1"); + conn.commit(); + stmt.close(); + + populateTempTable(conn); + showTableContents(conn); + + } // declareTempTable() + + // Drop the user temp tablespace. This function assumes that the tablespace + // can be dropped. If the declared temporary table still exists in the + // tablespace, then the tablespace cannot be dropped. + static void dropTablespace(Connection conn) throws SQLException + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " DROP TABLESPACE \n" + + "TO REMOVE THE TABLESPACE THAT THIS PROGRAM CREATED\n" + + "\n Perform:\n" + + " DROP TABLESPACE usertemp1\n"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate("DROP TABLESPACE usertemp1"); + conn.commit(); + stmt.close(); + + } // dropTablespace() + + // Populate the temp table with the department table's contents + static void populateTempTable(Connection conn) throws Exception + { + // Populating the temp table is done the same way as a normal table + // except the qualifier "session" is required whenever the table name + // is referenced. + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT\n" + + "TO POPULATE THE DECLARED TEMPORARY TABLE WITH DATA FROM\n" + + "THE DEPARTMENT TABLE\n" + + "\n Perform:\n" + + " INSERT INTO session.temptb1\n" + + " (SELECT deptno, deptname, mgrno, admrdept, location\n" + + " FROM department)\n"); + + Statement stmt = conn.createStatement(); + + stmt.executeUpdate( + "INSERT INTO session.temptb1 " + + "(SELECT deptno, deptname, mgrno, admrdept, location FROM department)"); + + stmt.close(); + + } // populateTempTable() + + // Declare the temp table temptb1 again, this time with logging option, + // thereby replacing the existing one. If the "with replace" option is not + // used, then an error will result if the table name is already associated + // with an existing temp table. Populate and show contents again. + static void recreateTempTableWithLogging(Connection conn) throws Exception + { + // Declare the declared temporary table again, this time without the + // NOT LOGGED clause. It is created empty. + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + "\nDECLARE GLOBAL TEMPORARY TABLE\n" + + "TO REPLACE A GLOBAL DECLARED TEMPORARY TABLE WITH A NEW\n" + + "TEMPORARY TABLE OF THE SAME NAME WITH LOGGING ENABLED.\n" + + "\n Perform:\n" + + " DECLARE GLOBAL TEMPORARY TABLE temptb1 \n" + + " LIKE department \n" + + " WITH REPLACE\n" + + " ON COMMIT PRESERVE ROWS\n" + + " IN usertemp1"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate("DECLARE GLOBAL TEMPORARY TABLE temptb1 " + + " LIKE department " + + " WITH REPLACE " + + " ON COMMIT PRESERVE ROWS " + + " IN usertemp1"); + stmt.close(); + + populateTempTable(conn); + showTableContents(conn); + + } // recreateTempTableWithLogging() + + // Show that the temp table still exists after the commit. All the + // rows will be deleted because the temp table was declared, by default, + // with "on commit delete rows". If "on commit preserve rows" was used, + // then the rows would have remained. + static void showAfterCommit(Connection conn) throws Exception + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " COMMIT\n" + + "TO SHOW THAT THE TEMP TABLE EXISTS AFTER A COMMIT BUT WITH\n" + + "ALL ROWS DELETED\n" + + "\n Perform:\n" + + " COMMIT\n"); + + + conn.commit(); + + showTableContents(conn); + + } // showAftercommit() + + // Use cursors to access each row of the declared temp table and then print + // each row. This function assumes that the declared temp table exists. + // This access is the same as accessing a normal table except the qualifier, + // "session", is required in the table name. + static void showTableContents(Connection conn) throws Exception + { + + // Variables to store data from the department table + + String deptno = ""; + String deptname = ""; + String mgrno = ""; + String admrdept = ""; + String location = ""; + + System.out.println("\n SELECT * FROM session.temptb1\n"); + System.out.println( + " DEPT# DEPTNAME MGRNO ADMRDEPT LOCATION\n"+ + " ----- ---------------------------- ------ -------- --------"); + + Statement stmt = conn.createStatement(); + + ResultSet rs = stmt.executeQuery("SELECT * FROM session.temptb1"); + + while (rs.next())//Fetch a row of data + { + try + { + deptno = rs.getObject("deptno").toString(); + } + catch (Exception e) + { + deptno = " -"; + } + + try + { + deptname = rs.getObject("deptname").toString(); + + if (deptname.length() < 28) // For GUI purposes + { + int l = 28 - deptname.length(); + while (l != 0) + { + deptname = deptname + " "; + l--; + } + } + } + catch (Exception e) + { + deptname = " -"; + } + + try + { + mgrno = rs.getObject("mgrno").toString(); + } + catch (Exception e) + { + mgrno = " -"; + } + + try + { + admrdept = rs.getObject("admrdept").toString(); + } + catch (Exception e) + { + admrdept = " -"; + } + + try + { + location = rs.getObject("location").toString(); + } + catch (Exception e) + { + location = " -"; + } + + System.out.println(" " + deptno + " " + deptname + " " + + mgrno + " " + admrdept + " " + location); + + } // while + + rs.close(); + stmt.close(); + conn.commit(); + + } // showTableContents() + + // create Index command can be used on temporary tables to improve + // the performance of queries + static void createIndex(Connection conn) throws Exception + { + System.out.print( + "\n-----------------------------------------------------------"); + System.out.print( + "\n Indexes can be created for temporary tables. Indexing a table\n" + + " optimizes query performance \n"); + + System.out.print( + "\n CREATE INDEX session.tb1ind \n" + + " ON session.temptb1 (deptno DESC) \n" + + " DISALLOW REVERSE SCANS \n"); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate( + "CREATE INDEX session.tb1ind " + + "ON session.temptb1(deptno DESC) " + + "DISALLOW REVERSE SCANS"); + + System.out.print( + "\n Following clauses in create index are not supported \n" + + " for temporary tables:\n" + + " SPECIFICATION ONLY\n" + + " CLUSTER\n" + + " EXTEND USING\n" + + " Option SHRLEVEL will have no effect when creating indexes \n" + + " on DGTTs and will be ignored \n"); + + System.out.print( + "\n Indexes can be dropped by issuing DROP INDEX statement, \n" + + " or they will be implicitly dropped when the underlying temp \n" + + " table is dropped.\n"); + + stmt.close(); + } // createIndex + + // Issue a SELECT * command on the temporary table created and use + // ResultSetMetaData to obtain description of the temporary table + static void describeTemporaryTable(Connection conn) throws Exception + { + System.out.print( + "\n-----------------------------------------------------------"); + System.out.print( + "\n Use ResultSetMetaData to get temporary table description\n" + + "\n Perform:" + + "\n SELECT * FROM session.temptb1\n" + + "\n Use ResultSetMetaData to get information about structure of" + + "\n the temporary table\n"); + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM session.temptb1"); + ResultSetMetaData rsmd = rs.getMetaData(); + int numberOfColumns = rsmd.getColumnCount(); + + String colName = ""; + String schemaName = ""; + String colType = ""; + int colLength, colScale, colNull; + + System.out.print( + "\n Column Type Type \n" + + " name schema name Length Scale Nulls\n"+ + " -------------------- -------- -------------- ------ ----- -----"); + + for (int i = 1; i <= numberOfColumns; i++) + { + colName = rsmd.getColumnName(i); + schemaName = rsmd.getSchemaName(i); + colType = rsmd.getColumnTypeName(i); + colLength = rsmd.getColumnDisplaySize(i); + colScale = rsmd.getScale(i); + colNull = rsmd.isNullable(i); + + System.out.print( + "\n " + Data.format(colName, 20) + " " + + Data.format(schemaName, 8) + " " + + Data.format(colType, 14) + " " + + Data.format(colLength, 6) + " " + + Data.format(colScale, 5) + " "); + + if (colNull == rsmd.columnNullable) + System.out.print("Yes"); + else if (colNull == rsmd.columnNoNulls) + System.out.print("No"); + else + System.out.print("Unknown"); + } + System.out.println(); + + rs.close(); + stmt.close(); + } // describeTemporaryTable +} // TbTemp diff --git a/java/jdbc/TbTrig.java b/java/jdbc/TbTrig.java new file mode 100644 index 0000000..43f95fa --- /dev/null +++ b/java/jdbc/TbTrig.java @@ -0,0 +1,1011 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbTrig.java +// +// SAMPLE: How to use triggers +// +// SQL Statements USED: +// CREATE TABLE +// CREATE TRIGGER +// DROP TABLE +// DROP TRIGGER +// SELECT +// INSERT +// UPDATE +// DELETE +// COMMIT +// ROLLBACK +// +// JAVA 2 CLASSES USED: +// Statement +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbTrig.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbTrig +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO USE TRIGGERS."); + + // connect to the 'sample' database + db.connect(); + + TbBeforeInsertTriggerUse(db.con); + TbAfterInsertTriggerUse(db.con); + TbBeforeDeleteTriggerUse(db.con); + TbBeforeUpdateTriggerUse(db.con); + TbAfterUpdateTriggerUse(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // helping function + static void StaffTbContentDisplay(Connection con) + { + try + { + int id = 0; + int dept = 0; + double salary = 0.0; + String name = null; + String job = null; + Integer years = new Integer(0); + Double comm = new Double(0.0); + + System.out.println(); + System.out.println(" SELECT * FROM staff WHERE id <= 50"); + + System.out.println( + " ID NAME DEPT JOB YEARS SALARY COMM\n" + + " --- ------- ---- ----- ----- -------- --------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT * FROM staff WHERE id <= 50"); + + while (rs.next()) + { + id = rs.getInt(1); + name = rs.getString(2); + dept = rs.getInt(3); + job = rs.getString(4); + + if (rs.getString(5) == null) + { + years = null; + } + else + { + years = Integer.valueOf(rs.getString(5)); + } + salary = rs.getDouble(6); + if (rs.getDouble(7) == 0.0) + { + comm = null; + } + else + { + comm = Double.valueOf(Double.toString(rs.getDouble(7))); + } + + System.out.print(" " + Data.format(id,3) + + " " + Data.format(name,7) + + " " + Data.format(dept,4)); + if (job != null) + { + System.out.print(" " + Data.format(job,5)); + } + else + { + System.out.print(" -"); + } + if (years != null) + { + System.out.print(" " + Data.format(years,5)); + } + else + { + System.out.print(" -"); + } + System.out.print(" " + Data.format(salary,7,2)); + if (comm != null) + { + System.out.print(" " + Data.format(comm,7,2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // StaffTbContentDisplay + + // helping function + static void StaffStatsTbCreate(Connection con) + { + try + { + System.out.println(); + System.out.println(" CREATE TABLE staff_stats(nbemp SMALLINT)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("CREATE TABLE staff_stats(nbemp SMALLINT)"); + stmt.close(); + + System.out.println(); + System.out.println( + " INSERT INTO staff_stats VALUES(SELECT COUNT(*) FROM staff)"); + + Statement stmt1 = con.createStatement(); + stmt1.execute( + "INSERT INTO staff_stats VALUES(SELECT COUNT(*) FROM staff)"); + stmt1.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // StaffStatsTbCreate + + // helping function + static void StaffStatsTbContentDisplay(Connection con) + { + try + { + System.out.println(); + System.out.println(" SELECT nbemp FROM staff_stats"); + System.out.println(" NBEMP\n" + + " -----"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM staff_stats"); + rs.next(); + + System.out.println(" " + Data.format(rs.getShort("nbemp"),5)); + stmt.close(); + rs.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // StaffStatsTbContentDisplay + + // helping function + static void StaffStatsTbDrop(Connection con) + { + try + { + System.out.println(); + System.out.println(" DROP TABLE staff_stats"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE staff_stats"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // StaffStatsTbDrop + + // helping function + static void SalaryStatusTbCreate(Connection con) + { + try + { + System.out.println(); + System.out.println( + " CREATE TABLE salary_status(emp_name VARCHAR(9),\n" + + " sal DECIMAL(7, 2),\n" + + " status CHAR(15))"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE salary_status(emp_name VARCHAR(9), " + + " sal DECIMAL(7, 2), " + + " status CHAR(15))"); + stmt.close(); + + System.out.println(); + System.out.println( + " INSERT INTO salary_status\n" + + " SELECT name, salary, 'Not Defined'\n" + + " FROM staff\n" + + " WHERE id <= 50"); + + Statement stmt1 = con.createStatement(); + stmt1.execute("INSERT INTO salary_status " + + " SELECT name, salary, 'Not Defined' " + + " FROM staff " + + " WHERE id <= 50"); + stmt1.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // SalaryStatusTbCreate + + // helping function + static void SalaryStatusTbContentDisplay(Connection con) + { + try + { + System.out.println(); + System.out.println(" SELECT * FROM salary_status"); + System.out.println(" EMP_NAME SALARY STATUS\n" + + " ---------- -------- ----------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM salary_status"); + + while (rs.next()) + { + System.out.println(" " + + Data.format(rs.getString("emp_name"),10) + " " + + Data.format(rs.getDouble("sal"),7,2) + " " + + Data.format(rs.getString("status"),15)); + } + stmt.close(); + rs.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // SalaryStatusTbContentDisplay + + // helping function + static void SalaryStatusTbDrop(Connection con) + { + try + { + System.out.println(); + System.out.println(" DROP TABLE salary_status"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE salary_status"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // SalaryStatusTbDrop + + // helping function + static void SalaryHistoryTbCreate(Connection con) + { + System.out.println(); + System.out.println( + " CREATE TABLE salary_history(employee_name VARCHAR(9),\n" + + " salary_record DECIMAL(7, 2),\n" + + " change_date DATE)"); + + try + { + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "CREATE TABLE salary_history(employee_name VARCHAR(9), " + + " salary_record DECIMAL(7, 2), " + + " change_date DATE)"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // SalaryHistoryTbCreate + + // helping function + static void SalaryHistoryTbContentDisplay(Connection con) + { + try + { + System.out.println(); + System.out.println(" SELECT * FROM salary_history"); + System.out.println(" EMPLOYEE_NAME SALARY_RECORD CHANGE_DATE\n" + + " -------------- -------------- -----------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM salary_history"); + + while (rs.next()) + { + System.out.println(" " + + Data.format(rs.getString("employee_name"),14) + " " + + Data.format(rs.getDouble("salary_record"),13,2) + " " + + rs.getDate("change_date")); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // SalaryHistoryTbContentDisplay + + // helping function + static void SalaryHistoryTbDrop(Connection con) + { + try + { + System.out.println(); + System.out.println(" DROP TABLE salary_history"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE salary_history"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // SalaryHistoryTbDrop + + + static void TbBeforeInsertTriggerUse(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " INSERT\n" + + " ROLLBACK\n" + + " DROP TRIGGER\n" + + "TO SHOW A 'BEFORE INSERT' TRIGGER."); + + // display the initial content of the 'staff' table + StaffTbContentDisplay(con); + + // create a 'BEFORE INSERT' trigger + try + { + System.out.println(); + System.out.println(" CREATE TRIGGER min_sal\n" + + " NO CASCADE BEFORE INSERT\n" + + " ON staff\n" + + " REFERENCING NEW AS newstaff\n" + + " FOR EACH ROW \n" + + " BEGIN ATOMIC\n" + + " SET newstaff.salary =\n" + + " CASE\n" + + " WHEN newstaff.job = 'Mgr' AND\n" + + " newstaff.salary < 17000.00\n" + + " THEN 17000.00\n" + + " WHEN newstaff.job = 'Sales' AND\n" + + " newstaff.salary < 14000.00\n" + + " THEN 14000.00\n" + + " WHEN newstaff.job = 'Clerk' AND\n" + + " newstaff.salary < 10000.00\n" + + " THEN 10000.00\n" + + " ELSE newstaff.salary\n" + + " END;\n" + + " END"); + + Statement stmt = con.createStatement(); + stmt.execute("CREATE TRIGGER min_sal " + + " NO CASCADE BEFORE INSERT " + + " ON staff " + + " REFERENCING NEW AS newstaff " + + " FOR EACH ROW " + + " BEGIN ATOMIC " + + " SET newstaff.salary = " + + " CASE " + + " WHEN newstaff.job = 'Mgr' AND " + + " newstaff.salary < 17000.00 " + + " THEN 17000.00 " + + " WHEN newstaff.job = 'Sales' AND " + + " newstaff.salary < 14000.00 " + + " THEN 14000.00 " + + " WHEN newstaff.job = 'Clerk' AND " + + " newstaff.salary < 10000.00 " + + " THEN 10000.00 " + + " ELSE newstaff.salary " + + " END; " + + " END"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // insert table data using values + try + { + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " INSERT INTO staff(id, name, dept, job, salary)\n" + + " VALUES(25, 'Pearce', 38, 'Clerk', 7217.50),\n" + + " (35, 'Hachey', 38, 'Mgr', 21270.00),\n" + + " (45, 'Wagland', 38, 'Sales', 11575.00)"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO staff(id, name, dept, job, salary) " + + " VALUES(25, 'Pearce', 38, 'Clerk', 7217.50), " + + " (35, 'Hachey', 38, 'Mgr', 21270.00), " + + " (45, 'Wagland', 38, 'Sales', 11575.00)"); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the final content of the 'staff' table + StaffTbContentDisplay(con); + + // drop the trigger + try + { + System.out.println(); + System.out.println(" Rollback the transaction."); + con.rollback(); + + System.out.println(); + System.out.println(" DROP TRIGGER min_sal"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("DROP TRIGGER min_sal"); + stmt2.close(); + + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // TbBeforeInsertTriggerUse + + static void TbAfterInsertTriggerUse(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " INSERT\n" + + " ROLLBACK\n" + + " DROP TRIGGER\n" + + "TO SHOW AN 'AFTER INSERT' TRIGGER."); + + // create a table called 'staff_stats' + StaffStatsTbCreate(con); + + // display the content of the 'staff_stats' table + StaffStatsTbContentDisplay(con); + + // create an 'AFTER INSERT' trigger + try + { + System.out.println(); + System.out.println(" CREATE TRIGGER new_hire\n" + + " AFTER INSERT\n" + + " ON staff\n" + + " FOR EACH ROW \n" + + " BEGIN ATOMIC\n" + + " UPDATE staff_stats\n" + + " SET nbemp = nbemp + 1;\n" + + " END"); + + Statement stmt = con.createStatement(); + stmt.execute("CREATE TRIGGER new_hire " + + " AFTER INSERT " + + " ON staff " + + " FOR EACH ROW " + + " BEGIN ATOMIC " + + " UPDATE staff_stats " + + " SET nbemp = nbemp + 1; " + + " END"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // insert table data using values + try + { + String strStmt; + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " INSERT INTO staff(id, name, dept, job, salary)\n" + + " VALUES(25, 'Pearce', 38, 'Clerk', 7217.50),\n" + + " (35, 'Hachey', 38, 'Mgr', 21270.00),\n" + + " (45, 'Wagland', 38, 'Sales', 11575.00)"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO staff(id, name, dept, job, salary) " + + " VALUES(25, 'Pearce' , 38, 'Clerk', 7217.50), " + + " (35, 'Hachey' , 38, 'Mgr' , 21270.00), " + + " (45, 'Wagland', 38, 'Sales', 11575.00)"); + stmt1.close(); + + // display the content of the 'staff_stats' table + StaffStatsTbContentDisplay(con); + + System.out.println(); + System.out.println(" Rollback the transaction."); + con.rollback(); + + System.out.println(); + System.out.println(" DROP TRIGGER new_hire"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("DROP TRIGGER new_hire"); + + stmt2.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop the 'staff_stats' table + StaffStatsTbDrop(con); + + } // TbAfterInsertTriggerUse + + static void TbBeforeDeleteTriggerUse(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " DELETE\n" + + " ROLLBACK\n" + + " DROP TRIGGER\n" + + "TO SHOW A 'BEFORE DELETE' TRIGGER."); + + // display the initial content of the 'staff' table + StaffTbContentDisplay(con); + + // create a 'BEFORE DELETE' trigger + try + { + System.out.println(); + System.out.println(" CREATE TRIGGER do_not_delete_sales\n" + + " NO CASCADE BEFORE DELETE\n" + + " ON staff\n" + + " REFERENCING OLD AS oldstaff\n" + + " FOR EACH ROW \n" + + " WHEN (oldstaff.job = 'Sales')\n" + + " BEGIN ATOMIC\n" + + " SIGNAL SQLSTATE '75000' " + + "('Sales can not be deleted now.');\n" + + " END"); + + Statement stmt = con.createStatement(); + stmt.execute("CREATE TRIGGER do_not_delete_sales " + + " NO CASCADE BEFORE DELETE " + + " ON staff " + + " REFERENCING OLD AS oldstaff " + + " FOR EACH ROW " + + " WHEN (oldstaff.job = 'Sales') " + + " BEGIN ATOMIC " + + " SIGNAL SQLSTATE '75000' " + + " ('Sales can not be deleted now.'); " + + " END"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // delete data from the 'staff' table + try + { + System.out.println(); + System.out.println(" Invoke the statement:\n" + + " DELETE FROM staff WHERE id <= 50"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("DELETE FROM staff WHERE id <= 50"); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + // display the final content of the 'staff' table + StaffTbContentDisplay(con); + + // drop the trigger + try + { + System.out.println(); + System.out.println(" Rollback the transaction."); + con.rollback(); + + System.out.println(); + System.out.println(" DROP TRIGGER do_not_delete_sales"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("DROP TRIGGER do_not_delete_sales"); + stmt2.close(); + + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // TbBeforeDeleteTriggerUse + + static void TbBeforeUpdateTriggerUse(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " UPDATE\n" + + " ROLLBACK\n" + + " DROP TRIGGER\n" + + "TO SHOW A 'BEFORE UPDATE' TRIGGER."); + + // create a table called salary_status + SalaryStatusTbCreate(con); + + // display the content of the 'salary_status' table + SalaryStatusTbContentDisplay(con); + + // create a 'BEFORE UPDATE' trigger + try + { + System.out.println(); + System.out.println(" CREATE TRIGGER salary_status\n" + + " NO CASCADE BEFORE UPDATE OF sal\n" + + " ON salary_status\n" + + " REFERENCING NEW AS new OLD AS old\n" + + " FOR EACH ROW \n" + + " BEGIN ATOMIC\n" + + " SET new.status =\n" + + " CASE\n" + + " WHEN new.sal < old.sal\n" + + " THEN 'Decreasing'\n" + + " WHEN new.sal > old.sal\n" + + " THEN 'Increasing'\n" + + " END;\n" + + " END"); + + Statement stmt = con.createStatement(); + stmt.execute("CREATE TRIGGER sal_status " + + " NO CASCADE BEFORE UPDATE OF sal " + + " ON salary_status " + + " REFERENCING NEW AS new OLD AS old " + + " FOR EACH ROW " + + " BEGIN ATOMIC " + + " SET new.status = " + + " CASE " + + " WHEN new.sal < old.sal " + + " THEN 'Decreasing' " + + " WHEN new.sal > old.sal " + + " THEN 'Increasing' " + + " END; " + + " END "); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // update data in table 'salary_status' + try + { + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE salary_status SET sal = 18000.00"); + + Statement stmt1 = con.createStatement(); + stmt1.execute("UPDATE salary_status SET sal = 18000.00"); + stmt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the content of the 'salary_status' table + SalaryStatusTbContentDisplay(con); + + // rollback the transaction + try + { + System.out.println(); + System.out.println(" Rollback the transaction."); + con.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop the trigger + try + { + System.out.println(); + System.out.println(" DROP TRIGGER sal_status"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate("DROP TRIGGER sal_status"); + stmt2.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop salary_status table + SalaryStatusTbDrop(con); + + } // TbBeforeUpdateTriggerUse + + static void TbAfterUpdateTriggerUse(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " UPDATE\n" + + " DROP TRIGGER\n" + + "TO SHOW AN 'AFTER UPDATE' TRIGGER."); + + // create a table called 'salary_history' + SalaryHistoryTbCreate(con); + + // display the content of the 'salary_history' table + SalaryHistoryTbContentDisplay(con); + + try + { + System.out.println(); + System.out.println(" CREATE TRIGGER sal_history\n" + + " AFTER UPDATE OF salary\n" + + " ON staff\n" + + " REFERENCING NEW AS newstaff\n" + + " FOR EACH ROW \n" + + " BEGIN ATOMIC\n" + + " INSERT INTO salary_history\n" + + " VALUES(newstaff.name,\n" + + " newstaff.salary,\n" + + " CURRENT DATE);\n" + + " END"); + + Statement stmt = con.createStatement(); + stmt.execute("CREATE TRIGGER sal_history " + + " AFTER UPDATE OF salary " + + " ON staff " + + " REFERENCING NEW AS newstaff " + + " FOR EACH ROW " + + " BEGIN ATOMIC " + + " INSERT INTO salary_history " + + " VALUES(newstaff.name, " + + " newstaff.salary, " + + " CURRENT DATE); " + + " END"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // update table data + try + { + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 20000.00 WHERE name = 'Sanders'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "UPDATE staff SET salary = 20000.00 WHERE name = 'Sanders'"); + stmt1.close(); + + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 21000.00 WHERE name = 'Sanders'"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "UPDATE staff SET salary = 21000.00 WHERE name = 'Sanders'"); + stmt2.close(); + + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 23000.00 WHERE name = 'Sanders'"); + + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate( + "UPDATE staff SET salary = 23000.00 WHERE name = 'Sanders'"); + stmt3.close(); + + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 20000.00 WHERE name = 'Hanes'"); + + Statement stmt4 = con.createStatement(); + stmt4.executeUpdate( + "UPDATE staff SET salary = 20000.00 WHERE name = 'Hanes'"); + stmt4.close(); + + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 21000.00 WHERE name = 'Hanes'"); + + Statement stmt5 = con.createStatement(); + stmt5.executeUpdate( + "UPDATE staff SET salary = 21000.00 WHERE name = 'Hanes'"); + stmt5.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the content of the 'salary_history' table + SalaryHistoryTbContentDisplay(con); + + // rollback the transaction + try + { + System.out.println(); + System.out.println(" Rollback the transaction."); + con.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop the trigger + try + { + System.out.println(); + System.out.println(" DROP TRIGGER sal_history"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TRIGGER sal_history"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // drop the 'salary_history' table + SalaryHistoryTbDrop(con); + + } // TbAfterUpdateTriggerUse +} // TbTrig + diff --git a/java/jdbc/TbUMQT.java b/java/jdbc/TbUMQT.java new file mode 100644 index 0000000..d94a075 --- /dev/null +++ b/java/jdbc/TbUMQT.java @@ -0,0 +1,952 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbUMQT.java +// +// SAMPLE: How to use user materialized query tables (summary tables). +// +// This sample: +// 1. Query Table (UMQT) for the 'employee' table. +// 2. Shows the usage and update mechanisms for non-partitioned UMQTs. +// 3. Creates a new partitioned Maintained Materialized +// Query Table (MQT). +// 4. Shows the availability of partitioned MQTs during SET INTEGRITY +// after add/detach of a partition via ALTER ADD PARTITION and +// ALTER DETACH PARTITION. +// +// SQL Statements USED: +// ALTER TABLE +// CREATE TABLE +// EXECUTE IMMEDIATE +// DROP +// INSERT +// SELECT +// SET CURRENT +// SET INTEGRITY +// REFRESH TABLE +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbUMQT.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//************************************************************************** + +import java.lang.*; +import java.sql.*; + +class TbUMQT +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println( + "\nTHIS SAMPLE SHOWS THE USAGE OF USER MAINTAINED MATERIALIZED.\n" + + " QUERY TABLES(MQTs).\n"); + + // connect to the 'sample' database + db.connect(); + + // create summary tables + createMQT(db.con); + + // bring the summary tables out of check-pending state + setIntegrity(db.con); + + // populate the base table and update contents of the summary tables + updateUserMQT(db.con); + + // set registers to optimize query processing by routing queries to + // UMQT + setRegisters(db.con); + + // issue a select statement that is routed to the summary tables + showTableContents(db.con); + + // drop summary tables + dropTables(db.con); + + // creates regular DMS tablespaces + dms_tspaceaceCreate(db.con); + + // creates a partitioned table + partitionedTbCreate(db.con); + + // create MQT on a paartitioned table + createMQT_on_Partitionedtb(db.con); + + // create partitione MQT on a partitioned table + createPartitioned_MQT(db.con); + + // drop tablespaces + tablespacesDrop(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + } // main + + // Create summary tables. + static void createMQT(Connection con) + { + Statement stmt; + + System.out.println( + "\n----------------------------------------------------------\n" + + "Creating UMQT on EMPLOYEE table...\n"); + try + { + System.out.println( + "USE THE SQL STATEMENT:\n" + + " CREATE SUMMARY TABLE \n" + + "TO CREATE A UMQT WITH DEFERRED REFRESH\n\n" + + "Execute the statement:\n" + + "CREATE SUMMARY TABLE umqt_employee AS \n" + + " (SELECT workdept, count(*) AS no_of_employees \n" + + " FROM employee GROUP BY workdept)\n" + + " DATA INITIALLY DEFERRED REFRESH DEFERRED\n" + + " MAINTAINED BY USER\n"); + + stmt = con.createStatement(); + stmt.executeUpdate( + " CREATE SUMMARY TABLE umqt_employee AS" + + " (SELECT workdept, count(*) AS no_of_employees" + + " FROM employee GROUP BY workdept)" + + " DATA INITIALLY DEFERRED REFRESH DEFERRED" + + " MAINTAINED BY USER"); + + // commit the transaction + con.commit(); + + stmt.close(); + } + + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // creating a UMQT with immediate refresh option is not supported + try + { + System.out.println( + "\nCREATE SUMMARY TABLE to create a UMQT with immediate\n" + + "refresh option is not supported\n\n" + + "Execute the statement:\n" + + "CREATE SUMMARY TABLE aimdusr AS \n" + + " (SELECT workdept, count(*) AS no_of_employees \n" + + " FROM employee GROUP BY workdept)\n" + + " DATA INITIALLY DEFERRED REFRESH IMMEDIATE\n" + + " MAINTAINED BY USER\n"); + + stmt = con.createStatement(); + stmt.executeUpdate( + " CREATE SUMMARY TABLE aimdusr AS" + + " (SELECT workdept, count(*) AS no_of_employees" + + " FROM employee GROUP BY workdept)" + + " DATA INITIALLY DEFERRED REFRESH IMMEDIATE" + + " MAINTAINED BY USER"); + + // commit the transaction + System.out.println("\n COMMIT"); + con.commit(); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + + } // createMQT + + // Bring the summary tables out of check-pending state. + static void setIntegrity(Connection con) + { + System.out.println( + "\n-----------------------------------------------------------"); + System.out.println( + "USE THE SQL STATEMENT:\n" + + " SET INTEGRITY \n" + + "To bring the MQTs out of check pending state\n"); + try + { + System.out.println( + "Execute the statement:\n" + + "SET INTEGRITY FOR umqt_employee ALL IMMEDIATE UNCHECKED\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "SET INTEGRITY FOR umqt_employee ALL IMMEDIATE UNCHECKED"); + + // commit the transaction + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + } // setIntegrity + + // Populate the base table and update the contents of the summary tables. + static void updateUserMQT(Connection con) + { + System.out.println( + "\n-----------------------------------------------------------\n" + + "\nUMQT_EMPLOYEE must be updated manually by the user\n\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "To update the UMQT\n "); + try + { + System.out.println( + "Execute the statement:\n" + + "INSERT INTO umqt_employee \n" + + " (SELECT workdept, count(*) AS no_of_employees\n" + + " FROM employee GROUP BY workdept)\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO umqt_employee "+ + " (SELECT workdept, count(*) AS no_of_employees " + + " FROM employee GROUP BY workdept)"); + + // commit the transaction + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + } // updateUserMQT + + // Set registers to optimize query processing by routing queries to UMQT. + static void setRegisters(Connection con) + { + // the CURRENT REFRESH AGE special register must be set to a value other + // than zero for the specified table types to be considered when + // optimizing the processing of dynamic SQL queries. + + System.out.println( + "\n-----------------------------------------------------------\n" + + "The following registers must be set to route queries to UMQT\n"); + + try + { + System.out.println( + "\n SET CURRENT REFRESH AGE ANY\n" + + "\nIndicates that any table types specified by CURRENT MAINTAINED" + + "\nTABLE TYPES FOR OPTIMIZATION, and MQTs defined with REFRESH \n" + + "IMMEDIATE option, can be used to optimize the \n" + + "processing of a query. \n\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("SET CURRENT REFRESH AGE ANY"); + + System.out.println( + " SET CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION USER \n\n" + + "Specifies that user-maintained refresh-deferred materialized \n" + + "query tables can be considered to optimize the processing of \n" + + "dynamic SQL queries. \n"); + + stmt.executeUpdate( + "SET CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION USER"); + + // commit the transaction + con.commit(); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // setRegisters + + // Issue a select statement that is routed to the summary tables. + static void showTableContents(Connection con) + { + String workDept = null; + int countWorkDept = 0; + + System.out.println( + "\n-----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " SELECT\n" + + "On EMPLOYEE table. This is routed to the UMQT umqt_employee\n"); + + try + { + Statement stmt = con.createStatement(); + ResultSet rs; + + System.out.println( + " SELECT workdept, count(*) AS no_of_employees \n" + + " FROM employee GROUP BY workdept\n"); + System.out.println( + " DEPT CODE NO. OF EMPLOYEES \n" + + " ---------- ----------------"); + + // perform a SELECT against the "employee" table in the sample database + rs = stmt.executeQuery( + "SELECT workdept, count(*) AS no_of_employees " + + "FROM employee GROUP BY workdept"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + workDept = rs.getString("workdept"); + countWorkDept = rs.getInt("no_of_employees"); + + System.out.println( + " " + + Data.format(workDept, 7) + " " + + Data.format(countWorkDept, 17)); + } + rs.close(); + + System.out.println( + "\nA SELECT query on umqt_employee yields similar results\n\n" + + " SELECT * FROM umqt_employee \n"); + System.out.println( + " DEPT CODE NO. OF EMPLOYEES \n" + + " ---------- ----------------\n"); + + // perform a SELECT against umqt_employee query table + rs = stmt.executeQuery(" SELECT * FROM umqt_employee"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + workDept = rs.getString("workdept"); + countWorkDept = rs.getInt("no_of_employees"); + + System.out.println( + " " + + Data.format(workDept, 7) + " " + + Data.format(countWorkDept, 17)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // showTableContents + + // drop tables. + static void dropTables(Connection con) + { + System.out.println( + "\nDropping tables...\n\n" + + "USE THE SQL STATEMENT:\n" + + " DROP\n" + + "To drop the UMQT umqt_employee\n"); + + try + { + System.out.println( + "Execute the statement:\n" + + "DROP TABLE umqt_employee\n"); + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE umqt_employee"); + + // commit the transaction + con.commit(); + + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // dropTables + + // creates regular DMS tablespaces. + static void dms_tspaceaceCreate(Connection con) throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " CREATE REGULAR TABLESPACE \n" + + "TO CREATE A REGULAR DMS TABLESPACES \n" + + "\nExecute the statement:\n" + + " CREATE REGULAR TABLESPACE dms_tspace"); + + // create regular DMS table space 'dms_tspace' + Statement stmt = con.createStatement(); + String str = ""; + str = "CREATE REGULAR TABLESPACE dms_tspace"; + stmt.executeUpdate(str); + + System.out.println( + "\nExecute the statement:\n" + + " CREATE REGULAR TABLESPACE dms_tspace1"); + + // create regular DMS table space 'dms_tspace1' + str = "CREATE REGULAR TABLESPACE dms_tspace1"; + stmt.executeUpdate(str); + + System.out.println( + "\nExecute the statement:\n" + + " CREATE REGULAR TABLESPACE dms_tspace2"); + + // create regular DMS table space 'dms_tspace2' + str = "CREATE REGULAR TABLESPACE dms_tspace2"; + stmt.executeUpdate(str); + + System.out.println( + "\nExecute the statement:\n" + + " CREATE REGULAR TABLESPACE dms_tspace3"); + + // create regular DMS table space 'dms_tspace3' + str = "CREATE REGULAR TABLESPACE dms_tspace3"; + stmt.executeUpdate(str); + + System.out.println( + "\n-----------------------------------------------------------"); + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } //dms_tspaceaceCreate + + // create a partitioned table in regular DMS tablespaces i.e; 'part1' is + // placed in 'dms_tspace1', 'part2' is placed in 'dms_tspace2' and + // 'part3' in 'dms_tspace3' and inserts data into it. + static void partitionedTbCreate(Connection con) throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n" + + "\nExecute the statement:\n" + + " CREATE TABLE fact_table (max SMALLINT NOT NULL,\n" + + " CONSTRAINT CC CHECK (max>0))\n" + + " PARTITION BY RANGE (max)\n "+ + " (PART part1 STARTING FROM (1) ENDING (3) IN dms_tspace1,\n" + + " PART part2 STARTING FROM (4) ENDING (6) IN dms_tspace2,\n" + + " PART part3 STARTING FROM (7) ENDING (9) IN dms_tspace3)"); + + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "CREATE TABLE fact_table "; + str = str + "(max SMALLINT NOT NULL, CONSTRAINT CC CHECK (max>0))"; + str = str + " PARTITION BY RANGE (max) "; + str = str + "(PART part1 STARTING FROM (1) ENDING (3) "; + str = str + "IN dms_tspace1, PART part2 STARTING FROM (4) ENDING (6) "; + str = str + "IN dms_tspace2, PART part3 STARTING FROM (7) ENDING (9) "; + str = str + "IN dms_tspace3)"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " INSERT INTO \n" + + "TOINSERT DATA IN A TABLE \n" + + "\nExecute the statement:\n" + + " INSERT INTO fact_table VALUES (1), (2), (3),\n" + + " (4), (5), (6),\n" + + " (7), (8), (9)"); + + // insert data into the table + Statement stmt = con.createStatement(); + String str = ""; + + str = "INSERT INTO fact_table VALUES (1), (2), (3), (4),"; + str = str + " (5), (6), (7), (8), (9)"; + stmt.executeUpdate(str); + + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // partitionedTbCreate + + // creates MQT on a partitioned table. Performs SET INTEGRITY on MQT to + // bring MQT out of check pending state and to get changes reflected. + static void createMQT_on_Partitionedtb (Connection con) throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n" + + "\nExecute the statement:\n" + + " CREATE TABLE mqt_fact_table AS\n" + + " (SELECT max, COUNT (*) AS no_of_rows FROM fact_table)\n" + + " GROUP BY max) DATA INITIALLY DEFERRED REFRESH IMMEDIATE"); + + Statement stmt = con.createStatement(); + String str = ""; + str = str + "CREATE TABLE mqt_fact_table AS"; + str = str + "(SELECT max, COUNT (*) AS no_of_rows FROM fact_table "; + str = str + " GROUP BY max) DATA INITIALLY DEFERRED REFRESH IMMEDIATE"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:" + + "\n SET INTEGRITY " + + "\nTO PERFORM SET INTEGRITY ON A TABLE\n" + + "\nExecute the statement:" + + "\n SET INTEGRITY FOR mqt_fact_table IMMEDIATE CHECKED"); + + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "SET INTEGRITY FOR mqt_fact_table IMMEDIATE CHECKED"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the contents of a table + displaytbData(con); + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " DROP\n" + + "TO DROP A TABLE.\n" + + + "\nExecute the statements:" + + "\n DROP TABLE mqt_fact_table" + + "\n DROP TABLE fact_table"); + + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "DROP TABLE mqt_fact_table"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + stmt = con.createStatement(); + str = ""; + + str = str + "DROP TABLE fact_table"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + } // createMQT_on_Partitionedtb + + // creates a partitioned MQT on a partitioned table whose range is less + // then that of the base table. Partition is added to MQT and + // REFRESH TABLE is performed on MQT to bring MQT out of check pending + // state and to get changes reflected to MQT. + static void createPartitioned_MQT(Connection con) throws SQLException + { + // creates a partitioned table + partitionedTbCreate(con); + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " CREATE\n" + + "TO CREATE A PARTITIONED MQT ON A PARTITIONED TABLE .\n" + + + "\nExecute the statement:" + + "\n CREATE TABLE mqt_fact_table AS" + + "\n (SELECT max, COUNT (*) AS no_of_rows FROM fact_table \n" + + "\n GROUP BY max) DATA INITIALLY DEFERRED REFRESH IMMEDIATE\n" + + " PARTITION BY RANGE (max)\n" + + " (STARTING 0 ENDING 6 EVERY 3)\n"); + + Statement stmt = con.createStatement(); + String str = ""; + str = str + "CREATE TABLE mqt_fact_table AS" ; + str = str + "(SELECT max, COUNT (*) AS no_of_rows FROM fact_table "; + str = str + " GROUP BY max) DATA INITIALLY DEFERRED REFRESH IMMEDIATE"; + str = str + " PARTITION BY RANGE (max)"; + str = str + " (STARTING 0 ENDING 6 EVERY 3)"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLE \n" + + "TO ADD PARTITION TO MQT\n" + + "\nExecute the statement:" + + "\n ALTER TABLE mqt_fact_table ADD PARTITION part4\n " + + " STARTING (7) ENDING (9)\n"); + + Statement stmt = con.createStatement(); + String str = ""; + str = str + "ALTER TABLE mqt_fact_table ADD PARTITION part4 "; + str = str + "STARTING (7) ENDING (9)"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " REFRESH\n" + + "TO REFRESH TABLE\n" + + "\nExecute the statement:" + + "\n REFRESH TABLE mqt_fact_table"); + + stmt = con.createStatement(); + str = ""; + str = str + "REFRESH TABLE mqt_fact_table"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + // display the contents of a table. + displaytbData(con); + + // detach partition from a table. + Detach_Partitiontb(con); + } // createPartitioned_MQT + + // detach a partition from 'fact_table'. + // SET INTEGRITY is performed on MQT to bring it out of + // check pending state. Later, a partition is detached form + // 'mqt_fact_table'. REFRESH TABLE is performed on MQT to bring it out of + // check pending state and to get changes reflected into MQT. + static void Detach_Partitiontb(Connection con) throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLE \n" + + "TO DETACH A PARTITION FROM A TABLE\n" + + + "\nExecute the statement\n" + + " ALTER TABLE fact_table DETACH PARTITION part2 INTO \n" + + " TABLE detach_part1"); + + Statement stmt = con.createStatement(); + String str = ""; + str = str + "ALTER TABLE fact_table DETACH PARTITION part2 "; + str = str + " INTO TABLE detach_part1"; + + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + System.out.println( + "\nUSE THE SQL STATEMENT:" + + "\n SET INTEGRITY \n" + + "TO BRING THE MQTs OUT OF CHECK PENDING STATE\n" + + + "\nExecute the statement:" + + "\nSET INTEGRITY FOR mqt_fact_table IMMEDIATE CHECKED"); + + Statement stmt = con.createStatement(); + String str = ""; + + str = str + "SET INTEGRITY FOR mqt_fact_table IMMEDIATE CHECKED"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + System.out.println( + "\nExecute the statement:\n" + + " ALTER TABLE mqt_fact_table DETACH PARTITION part2\n " + + " INTO TABLE detach_part2"); + + stmt = con.createStatement(); + str = ""; + str = str + "ALTER TABLE mqt_fact_table DETACH PARTITION part2 "; + str = str + " INTO TABLE detach_part2"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + System.out.println( + "\nUSE THE SQL STATEMENT:" + + "\n REFRESH\n" + + "TO GET CHANGES REFLECTED\n" + + + "\nExecute the statement:" + + "\n REFRESH TABLE mqt_fact_table"); + + stmt = con.createStatement(); + str = ""; + str = str + "REFRESH TABLE mqt_fact_table"; + stmt.executeUpdate(str); + con.commit(); + stmt.close(); + + // display the contents of a table + displaytbData(con); + } // Detach_Partitiontb + + // display the contents of a table. + static void displaytbData(Connection con) throws SQLException + { + System.out.println( + "\n-----------------------------------------------------------"); + try + { + int max = 0; + + System.out.println(); + System.out.println("SELECT * FROM fact_table"); + System.out.println( + " MAX\n" + + " ------"); + + Statement stmt = con.createStatement(); + // perform a SELECT against the "fact_table" table. + ResultSet rs1 = stmt.executeQuery("SELECT * FROM fact_table"); + + // retrieve and display the result from the SELECT statement + while (rs1.next()) + { + max = rs1.getInt(1); + + System.out.println( + " " + + Data.format(max, 3)); + } + rs1.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + + try + { + int max = 0; + int no_of_rows = 0; + System.out.println(); + System.out.println("SELECT * FROM mqt_fact_table"); + System.out.println( + " MAX NO_OF_ROWS\n" + + " ------ ------------"); + Statement stmt = con.createStatement(); + // perform a SELECT against the "mqt_fact_table" table. + ResultSet rs = stmt.executeQuery("SELECT * FROM mqt_fact_table"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + max = rs.getInt(1); + no_of_rows = rs.getInt(2); + System.out.println( + " " + + Data.format(max, 3)+ " " + + Data.format(no_of_rows, 8)); + } + rs.close(); + stmt.close(); + System.out.println( + "\n-----------------------------------------------------------"); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // displaytbData + + // drop tables. + static void cleanup(Connection con) throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " DROP \n" + + "TO DROP THE TABLES \n" + + "\nExecute the statements:\n" + + " DROP TABLE fact_table\n" + + " DROP TABLE mqt_fact_table\n" + + " DROP TABLE detach_part1\n" + + " DROP TABLE detach_part2"); + + // drop the tables + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLE mqt_fact_table"); + stmt.executeUpdate("DROP TABLE fact_table"); + stmt.executeUpdate("DROP TABLE detach_part1"); + stmt.executeUpdate("DROP TABLE detach_part2"); + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // cleanup + + // drop tablespaces. + static void tablespacesDrop(Connection con) throws SQLException + { + // drop tables. + cleanup(con); + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " DROP \n" + + "TO DROP THE TABLESPACES \n" + + "\nExecute the statements:\n" + + " DROP TABLESPACE dms_tspace\n" + + " DROP TABLESPACE dms_tspace1\n" + + " DROP TABLESPACE dms_tspace2\n" + + " DROP TABLESPACE dms_tspace3"); + + // drop the tablespaces + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TABLESPACE dms_tspace"); + stmt.executeUpdate("DROP TABLESPACE dms_tspace1"); + stmt.executeUpdate("DROP TABLESPACE dms_tspace2"); + stmt.executeUpdate("DROP TABLESPACE dms_tspace3"); + + con.commit(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // tablespacesDrop +} // TbUMQT + diff --git a/java/jdbc/TbUnion.java b/java/jdbc/TbUnion.java new file mode 100644 index 0000000..59302d8 --- /dev/null +++ b/java/jdbc/TbUnion.java @@ -0,0 +1,700 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbUnion.java +// +// SAMPLE: How to insert through a UNION ALL view +// +// SQL Statements USED: +// SELECT +// CREATE TABLE +// ALTER TABLE +// DROP TABLE +// CREATE VIEW +// DROP VIEW +// INSERT +// DELETE +// UPDATE +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: TbUnion.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class TbUnion +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + " THIS SAMPLE SHOWS HOW TO INSERT THROUGH A 'UNION ALL' VIEW.\n"); + + // Connect to the 'sample' database + db.connect(); + + // Create tables Q1, Q2, Q3 and Q4 and add constraints to them. + // Also create a view FY which is a view over the full year. + CreateTablesAndView(db.con); + + // Insert some values directly into tables Q1, Q2, Q3 and Q4 + InsertInitialValuesInTables(db.con); + + // Demonstrate how to insert through a UNION ALL view + InsertUsingUnionAll(db.con); + + // Modify the constraints of table Q1 + NewConstraints(db.con); + + // Attempt to insert data through a UNION ALL view where no table + // accepts the row + InsertWhenNoTableAcceptsIt(db.con); + + // Attempt to insert data through a UNION ALL view where more than + // one table accepts the row + InsertWhenMoreThanOneTableAcceptsIt(db.con); + + // Drop, recreate and reinitialize the tables and view + DropTablesAndView(db.con); + CreateTablesAndView(db.con); + InsertInitialValuesInTables(db.con); + + // Create a new view and perform some updates through it. This shows how + // updates through a view with row migration affect the underlying + // tables + UpdateWithRowMovement(db.con); + + // Show two special cases of row migration involving tables with + // overlapping constraints + UpdateWithRowMovementSpecialCase(db.con); + + // Drop tables Q1, Q2, Q3 and Q4 and the view FY + DropTablesAndView(db.con); + + // Disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // This method create tables Q1, Q2, Q3 and Q4 and adds constraints + // to them. It also creates a view FY which is a view over the full year. + public static void CreateTablesAndView(Connection con) + { + try + { + System.out.println(); + System.out.println( + " CREATE TABLES Q1,Q2,Q3 AND Q4 BY INVOKING\n" + + " THE STATEMENTS:\n\n" + + " CREATE TABLE Q1(product_no INT, sales INT, date DATE)\n" + + " CREATE TABLE Q2 LIKE Q1\n" + + " CREATE TABLE Q3 LIKE Q1\n" + + " CREATE TABLE Q4 LIKE Q1\n"); + + // Create tables Q1, Q2, Q3 and Q4 + Statement stmt = con.createStatement(); + stmt.execute( + "CREATE TABLE Q1(product_no INT, sales INT, date DATE)"); + stmt.execute("CREATE TABLE Q2 LIKE Q1"); + stmt.execute("CREATE TABLE Q3 LIKE Q1"); + stmt.execute("CREATE TABLE Q4 LIKE Q1"); + + System.out.println( + " ADD CONSTRAINTS TO TABLES Q1, Q2, Q3 AND Q4 BY INVOKING\n" + + " THE STATEMENTS:\n\n" + + " ALTER TABLE Q1 ADD CONSTRAINT Q1_CHK_DATE" + + " CHECK (MONTH(date) IN (1, 2, 3))\n" + + " ALTER TABLE Q2 ADD CONSTRAINT Q2_CHK_DATE" + + " CHECK (MONTH(date) IN (4, 5, 6))\n" + + " ALTER TABLE Q3 ADD CONSTRAINT Q3_CHK_DATE" + + " CHECK (MONTH(date) IN (7, 8, 9))\n" + + " ALTER TABLE Q4 ADD CONSTRAINT Q4_CHK_DATE" + + " CHECK (MONTH(date) IN (10,11,12))\n"); + + // Adds constraints to tables Q1, Q2, Q3 and Q4 + stmt.execute("ALTER TABLE Q1 ADD CONSTRAINT Q1_CHK_DATE " + + "CHECK (MONTH(date) IN (1, 2, 3))"); + stmt.execute("ALTER TABLE Q2 ADD CONSTRAINT Q2_CHK_DATE " + + "CHECK (MONTH(date) IN (4, 5, 6))"); + stmt.execute("ALTER TABLE Q3 ADD CONSTRAINT Q3_CHK_DATE " + + "CHECK (MONTH(date) IN (7, 8, 9))"); + stmt.execute("ALTER TABLE Q4 ADD CONSTRAINT Q4_CHK_DATE " + + "CHECK (MONTH(date) IN (10, 11, 12))"); + + System.out.println( + " CREATE A VIEW 'FY' BY INVOKING THE STATEMENT:\n\n" + + " CREATE VIEW FY AS\n" + + " SELECT product_no, sales, date FROM Q1\n" + + " UNION ALL\n" + + " SELECT product_no, sales, date FROM Q2\n" + + " UNION ALL\n" + + " SELECT product_no, sales, date FROM Q3\n" + + " UNION ALL\n" + + " SELECT product_no, sales, date FROM Q4\n"); + + // Create the view FY, a view over the full year. + stmt.execute("CREATE VIEW FY AS" + + " SELECT product_no, sales, date FROM Q1" + + " UNION ALL" + + " SELECT product_no, sales, date FROM Q2" + + " UNION ALL" + + " SELECT product_no, sales, date FROM Q3" + + " UNION ALL" + + " SELECT product_no, sales, date FROM Q4"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + // This method inserts some values directly into tables Q1, Q2, Q3 and Q4 + public static void InsertInitialValuesInTables(Connection con) + { + try + { + System.out.println( + " INSERT INITIAL VALUES INTO TABLES Q1, Q2, Q3, Q4 BY INVOKING\n" + + " THE STATEMENTS:\n\n" + + " INSERT INTO Q1 VALUES (5, 6, '2001-01-02'),\n" + + " (8, 100, '2001-02-28')\n" + + " INSERT INTO Q2 VALUES (3, 10, '2001-04-11'),\n" + + " (5, 15, '2001-05-19')\n" + + " INSERT INTO Q3 VALUES (1, 12, '2001-08-27')\n" + + " INSERT INTO Q4 VALUES (3, 14, '2001-12-29'),\n" + + " (2, 21, '2001-12-12')"); + + // Insert initial values into tables Q1, Q2, Q3 and Q4 + Statement stmt = con.createStatement(); + stmt.execute("INSERT INTO Q1 VALUES (5, 6, '2001-01-02')," + + " (8, 100, '2001-02-28')"); + stmt.execute("INSERT INTO Q2 VALUES (3, 10, '2001-04-11')," + + " (5, 15, '2001-05-19')"); + stmt.execute("INSERT INTO Q3 VALUES (1, 12, '2001-08-27')"); + stmt.execute("INSERT INTO Q4 VALUES (3, 14, '2001-12-29')," + + " (2, 21, '2001-12-12')"); + + stmt.close(); + + // Display the view FY after inserting values into the tables + DisplayData(con, "SELECT * FROM FY ORDER BY date, product_no"); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + // This method drops tables Q1, Q2, Q3 and Q4 and the view FY + public static void DropTablesAndView(Connection con) + { + try + { + System.out.println( + "\n DROP TABLES Q1,Q2,Q3,Q4 AND VIEW FY BY INVOKING\n" + + " THE STATEMENTS:\n\n" + + " DROP VIEW FY\n" + + " DROP TABLE Q1\n" + + " DROP TABLE Q2\n" + + " DROP TABLE Q3\n" + + " DROP TABLE Q4"); + + Statement stmt = con.createStatement(); + stmt.execute("DROP VIEW FY"); + stmt.execute("DROP TABLE Q1"); + stmt.execute("DROP TABLE Q2"); + stmt.execute("DROP TABLE Q3"); + stmt.execute("DROP TABLE Q4"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + // Helper method: This method displays the results of the query + // specified by 'querystr' + public static void DisplayData(Connection con, String querystr) + { + try + { + Integer prod_num = new Integer(0); + Integer sales_amt = new Integer(0); + String sales_date = new String(); + + System.out.println(); + System.out.println( + " " + querystr + "\n\n" + + " PRODUCT_NO SALES DATE\n" + + " ----------- ----------- ----------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery(querystr); + + while (rs.next()) + { + prod_num = Integer.valueOf(rs.getString(1)); + sales_amt = Integer.valueOf(rs.getString(2)); + sales_date = rs.getString(3); + + System.out.print(" "+Data.format(prod_num, 11) + + " " + Data.format(sales_amt, 11) + + " " + Data.format(sales_date, 10)); + System.out.println(); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + // This method demonstrates how to insert through a UNION ALL view + public static void InsertUsingUnionAll(Connection con) + { + try + { + System.out.println(); + System.out.println( + " ----------------------------------------------------------\n" + + " USE THE SQL STATEMENT:\n\n" + + " INSERT\n\n" + + " TO INSERT DATA THROUGH THE 'UNION ALL' VIEW.\n"); + + System.out.println( + " CONTENTS OF THE VIEW 'FY' BEFORE INSERTING DATA:"); + + // Display the initial content of the view FY before inserting new + // rows + DisplayData(con, "SELECT * FROM FY ORDER BY date, product_no"); + + // INSERT data into tables Q1, Q2, Q3 and Q4 through the + // UNION ALL view FY + System.out.println(); + System.out.println( + " INSERT DATA THROUGH THE 'UNION ALL' VIEW" + + " BY INVOKING THE STATEMENT:\n\n" + + " INSERT INTO FY VALUES (1, 20, '2001-06-03'),\n" + + " (2, 30, '2001-03-21'),\n" + + " (2, 25, '2001-08-30')\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO FY VALUES (1, 20, '2001-06-03')," + + " (2, 30, '2001-03-21')," + + " (2, 25, '2001-08-30')"); + stmt.close(); + + // Display the final content of all tables + System.out.println( + " CONTENTS OF THE TABLES Q1, Q2, Q3, AND Q4 AFTER INSERTING DATA:"); + DisplayData(con, "SELECT * FROM Q1 ORDER BY date, product_no"); + DisplayData(con, "SELECT * FROM Q2 ORDER BY date, product_no"); + DisplayData(con, "SELECT * FROM Q3 ORDER BY date, product_no"); + DisplayData(con, "SELECT * FROM Q4 ORDER BY date, product_no"); + + con.rollback(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + // This method modifies the constraints of table Q1 + public static void NewConstraints(Connection con) + { + try + { + System.out.println(); + Statement stmt = con.createStatement(); + + System.out.println( + " CHANGE THE CONSTRAINTS OF TABLE 'Q1' BY" + + " INVOKING THE STATEMENTS:\n\n" + + " DELETE FROM FY\n" + + " ALTER TABLE Q1 DROP CONSTRAINT Q1_CHK_DATE\n" + + " ALTER TABLE Q1 ADD CONSTRAINT Q1_CHK_DATE" + + " CHECK (MONTH(date) IN (4, 2, 3))"); + + // Drop the constraint Q1_CHK_DATE and add a new one + stmt.execute("DELETE FROM FY"); + stmt.execute("ALTER TABLE Q1 DROP CONSTRAINT Q1_CHK_DATE"); + stmt.execute("ALTER TABLE Q1 ADD CONSTRAINT Q1_CHK_DATE" + + " CHECK (MONTH(date) IN (4, 2, 3))"); + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + + // This method attempts to insert data through a UNION ALL view where no + // table accepts the row + public static void InsertWhenNoTableAcceptsIt(Connection con) + { + try + { + System.out.println(); + System.out.println( + " ----------------------------------------------------------\n" + + " USE THE SQL STATEMENT:\n\n" + + " INSERT\n\n" + + " TO ATTEMPT TO INSERT DATA THROUGH A 'UNION ALL' VIEW WHERE\n" + + " NO TABLE ACCEPTS THE ROW\n"); + + System.out.println( + " NO TABLE ACCEPTS A ROW WITH 'MONTH' = 1." + + " AN ATTEMPT TO INSERT A ROW WITH\n" + + " 'MONTH' = 1, WOULD CAUSE A 'NO TARGET' ERROR TO BE RAISED"); + + Statement stmt = con.createStatement(); + + System.out.println(); + System.out.println( + " ATTEMPT TO INSERT A ROW WITH 'MONTH' = 1" + + " BY INVOKING THE STATEMENT:\n\n" + + " INSERT INTO FY VALUES (5, 35, '2001-01-14')\n"); + + // Attempt to insert a row with 'MONTH' = 1 which no table will accept + stmt.executeUpdate( + "INSERT INTO FY VALUES (5, 35, '2001-01-14')"); + stmt.close(); + + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + } + + // This method attempts to insert data through a UNION ALL view where more + // than one table accepts the row + public static void InsertWhenMoreThanOneTableAcceptsIt(Connection con) + { + try + { + System.out.println(); + System.out.println( + " ----------------------------------------------------------\n" + + " USE THE SQL STATEMENT:\n\n" + + " INSERT\n\n" + + " TO ATTEMPT TO INSERT DATA THROUGH A 'UNION ALL' VIEW WHERE\n" + + " MORE THAN ONE TABLE ACCEPTS THE ROW\n"); + + System.out.println( + " BOTH TABLES Q1 AND Q2 ACCEPT A ROW WITH 'MONTH' = 4." + + " AN ATTEMPT TO\n" + + " INSERT A ROW WITH 'MONTH' = 4, WOULD CAUSE AN 'AMBIGUOUS" + + " TARGET' ERROR\n" + + " TO BE RAISED"); + + Statement stmt = con.createStatement(); + + System.out.println(); + System.out.println( + " ATTEMPT TO INSERT A ROW WITH 'MONTH' = 4" + + " BY INVOKING THE STATEMENT:\n\n" + + " INSERT INTO FY VALUES (3, 30, '2001-04-21')\n"); + + // Attempt to insert a row with 'MONTH' = 4 which is accepted + // by both tables Q1 and Q2 + stmt.executeUpdate( + "INSERT INTO FY VALUES (3, 30, '2001-04-21')"); + stmt.close(); + + con.rollback(); + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + } + + // This function creates a new view. The new view has the WITH ROW + // MIGRATION clause in it, which enables row migration. It performs some + // updates through this view to show how row migration affects the + // underlying tables. + public static void UpdateWithRowMovement(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "\n CREATE A VIEW 'vfullyear' BY INVOKING THE STATEMENT:\n\n" + + " CREATE VIEW vfullyear AS\n" + + " SELECT product_no, sales, date FROM Q1\n" + + " UNION ALL\n" + + " SELECT product_no, sales, date FROM Q2\n" + + " UNION ALL\n" + + " SELECT product_no, sales, date FROM Q3\n" + + " UNION ALL\n" + + " SELECT product_no, sales, date FROM Q4\n" + + " WITH ROW MOVEMENT\n"); + + // Create the view vfullyear, this is the same as view FY with the + // exception that it has the WITH ROW MOVEMENT clause. This additional + // clause allows updates through the view to move rows across the underlying + // tables (row migration) as necessary. + stmt.execute( + "CREATE VIEW vfullyear AS" + + " SELECT product_no, sales, date FROM Q1" + + " UNION ALL" + + " SELECT product_no, sales, date FROM Q2" + + " UNION ALL" + + " SELECT product_no, sales, date FROM Q3" + + " UNION ALL" + + " SELECT product_no, sales, date FROM Q4" + + " WITH ROW MOVEMENT"); + + System.out.println( + " CONTENTS OF THE TABLES Q1 AND Q2 BEFORE ROW MOVEMENT OCCURS"); + DisplayData(con, "SELECT * FROM Q1"); + DisplayData(con, "SELECT * FROM Q2"); + + System.out.println( + "\n UPDATE VALUES IN VIEW vfullyear BY INVOKING\n" + + " THE STATEMENT:\n\n" + + " UPDATE vfullyear SET date = date + 2 MONTHS\n" + + " WHERE date='2001-02-28'"); + + // Demonstrate row movement by executing the following UPDATE statement. + // This statement causes a row to move from table Q1 to table Q2. + stmt.execute( + "UPDATE vfullyear SET date = date + 2 MONTHS" + + " WHERE date='2001-02-28'"); + + System.out.println( + "\n CONTENTS OF THE TABLES Q1 AND Q2 AFTER ROW MOVEMENT OCCURS"); + DisplayData(con, "SELECT * FROM Q1"); + DisplayData(con, "SELECT * FROM Q2"); + + System.out.println( + "\n DROP THE VIEW vfullyear BY INVOKING\n" + + " THE STATEMENT:\n\n" + + " DROP VIEW vfullyear"); + + stmt.execute("DROP VIEW vfullyear"); + + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // UpdateWithRowMovement + + // This function creates three new tables and one new view. It performs some + // updates through the view to show two special cases of row migration. + public static void UpdateWithRowMovementSpecialCase(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "\n CREATE TABLES T1,T2 AND T3 BY INVOKING\n" + + " THE STATEMENTS:\n\n" + + " CREATE TABLE T1(name CHAR, grade INT)\n" + + " CREATE TABLE T2 LIKE T1\n" + + " CREATE TABLE T3 LIKE T1\n"); + + stmt.execute("CREATE TABLE T1(name CHAR, grade INT)"); + stmt.execute("CREATE TABLE T2 LIKE T1"); + stmt.execute("CREATE TABLE T3 LIKE T1"); + + System.out.println( + " INSERT INITIAL VALUES INTO TABLES T1, T2, T3 BY INVOKING\n" + + " THE STATEMENTS:\n\n" + + " INSERT INTO T1 VALUES ('a', 40), ('b', 55)\n" + + " INSERT INTO T2 VALUES ('c', 50), ('d', 75)\n" + + " INSERT INTO T3 VALUES ('d', 90), ('e', 95)"); + + stmt.execute("INSERT INTO T1 VALUES ('a', 40), ('b', 55)"); + stmt.execute("INSERT INTO T2 VALUES ('c', 50), ('d', 75)"); + stmt.execute("INSERT INTO T3 VALUES ('d', 90), ('e', 95)"); + + System.out.println( + "\n ADD CONSTRAINTS TO TABLES T1, T2 AND T3 BY INVOKING\n" + + " THE STATEMENTS:\n\n" + + " ALTER TABLE T1 ADD CONSTRAINT T1_CHK_GRADE\n" + + " CHECK (grade >= 0 AND grade <= 55)\n" + + " ALTER TABLE T2 ADD CONSTRAINT T2_CHK_GRADE\n" + + " CHECK (grade >= 50 AND grade <= 100)\n" + + " ALTER TABLE T3 ADD CONSTRAINT T3_CHK_GRADE\n" + + " CHECK (grade >= 90 AND grade <= 100)\n"); + + stmt.execute( + "ALTER TABLE T1 ADD CONSTRAINT T1_CHK_GRADE" + + " CHECK (grade >= 0 AND grade <= 55)"); + + stmt.execute( + "ALTER TABLE T2 ADD CONSTRAINT T2_CHK_GRADE" + + " CHECK (grade >= 50 AND grade <= 100)"); + + stmt.execute( + "ALTER TABLE T3 ADD CONSTRAINT T3_CHK_GRADE" + + " CHECK (grade >= 90 AND grade <= 100)"); + + } + catch(Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + try + { + Statement stmt = con.createStatement(); + + System.out.println( + " CREATE A VIEW 'vmarks' BY INVOKING THE STATEMENT:\n\n" + + " CREATE VIEW vmarks AS\n" + + " SELECT name, grade FROM T1\n" + + " UNION ALL\n" + + " SELECT name, grade FROM T2\n" + + " UNION ALL\n" + + " SELECT name, grade FROM T3\n" + + " WITH ROW MOVEMENT\n"); + + stmt.execute( + "CREATE VIEW vmarks AS" + + " SELECT name, grade FROM T1" + + " UNION ALL" + + " SELECT name, grade FROM T2" + + " UNION ALL" + + " SELECT name, grade FROM T3" + + " WITH ROW MOVEMENT"); + + System.out.println( + " ATTEMPT TO UPDATE THE ROW WITH grade = 50" + + " BY INVOKING THE STATEMENT:\n\n" + + " UPDATE vmarks SET GRADE = 60 WHERE GRADE = 50"); + + // Attempt to update the row where grade = 50, which satisfies constraints + // for both tables T2 and T3. In this case no error is raised as row + // migration doesn't apply. The row does not need to be moved because it + // satisfies all constraints of the table it is already in. + stmt.execute( + "UPDATE vmarks SET grade = 60" + + " WHERE grade = 50"); + + System.out.println( + "\n ATTEMPT TO UPDATE THE ROW WITH grade = 90" + + " BY INVOKING THE STATEMENT:\n\n" + + " UPDATE vmarks SET GRADE = 50 WHERE GRADE = 90"); + + // Attempt to update the row where grade = 90, which satisfies constraints + // for both tables T1 and T2. An error is raised since this update is + // ambiguous. A similar error is raised on an ambiguous insert statement. + stmt.execute( + "UPDATE vmarks SET grade = 50" + + " WHERE grade = 90"); + } + catch(Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handleExpectedErr(); + } + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "\n DROP TABLES T1,T2,T3 AND VIEW vmarks BY INVOKING\n" + + " THE STATEMENTS:\n\n" + + " DROP VIEW vmarks\n" + + " DROP TABLE T1\n" + + " DROP TABLE T2\n" + + " DROP TABLE T3"); + + stmt.execute("DROP VIEW vmarks"); + stmt.execute("DROP TABLE T1"); + stmt.execute("DROP TABLE T2"); + stmt.execute("DROP TABLE T3"); + + stmt.close(); + con.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // UpdateWithRowMovementSpecialCase +} // TbUnion + diff --git a/java/jdbc/Temporal.java b/java/jdbc/Temporal.java new file mode 100644 index 0000000..ac9cf18 --- /dev/null +++ b/java/jdbc/Temporal.java @@ -0,0 +1,655 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2011 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Temporal.java +// +// SAMPLE: How to create a temporal table and perform insert, +// update and select data using parameter marker. +// Scenario : +// 1) Customer takes loan from bank. The details of the loan like account number, +// loan type, rate of interest, loan period and balance are stored in a table. +// 2) The rate of interest will be updated and is applicable +// for future loan payments. The rate of interest for the previous date +// should be maintainned. +// 3) The history of these inserts and updates should be maintainned +// with the time of these changes. +// 4) When querying the data for reports the data should be fetched +// for a particular period of time. +// 5) The result of the query should exactly match the loan details for +// that particular point of time as it happened in history. +// +// Solution : +// 1) This Solution creates a loan_accounts_btt BI-Temporal +// table and loan_accounts_history_btt. +// 2) Inserts the loan details of customers in loan_accounts_btt +// and the history in loan_accounts_history_btt. +// 3) The period for which the loan is taken becomes the temporal +// BUSINESS_TIME having begin and end dates. +// 4) The period at which the actual changes happen for the data +// in the table is maintainnned by SYSTEM_TIME sysbegin and sysend TIMESTAMPs. +// 5) The query will fetch data for different BUSINESS_TIME and SYSTEM_TIME. +// 6) The CURRENT TEMPORAL SYSTEM_TIME and CURRENT TEMPORAL +// BUSINNESS_TIME special register +// sets the temporal table for the specified period mentionned by the +// register and any query without predicates will return data +// for that particular period. +// 7) Temporal table thus helps to set automatic history maintanance by capturing +// each and every change to rows in the master with its corresponding +// history table using SYSTEM_TIME and BUSINESS_TIME +// and helps while generating reports. +// +// SQL Statements USED: +// CREATE TABLE +// ALTER TABLE +// INSERT +// SELECT +// UPDATE +// SET +// DROP TABLE +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac Temporal.java +// +// Run: java Temporal +// or +// java Temporal +// +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import java.util.*; +import java.lang.*; + +public class Temporal +{ + + //Creates Temporal tables and inserts data + public void AddTemporal(Connection conn) + { + System.out.println("THIS SAMPLE DEMONSTRATES THE TEMPORAL TABLE FEATURE."); + System.out.println("***************************************************"); + try + { + System.out.println("Creating a Bi-Temporal Table"); + System.out.println(); + System.out.println( + "CREATE TABLE loan_accounts_btt ( \n" + + " account_number INTEGER NOT NULL, \n" + + " loan_type VARCHAR(10), \n" + + " rate_of_interest DECIMAL(5,2) NOT NULL,\n" + + " balance DECIMAL (10,2), \n" + + " bus_begin DATE NOT NULL, \n" + + " bus_end DATE NOT NULL, \n" + + " system_begin TIMESTAMP(12) \n" + + " NOT NULL IMPLICITLY HIDDEN, \n" + + " system_end TIMESTAMP(12) \n" + + " NOT NULL IMPLICITLY HIDDEN, \n" + + " PERIOD BUSINESS_TIME(bus_begin, bus_end) \n" + + " ) ;\n\n" ); + + Statement stmt1 = conn.createStatement(); + stmt1.executeUpdate( + "CREATE TABLE loan_accounts_btt( " + + " account_number INTEGER NOT NULL, " + + " loan_type VARCHAR(10)," + + " rate_of_interest DECIMAL(5,2) NOT NULL, " + + " balance DECIMAL (10,2), " + + " bus_begin DATE NOT NULL, " + + " bus_end DATE NOT NULL, " + + " system_begin TIMESTAMP(12) " + + " NOT NULL IMPLICITLY HIDDEN, " + + " system_end TIMESTAMP(12) " + + " NOT NULL IMPLICITLY HIDDEN, " + + " PERIOD BUSINESS_TIME(bus_begin, bus_end)) "); + stmt1.close(); + + System.out.println("Creating a UNIQUE index " + + " with account_number and BUSINESS_TIME"); + + System.out.println( + "CREATE UNIQUE INDEX ix_loan_accounts \n" + + " ON loan_accounts_btt (account_number, BUSINESS_TIME WITHOUT OVERLAPS);\n"); + + Statement stmt2 = conn.createStatement(); + stmt2.executeUpdate( + "CREATE UNIQUE INDEX ix_loan_accounts " + + " ON loan_accounts_btt (account_number, BUSINESS_TIME WITHOUT OVERLAPS) " ); + stmt2.close(); + + // Creating history table which maintains + //history as the master table is modified + System.out.println("Creating a history table " + + " for the loan_accounts_btt table."); + System.out.println( + "CREATE TABLE loan_accounts_btt_history \n" + + " LIKE loan_accounts_btt \n" ); + + Statement stmt3 = conn.createStatement(); + stmt3.executeUpdate( + "CREATE TABLE loan_accounts_btt_history " + + " LIKE loan_accounts_btt " ); + stmt3.close(); + + System.out.println("INSERT data into the loan_accounts_btt " + + " and loan_accounts_btt_history table"); + + System.out.println("INSERT INTO loan_accounts_btt (account_number, " + + "loan_type,rate_of_interest, balance, system_begin, \n" + + " system_end, bus_begin, bus_end) \n" + + " VALUES (2111, 'A21', 9.5, 559500, '2010-02-01-05.45.02', " + + " '9999-12-31-00.00.00', '2009-11-01', '2013-11-01'), \n" + + " (2112, 'A10', 12, 450320, '2010-02-02-03.21.18', " + + " '9999-12-31-00.00.00', '2010-01-02', '2013-02-02'), \n" + + " (2113, 'A21', 9, 100000, '2010-02-06-13.15.06', " + + " '9999-12-31-00.00.00', '2010-02-06', '2010-12-30'), \n" + + " (2114, 'A15', 10, 200000, '2010-02-07-22.20.15', " + + " '9999-12-31-00.00.00', '2010-02-07', '2011-08-31') \n" ); + + System.out.println(); + Statement stmt4 = conn.createStatement(); + stmt4.executeUpdate( + "INSERT INTO loan_accounts_btt (account_number,loan_type,rate_of_interest, " + + " balance, system_begin, system_end, bus_begin, bus_end) " + + " VALUES (2111, 'A21', 9.5, 559500, '2010-02-01-05.45.02', " + + " '9999-12-31-00.00.00', '2009-11-01', '2013-11-01'), " + + " (2112, 'A10', 12, 450320, '2010-02-02-03.21.18', " + + " '9999-12-31-00.00.00', '2010-01-02', '2013-02-02'), " + + " (2113, 'A21', 9, 100000, '2010-02-06-13.15.06', " + + " '9999-12-31-00.00.00', '2010-02-06', '2010-12-30'), " + + " (2114, 'A15', 10, 200000, '2010-02-07-22.20.15', " + + " '9999-12-31-00.00.00', '2010-02-07', '2011-08-31')" ); + stmt4.close(); + + + System.out.println(); + + System.out.println( + "INSERT INTO loan_accounts_btt_history (account_number, " + + " loan_type, rate_of_interest, balance, \n" + + " system_begin, system_end, bus_begin, bus_end) \n " + + " VALUES (2111, 'A21', 8, 669000, '2009-09-01-23.45.01', " + + " '2009-10-01-14.33.08', '2009-08-01', '2013-11-01'), \n" + + " (2111, 'A21', 8, 648000, '2009-10-01-14.33.08', " + + " '2009-11-01-09.56.17', '2009-08-01', '2013-11-01'), \n" + + " (2111, 'A21', 9.5, 625875, '2009-11-01-09.56.17', " + + " '2009-12-01-07.03.18', '2009-11-01', '2013-11-01'), \n" + + " (2111, 'A21', 9.5, 603750, '2009-12-01-07.03.18', " + + " '2010-01-01-00.00.00', '2009-11-01', '2013-11-01'), \n" + + " (2111, 'A21', 9.5, 581625, '2010-01-01-00.00.00', " + + " '2010-02-01-05.45.02', '2009-11-01', '2013-11-01'), \n" + + " (2112, 'A10', 12, 468000, '2010-01-02-09.04.16', " + + " '2010-02-02-03.21.18', '2010-01-02', '2013-02-02') \n" + ); + + Statement stmt11 = conn.createStatement(); + stmt11.executeUpdate( + "INSERT INTO loan_accounts_btt_history (account_number, loan_type, " + + " rate_of_interest, balance,system_begin, system_end, bus_begin, bus_end) " + + " VALUES (2111, 'A21', 8, 669000, '2009-09-01-23.45.01', " + + " '2009-10-01-14.33.08', '2009-08-01', '2013-11-01'), " + + " (2111, 'A21', 8, 648000, '2009-10-01-14.33.08', " + + " '2009-11-01-09.56.17', '2009-08-01', '2013-11-01'), " + + " (2111, 'A21', 9.5, 625875, '2009-11-01-09.56.17', " + + " '2009-12-01-07.03.18', '2009-11-01', '2013-11-01'), " + + " (2111, 'A21', 9.5, 603750, '2009-12-01-07.03.18', " + + " '2010-01-01-00.00.00', '2009-11-01', '2013-11-01'), " + + " (2111, 'A21', 9.5, 581625, '2010-01-01-00.00.00', " + + " '2010-02-01-05.45.02', '2009-11-01', '2013-11-01'), " + + " (2112, 'A10', 12, 468000, '2010-01-02-09.04.16', " + + " '2010-02-02-03.21.18', '2010-01-02', '2013-02-02') " ); + + stmt4.close(); + + System.out.println(); + System.out.println("Adding SYSTEM_TIME columns to loan_accounts_btt"); + System.out.println("ALTER TABLE loan_accounts_btt \n" + + " ALTER COLUMN system_begin SET GENERATED AS ROW BEGIN \n" ); + + Statement stmt5 = conn.createStatement(); + stmt5.executeUpdate("ALTER TABLE loan_accounts_btt " + + "ALTER COLUMN system_begin SET GENERATED AS ROW BEGIN " ); + stmt5.close(); + + System.out.println(); + + System.out.println("ALTER TABLE loan_accounts_btt \n" + + "ALTER COLUMN system_end SET GENERATED AS ROW END \n" ); + + Statement stmt6 = conn.createStatement(); + stmt6.executeUpdate("ALTER TABLE loan_accounts_btt " + + "ALTER COLUMN system_end SET GENERATED AS ROW END " ); + stmt6.close(); + + System.out.println("ALTER loan_accounts_btt " + + " to include SYSTEM_TIME columns."); + + System.out.println("ALTER TABLE loan_accounts_btt \n" + + "ADD PERIOD SYSTEM_TIME (system_begin, system_end); \n" ); + + Statement stmt7 = conn.createStatement(); + stmt7.executeUpdate("ALTER TABLE loan_accounts_btt " + + "ADD PERIOD SYSTEM_TIME (system_begin, system_end) " ); + stmt7.close(); + + System.out.println("ALTER table loan_accounts_btt " + + " to add column trans_start"); + + System.out.println("ALTER TABLE loan_accounts_btt " + + " ADD COLUMN trans_start TIMESTAMP(12) \n" + + " GENERATED AS TRANSACTION START ID IMPLICITLY HIDDEN; \n" ); + + Statement stmt8 = conn.createStatement(); + stmt8.executeUpdate("ALTER TABLE loan_accounts_btt " + + " ADD COLUMN trans_start TIMESTAMP(12) " + + " GENERATED AS TRANSACTION START ID IMPLICITLY HIDDEN " ); + stmt8.close(); + + System.out.println("ALTER table loan_accounts_btt_history " + + " to add column trans_start"); + + System.out.println("ALTER TABLE loan_accounts_btt_history \n " + + "ADD COLUMN trans_start TIMESTAMP(12) IMPLICITLY HIDDEN; \n" ); + + Statement stmt9 = conn.createStatement(); + stmt9.executeUpdate("ALTER TABLE loan_accounts_btt_history " + + "ADD COLUMN trans_start TIMESTAMP(12) IMPLICITLY HIDDEN " ); + stmt9.close(); + + System.out.println("ALTER table loan_accounts_btt " + + " to add VERSIONING using loan_accounts_btt_history."); + + System.out.println("ALTER TABLE loan_accounts_btt \n" + + "ADD VERSIONING USE HISTORY TABLE loan_accounts_btt_history \n" ); + + Statement stmt10 = conn.createStatement(); + stmt10.executeUpdate("ALTER TABLE loan_accounts_btt " + + "ADD VERSIONING USE HISTORY TABLE loan_accounts_btt_history " ); + stmt10.close(); + + System.out.println("Set up done!!!!!"); + System.out.println(); + } + catch(Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + + } + //Query Temporal tables for specified temporal SYSTEM_TIME and BUSINESS_TIME + public void FetchTemporal(Connection conn,ResultSet rs) + { + try + { + //******************************************************************** + System.out.println(); + System.out.println("Query FOR BUSINESS_TIME AS OF " + + " 2011-12-01 using parameter marker"); + System.out.println(); + System.out.println("***********************************" + + "*************************************"); + System.out.println( + "SELECT account_number,loan_type, rate_of_interest, bus_begin, " + + " bus_end, system_begin, system_end \n" + + " FROM loan_accounts_btt \n" + + " FOR BUSINESS_TIME AS OF ? " ); + System.out.println("*****************************" + + "*******************************************"); + System.out.println(); + + PreparedStatement pstmnt1 = conn.prepareStatement( + "SELECT account_number,loan_type, rate_of_interest," + + " bus_begin, bus_end, system_begin, system_end " + + " FROM loan_accounts_btt " + + " FOR BUSINESS_TIME AS OF ?" ) ; + + pstmnt1.setString(1, "2011-12-01"); + // execute the statement + rs = pstmnt1.executeQuery(); + displayTemporal(conn,rs); + pstmnt1.close(); + + //************************************************************************* + System.out.println(); + System.out.println("Query FOR BUSINESS_TIME AS OF 2009-12-01 and " + + "SYSTEM_TIME AS OF 2009-10-01 using parameter marker"); + System.out.println(); + System.out.println("*******************************************" + + "*****************************"); + System.out.println( + "SELECT account_number,loan_type, rate_of_interest, bus_begin, " + + " bus_end, system_begin, system_end \n" + + " FROM loan_accounts_btt \n" + + " FOR BUSINESS_TIME AS OF ? \n" + + " FOR SYSTEM_TIME AS OF ? \n" ); + System.out.println("**************************************" + + "**********************************"); + System.out.println(); + + pstmnt1 = conn.prepareStatement( + "SELECT account_number,loan_type, rate_of_interest, bus_begin, " + + " bus_end, system_begin, system_end " + + " FROM loan_accounts_btt " + + " FOR BUSINESS_TIME AS OF ? " + + " FOR SYSTEM_TIME AS OF CAST(? AS TIMESTAMP)" ) ; + + pstmnt1.setString(1, "2009-12-01"); + pstmnt1.setString(2, "2009-10-01"); + + // execute the statement + + rs = pstmnt1.executeQuery(); + displayTemporal(conn,rs); + pstmnt1.close(); + + //*********************************************************************** + System.out.println(); + System.out.println("Query FOR SYSTEM_TIME FROM 0001-01-01 " + + " TO 9999-12-31 using parameter marker"); + System.out.println(); + System.out.println("**************************************" + + "**********************************"); + System.out.println( + "SELECT account_number,loan_type, rate_of_interest, system_begin, " + + " system_end, bus_begin, bus_end \n" + + " FROM loan_accounts_btt \n" + + " FOR SYSTEM_TIME FROM ? TO ? \n" + + " WHERE account_number = ? \n" ); + System.out.println("***********************************" + + "*************************************"); + System.out.println(); + + pstmnt1 = conn.prepareStatement( + "SELECT account_number,loan_type, rate_of_interest, " + + " system_begin, system_end, bus_begin, bus_end " + + " FROM loan_accounts_btt " + + " FOR SYSTEM_TIME FROM CAST(? AS TIMESTAMP) TO CAST(? AS TIMESTAMP) " + + " WHERE account_number = ?" ) ; + + pstmnt1.setString(1, "0001-01-01"); + pstmnt1.setString(2, "9999-12-31"); + pstmnt1.setString(3, "2111"); + // execute the statement + + rs = pstmnt1.executeQuery(); + displayTemporal(conn,rs); + pstmnt1.close(); + + //**************************************************************** + System.out.println(); + System.out.println("Query FOR BUSINESS_TIME BETWEEN 2009-06-01 " + + "TO 2010-01-02 using parameter marker"); + System.out.println(); + System.out.println("*******************************************" + + "*****************************"); + System.out.println( + "SELECT account_number,loan_type, rate_of_interest, system_begin, " + + " system_end, bus_begin, bus_end \n" + + " FROM loan_accounts_btt \n" + + " FOR BUSINESS_TIME BETWEEN ? AND ? \n" ); + System.out.println("**********************************" + + "**************************************"); + System.out.println(); + + pstmnt1 = conn.prepareStatement( + "SELECT account_number,loan_type, rate_of_interest, system_begin, " + + " system_end, bus_begin, bus_end " + + " FROM loan_accounts_btt " + + " FOR BUSINESS_TIME BETWEEN ? AND ? " ) ; + + pstmnt1.setString(1, "2009-06-01"); + pstmnt1.setString(2, "2010-01-02"); + // execute the statement + + rs = pstmnt1.executeQuery(); + displayTemporal(conn,rs); + pstmnt1.close(); + + //*********************************************************************** + System.out.println(); + System.out.println("Update FOR PORTION OF BUSINESS_TIME FROM " + + "2010-03-01 TO 2010-09-01 using parameter marker"); + System.out.println(); + System.out.println("**************************************" + + "**********************************"); + System.out.println( + "UPDATE loan_accounts_btt \n" + + " FOR PORTION OF BUSINESS_TIME FROM ? TO ? \n" + + " SET rate_of_interest = ? \n" + + " WHERE account_number = ? \n" ); + System.out.println("*********************************" + + "***************************************"); + System.out.println(); + + pstmnt1 = conn.prepareStatement( + "UPDATE loan_accounts_btt " + + " FOR PORTION OF BUSINESS_TIME FROM ? TO ? " + + " SET rate_of_interest = ? " + + " WHERE account_number = ? " ) ; + + pstmnt1.setString(1, "2010-03-01"); + pstmnt1.setString(2, "2010-09-01"); + pstmnt1.setString(3, "10"); + pstmnt1.setString(4, "2111"); + // execute the statement + + pstmnt1.executeUpdate(); + System.out.println("Update Done Successfully"); + pstmnt1.close(); + + + //*********************************************************************** + System.out.println(); + System.out.println("SET Special register CURRENT TEMPORAL BUSINESS_TIME"); + System.out.println(); + System.out.println("***********************************" + + "*************************************"); + System.out.println( "SET CURRENT TEMPORAL BUSINESS_TIME = '2011-01-01' \n" ); + System.out.println("*********************************" + + "***************************************"); + System.out.println(); + + pstmnt1 = conn.prepareStatement("SET CURRENT TEMPORAL BUSINESS_TIME = ? ") ; + + pstmnt1.setString(1, "2011-01-01"); + + // execute the statement + + pstmnt1.execute(); + System.out.println("Special register set Successfully"); + pstmnt1.close(); + + //*********************************************************************** + System.out.println(); + System.out.println("SET Special register CURRENT TEMPORAL SYSTEM_TIME"); + System.out.println(); + System.out.println("*************************************" + + "***********************************"); + System.out.println( "SET CURRENT TEMPORAL SYSTEM_TIME = '2010-10-01' \n" ); + System.out.println("************************************" + + "************************************"); + System.out.println(); + + pstmnt1 = conn.prepareStatement("SET CURRENT TEMPORAL SYSTEM_TIME = ? ") ; + + pstmnt1.setString(1, "2010-10-01"); + + // execute the statement + pstmnt1.execute(); + System.out.println("Special register set Successfully"); + pstmnt1.close(); + + + //*********************************************************************** + System.out.println(); + System.out.println("Query loan_accounts_btt table " + + " after setting the Special register"); + System.out.println(); + System.out.println("*************************************" + + "***********************************"); + System.out.println( + "SELECT account_number,loan_type, rate_of_interest, " + + " bus_begin, bus_end, system_begin, system_end \n" + + " FROM loan_accounts_btt \n" ); + System.out.println("****************************" + + "********************************************"); + System.out.println(); + + pstmnt1 = conn.prepareStatement( + "SELECT account_number,loan_type, rate_of_interest, " + + " bus_begin, bus_end, system_begin, system_end " + + " FROM loan_accounts_btt " ) ; + + // execute the statement + + rs = pstmnt1.executeQuery(); + displayTemporal(conn,rs); + pstmnt1.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } + //Generate Resultsets for the query specified + public void displayTemporal(Connection conn,ResultSet rs) + { + try + { + int acc_num; + String loan_typ; + double roi; + String bus_beg; + String bus_end; + String sys_beg; + String sys_end; + System.out.println("----------------------------------------------------------" + + "---------------------------------------------------------------------------" + + "-------------"); + System.out.println( + "Acc # Loan Type Rate of Interest bus_begin " + + " bus_end " + + " system_begin system_end\n" + + "------ --------- ---------------- ---------------- " + + " --------------- ------------------------ " + + "-------------------------"); + + while (rs.next()) + { + acc_num = rs.getInt(1); + loan_typ = rs.getString(2); + roi = rs.getDouble(3); + bus_beg = rs.getString(4); + bus_end = rs.getString(5); + sys_beg = rs.getString(6); + sys_end = rs.getString(7); + + System.out.println( + Data.format(acc_num, 5) + " " + + Data.format(loan_typ, 10) + " " + + Data.format(String.valueOf(roi), 20) + " " + + Data.format(bus_beg, 30) + " " + + Data.format(bus_end, 30) + " " + + Data.format(sys_beg, 30) + " " + + Data.format(sys_end, 30)); + } + rs.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + + } + //Drop the Database connection created + static void Drop(Connection conn) + { + try + { + System.out.println(); + System.out.println("DROP TABLE loan_accounts_btt\n"); + Statement stmt = conn.createStatement(); + stmt.executeUpdate("DROP TABLE loan_accounts_btt"); + stmt.close(); + + // Commit + conn.commit(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, conn); + jdbcExc.handle(); + } + } + public static void main(String args[]) + { + + Temporal temp = new Temporal(); + try + { + // Obtain a Connection to the 'sample' database + Db db = null; + ResultSet rs = null; + Connection conn = null ; + db = new Db(args); + db.connect(); + conn = db.con; + + temp.AddTemporal(conn); + temp.FetchTemporal(conn,rs); + temp.Drop(conn); + conn.close(); + } + catch(ClassNotFoundException cle) + { + System.out.println(" Driver class not found, please check the PATH" + + " and CLASSPATH system variables to ensure they are correct"); + } + catch(SQLException sqle) + { + System.out.println(" Could not open connection"); + sqle.printStackTrace(); + } + catch(Exception ne) + { + System.out.println(" Unexpected Error"); + ne.printStackTrace(); + } + System.out.println("Disconnect from 'sample' database."); + System.out.println("Exiting..............."); + } + +} + diff --git a/java/jdbc/TrustedContext.java b/java/jdbc/TrustedContext.java new file mode 100644 index 0000000..24d04a4 --- /dev/null +++ b/java/jdbc/TrustedContext.java @@ -0,0 +1,755 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: TrustedContext.java +// +// PURPOSE: To demonstrate +// 1. Creating a trusted Context object. +// 2. How to establish explicit trusted connection. +// 3. Authorizing switching of the user on a trusted connection. +// 4. Acquiring trusted context-specific privileges through Role inheritance. +// 5. Altering a trusted context object. +// 6. Dropping a trusted context object. +// +// PREREQUISITES: +// 1. a) Database "testdb" must exist. +// Create the database using command given below: +// db2 "CREATE DATABASE testdb" +// b) Update the configuration parameter SVCENAME. +// db2 "update dbm cfg using svcename " +// c) Set communication protocol to TCP/IP. +// db2set DB2COMM=TCPIP +// d) Stop and start the DB2 instance. +// db2 terminate; +// db2stop; +// db2start; +// 2. Following users with corresponding passwords must exist +// a) A user with SECADM authority on database. +// padma with "padma123" +// Grant SECADM authority to user "padma" commands given below: +// db2 "CONNECT TO testdb" +// db2 "GRANT SECADM ON DATABASE TO USER padma" +// db2 "CONNECT RESET" +// b) A valid system authorization ID and passord. +// bob with "bob123" +// c) Normal Users without SYSADM and DBADM authorities. +// joe with "joe123" +// pat with "pat123" +// mat with "mat123" +// +// EXECUTION: i) javac TrustedContext.java (compile the sample) +// ii) java TrustedContext +// eg: java TrustedContext db2aix.ibm.com 30308 padma padma123 +// userid and password that are passed must have the SECADM authority. +// +// INPUTS: NONE +// +// OUTPUTS: Successful establishment of trusted connection and switch user. +// +// OUTPUT FILE: TrustedContext.out (available in the online documentation) +// +// SQL Statements USED: +// CREATE TRUSTED CONTEXT +// ALTER TRUSTED CONTEXT +// GRANT +// CREATE TABLE +// CREATE ROLE +// INSERT +// UPDATE +// DROP ROLE +// DROP TRUSTED CONTEXT +// DROP TABLE +// +// JAVA CLASSES USED: +// Statement +// ResultSet +// Connection +// DB2ConnectionPoolDataSource +// DB2PooledConnection +// Properties +// +// ************************************************************************* +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +// *************************************************************************/ +// +// SAMPLE DESCRIPTION +// +// /************************************************************************* +// 1. Connect to database and create the trusted context object. +// 2. Establish the explicit trusted connection and grant privileges to the roles. +// 3. Switch the current user on the connection to a different user +// with and without authentication. +// 4. Switch the current user on the connection to an invalid user. +// 5. Alter the trusted context object after disabling it. +// 6. Drop the objects created for trusted context and roles. +// *************************************************************************/ + +// import the required classes +import java.util.*; +import java.sql.*; +import java.io.*; +import java.net.InetAddress; +import com.ibm.db2.jcc.*; +import com.ibm.db2.jcc.DB2Connection; +import com.ibm.db2.jcc.DB2ConnectionPoolDataSource; + +class TrustedContext +{ + public static void main (String[] args) + { + try { + // Users and Passwords + String authid = new String("bob"); + String authid_pwd = new String("bob123"); + String user1 = new String("joe"); + String user1_pwd = new String("joe123"); + String user2 = new String("pat"); + String user2_pwd = new String("pat123"); + String user3 = new String("mat"); + String user3_pwd = new String("mat123"); + + + // get the command line arguments + String serverName = args[0]; + String portNumber = args[1]; + String userid = args[2]; + String password = args[3]; + + // Local variables and classes + String ctname = new String("CTX1"); + String databaseName = new String("testdb"); + Connection con = null; + Statement stmt; + ResultSet rs=null; + String url,newUser,newPassword; + String sqlid = " "; + Object[] objects = new Object[6]; + byte[] cookie = new byte[1]; + com.ibm.db2.jcc.DB2ConnectionPoolDataSource ds1 = + new com.ibm.db2.jcc.DB2ConnectionPoolDataSource(); + java.util.Properties properties = new java.util.Properties(); + com.ibm.db2.jcc.DB2PooledConnection pooledCon = + (com.ibm.db2.jcc.DB2PooledConnection)objects[0]; + + // load the driver + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + url = "jdbc:db2://"+serverName+":"+portNumber+"/testdb"; + + System.out.println("\n This sample will demonstrate " + + "\n\t 1. Creating a trusted Context object. " + + "\n\t 2. How to establish explicit trusted connection. " + + "\n\t 3. Authorizing the switching of the user on a trusted connection. " + + "\n\t 4. Acquiring trusted context-specific privileges through Role inheritance. " + + "\n\t 5. Altering a trusted context object. " + + "\n\t 6. Dropping a trusted context object. "); + System.out.println("\n"); + + // connect to the database + try { + con = DriverManager.getConnection(url,userid,password ); + System.out.println(userid + " connected to the database"); + con.setAutoCommit(true); + } + catch(Exception ex) + { + System.out.println(" Connect to database failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // Create roles + try { + stmt = con.createStatement(); + stmt.execute("CREATE ROLE def_role"); + System.out.println("\n Role def_role created "); + stmt.execute("CREATE ROLE tc_role"); + System.out.println("\n Role tc_role created "); + stmt.execute("grant role def_role to user "+user1); + stmt.execute("grant role tc_role to user "+user2); + stmt.close(); + } + catch(Exception ex) + { + System.out.println(" Role creation failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // Create the trusted context object with + // system authorization id as authid + // for IP domain name containing serverName + // with no default role + // users as user1 with authentication and + // user2 having tc_role privileges and without authentication + try { + stmt = con.createStatement(); + String sql = "CREATE TRUSTED CONTEXT " + ctname + + " BASED UPON CONNECTION USING SYSTEM AUTHID " + authid + + " ATTRIBUTES ( ADDRESS '" + serverName + "') " + + " DEFAULT ROLE def_role" + + " ENABLE " + + " WITH USE FOR " + user1 + " WITH AUTHENTICATION, " + + user2 + " ROLE tc_role WITHOUT AUTHENTICATION"; + stmt.execute(sql); + System.out.println(); + System.out.println(sql); + System.out.println(" Trusted context object "+ ctname +" Created" ); + stmt.close(); + } + catch(Exception ex) + { + System.out.println(" Trusted context object " + ctname + " creation failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // Add a comment to the Trusted context object + try + { + stmt = con.createStatement(); + stmt.execute("COMMENT ON TRUSTED CONTEXT ctx1 IS 'Trusted Context object used to establish explicit trusted connection!'"); + con.commit(); + stmt.close(); + } + catch(Exception ex) + { + System.out.println(" Adding a comment to the Trusted context object failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + try + { + String remarks = ""; + + System.out.println(); + System.out.println("SELECT remarks FROM SYSIBM.SYSCOMMENTS"); + System.out.println( + " COMMENT ON TRUSTED CONTEXT\n" + + " -----------------------------\n"); + + stmt = con.createStatement(); + // perform a SELECT + rs = stmt.executeQuery("SELECT remarks FROM SYSIBM.SYSCOMMENTS"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + remarks = rs.getString(1); + System.out.println( " " + remarks); + } + rs.close(); + stmt.close(); + } + catch(Exception ex) + { + System.out.println(" Trusted context object comment not created"); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // close the connection + con.close(); + + // establish explicit trusted connection and switch user id to a different user + + /************************************************** + * Create datasource for connection to database. + **************************************************/ + + try + { + ds1.setServerName(serverName); + ds1.setPortNumber(Integer.valueOf(portNumber).intValue()); + ds1.setDatabaseName(databaseName); + ds1.setDriverType (4); + } + catch(Exception ex) + { + System.out.println(" Datasource creation failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + /************************************ + * Establish the explicit trusted connection + *************************************/ + + try + { + System.out.println("\n Establish explicit trusted connection using "+ authid +"..."); + objects = ds1.getDB2TrustedPooledConnection(authid, authid_pwd, properties); + pooledCon = (com.ibm.db2.jcc.DB2PooledConnection)objects[0]; + System.out.println(" Established explicit trusted connection for "+ authid ); + cookie = (byte[])objects[1]; + newUser = null; + newPassword = null; + rs = null; + sqlid = null; + stmt = null; + } + catch(Exception ex) + { + System.out.println(" Failed to establish trusted connection for " + authid ); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + /************************************************************** + * Connect as authid to check explicit trusted connection worked or not + * authid is the system authorization ID defined for the trusted context + ***************************************************************/ + newUser = authid; + newPassword = authid_pwd; + + try + { + System.out.println("\n Get connection as "+ newUser +" ..."); + con = pooledCon.getDB2Connection(cookie, newUser, newPassword, + null, null, null, properties); + + stmt = con.createStatement(); + System.out.println("\t Check who is currently connected to database, should be "+ newUser +" ..."); + rs = stmt.executeQuery("values SYSTEM_USER"); + rs.next(); + sqlid = rs.getString(1); + System.out.println("\tCurrent user connected to database = " + sqlid); + if((sqlid.trim()).equalsIgnoreCase(newUser.trim())) + { + System.out.println(" Connected as "+newUser); + System.out.println(" Trusted connection worked "); + } + else + { + System.out.println(" Trusted connection failed "); + } + } + catch(Exception ex) + { + System.out.println(" Trusted connection for "+ newUser +" failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // Create a table and populate the table + Statement stmt1 = con.createStatement(); + try + { + stmt1.executeUpdate("CREATE TABLE test.tc_emp_table (emp_no INT, emp_name VARCHAR (20), emp_sal DECIMAL)"); + stmt1 = con.createStatement(); + stmt1.executeUpdate("INSERT INTO test.tc_emp_table VALUES(100, 'Padma Kota', 30000)"); + stmt1.executeUpdate("INSERT INTO test.tc_emp_table VALUES(200, 'Kathy Smith',20000)"); + System.out.println("\n Created and Inserted data into table test.tc_emp_table using " + sqlid ); + } + catch(Exception ex) + { + System.out.println("\n Failed to create table test.tc_emp_table and populate it"); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // Grant privileges to the roles. + try + { + // Grant SELECT privilege on this table to the role def_role + stmt1.execute("GRANT SELECT ON TABLE test.tc_emp_table TO ROLE def_role"); + System.out.println(" Granted SELECT privilege on table test.tc_emp_table to def_role "); + // Grant UPDATE privilege on this table to the role tc_role + stmt1.execute("GRANT UPDATE ON TABLE test.tc_emp_table TO ROLE tc_role"); + System.out.println(" Granted UPDATE privilege on table test.tc_emp_table to tc_role "); + stmt1.close(); + } + catch(Exception ex) + { + System.out.println(" Failed to grant privileges on the table test.tc_emp_table"); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + /************************************************************* + * Switch to new user user1 under a trusted connection by + * providing authentication information. + * user1 is explicitly defined as a user of the trusted context + **************************************************************/ + + newUser = user1; + newPassword = user1_pwd; + + try + { + System.out.println("\n Attempt switch user to "+newUser+" ..."); + con = pooledCon.getDB2Connection(cookie,newUser, newPassword, + null, null, null, properties); + stmt = con.createStatement(); + System.out.println("\t Check who is currently connected to database, should be "+ newUser +" ..."); + rs = stmt.executeQuery("values SYSTEM_USER"); + rs.next(); + sqlid = rs.getString(1); + System.out.println("\tCurrent user connected to database = " + sqlid); + if((sqlid.trim()).equalsIgnoreCase(newUser.trim())) + { + System.out.println(" Connected as "+newUser); + System.out.println(" Success on switch user for "+newUser+ + " by providing authentication information"); + } + else + { + System.out.println(" Switch user failed "); + } + rs.close(); + } + catch(Exception ex) + { + System.out.println(" Switch user for " +newUser+" failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // check whether the user inherited trusted context-specific default privileges + try + { + stmt = con.createStatement(); + rs = stmt.executeQuery("SELECT emp_name FROM test.tc_emp_table where emp_no = 100 "); + System.out.println("\n Select emp_name from table tc_emp_table... "); + while (rs.next()) + { + String name = rs.getString(1); + System.out.println("\t" + name); + } + rs.close(); + System.out.println(" User "+ sqlid +" has inherited trusted context-specific default privileges"); + } + catch(Exception ex) + { + System.out.println(" Failed to inherit trusted context-specific privileges "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + /********************************************************************** + * Switch to new user user2 under a trusted connection without + * providing authentication information. + * Update the table as user2 has UPDATE privilege on the table. + ***********************************************************************/ + + newUser = user2; + + // Connect to database not from trusted conection and try to update the table + // user2 should not be able to update the table + try { + // connect to the database + Connection con1 = DriverManager.getConnection(url,user2,user2_pwd ); + System.out.println(user2 + " Connected to the database not from trusted connection"); + stmt = con1.createStatement(); + System.out.println("\n Update table tc_emp_table.... "); + stmt.executeUpdate("UPDATE test.tc_emp_table set emp_sal = 38000 where emp_no = 200"); + System.out.println("\n Updated table tc_emp_table"); + con1.close(); + } + catch (SQLException sqle) + { + System.out.println(" Update table failed "); + } + + try + { + System.out.println("\n Attempt switch user to "+newUser+" ..."); + con = pooledCon.getDB2Connection(cookie,newUser, null, + null, null, null, properties); + stmt = con.createStatement(); + System.out.println("\t Check who is currently connected to database, should be "+ newUser +" ..."); + rs = stmt.executeQuery("values SYSTEM_USER"); + rs.next(); + sqlid = rs.getString(1); + System.out.println("\tCurrent user connected to database = " + sqlid); + if((sqlid.trim()).equalsIgnoreCase(newUser.trim())) + { + System.out.println(" Connected as "+newUser); + System.out.println(" Success on switch user for "+newUser+ + " without providing authentication information"); + } + else + { + System.out.println(" Switch user failed "); + } + } + catch(Exception ex) + { + System.out.println(" Switch user failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // check whether the user inherited trusted context-specific privileges + try + { + stmt = con.createStatement(); + stmt.executeUpdate("UPDATE test.tc_emp_table set emp_sal = 38000 where emp_no = 200"); + System.out.println("\n Updated table tc_emp_table"); + System.out.println(" User "+ sqlid +" has inherited trusted context-specific privileges"); + } + catch(Exception ex) + { + System.out.println(" Failed to inherit trusted context-specific privileges "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + /************************************************************* + * Switch to user authid under a trusted connection to drop + * the objects created. + **************************************************************/ + + newUser = authid; + newPassword = authid_pwd; + + try + { + System.out.println("\n Attempt switch user to "+newUser+" ..."); + con = pooledCon.getDB2Connection(cookie,newUser, newPassword, + null, null, null, properties); + stmt = con.createStatement(); + System.out.println("\t Check who is currently connected to database, should be "+ newUser +" ..."); + rs = stmt.executeQuery("values SYSTEM_USER"); + rs.next(); + sqlid = rs.getString(1); + System.out.println("\tCurrent user connected to database = " + sqlid); + if((sqlid.trim()).equalsIgnoreCase(newUser.trim())) + { + System.out.println(" Connected as "+newUser); + System.out.println(" Success on switch user for "+newUser+ + " by providing authentication information"); + } + else + { + System.out.println(" Switch user failed "); + } + rs.close(); + } + catch(Exception ex) + { + System.out.println(" Switch user failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // Drop the table created + try + { + stmt = con.createStatement(); + System.out.println(" DROP the tables..."); + System.out.println(" DROP TABLE test.tc_emp_table"); + stmt.execute(" DROP TABLE test.tc_emp_table"); + stmt.close(); + } + catch(Exception ex) + { + System.out.println(" Alter trusted context failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + /************************************************************* + * Switch to a new user who is not defined as a user of the + * trusted context and this switch request made is not allowed + **************************************************************/ + + newUser = user3; + newPassword = user3_pwd; + + try + { + System.out.println("\n Attempt switch user to user "+newUser+" ..."); + con = pooledCon.getDB2Connection(cookie,newUser, newPassword, + null, null, null, properties); + stmt = con.createStatement(); + System.out.println("\t Check who is currently connected to database, should be "+ newUser +" ..."); + rs = stmt.executeQuery("values SYSTEM_USER"); + rs.next(); + sqlid = rs.getString(1); + System.out.println("\tCurrent user connected to database = " + sqlid); + if((sqlid.trim()).equalsIgnoreCase(newUser.trim())) + { + System.out.println(" Connected as "+newUser); + System.out.println(" Success on switch user for "+newUser); + } + else + { + System.out.println(" Switch user failed "); + } + } + catch(Exception ex) + { + System.out.println(" Switch user failed "); + System.out.println(" This is an Expected error!! "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + /************************************************ + * Close open connections + ***********************************************/ + finally{ + System.out.println("\n Close open connections"); + con.close(); + } + + /******************************************************* + * ALTER TRUSTED CONTEXT + ******************************************************/ + // connect to the database + try { + con = DriverManager.getConnection(url,userid,password ); + System.out.println(userid + " Connected to the database"); + con.setAutoCommit(true); + } + catch (SQLException sqle) + { + System.out.println(" Connect to database failed "); + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + } + + try + { + // Alter the trusted context to add new attributes + stmt = con.createStatement(); + // Disable the trusted context object + System.out.println("\n Disable the trusted context object"); + String st = "ALTER TRUSTED CONTEXT " + ctname + " ALTER DISABLE"; + stmt.execute(st); + System.out.println(st); + System.out.println("\n Alter the trusted context "); + st = "ALTER TRUSTED CONTEXT " + ctname + " ADD USE FOR PUBLIC WITH AUTHENTICATION"; + stmt.execute(st); + System.out.println(st); + stmt.close(); + } + catch(Exception ex) + { + System.out.println(" Alter trusted context failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // Drop the trusted context object and role + try + { + stmt = con.createStatement(); + // Drop the trusted context + System.out.println("\n Drop the trusted context... "); + System.out.println(" DROP TRUSTED CONTEXT " + ctname); + stmt.execute(" DROP TRUSTED CONTEXT " + ctname); + // Drop the role + System.out.println("\n Drop the roles..."); + System.out.println(" DROP ROLE tc_role "); + stmt.execute(" DROP ROLE tc_role "); + System.out.println(" DROP ROLE def_role "); + stmt.execute(" DROP ROLE def_role "); + stmt.close(); + } + catch(Exception ex) + { + System.out.println(" Alter trusted context failed "); + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + + // Close the connection + con.close(); + } + catch(Exception ex) + { + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + ((java.sql.SQLException)(ex)).getErrorCode()); + } + ex.printStackTrace(); + } + } // main +} // TrustedContext + diff --git a/java/jdbc/UDFCreate.db2 b/java/jdbc/UDFCreate.db2 new file mode 100644 index 0000000..729226d --- /dev/null +++ b/java/jdbc/UDFCreate.db2 @@ -0,0 +1,68 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFCreate.db2 +-- +-- SAMPLE: How to catalog the Java UDFs contained in UDFsrv.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +CREATE FUNCTION scratchpadScUDF( ) +RETURNS INTEGER +EXTERNAL NAME 'MYJAR1:UDFsrv!scratchpadScUDF' +FENCED +SCRATCHPAD 10 +FINAL CALL +VARIANT +NO SQL +PARAMETER STYLE DB2GENERAL +LANGUAGE JAVA +NO EXTERNAL ACTION@ + +CREATE FUNCTION scUDFReturningErr( DOUBLE, DOUBLE ) +RETURNS DOUBLE +EXTERNAL NAME 'MYJAR1:UDFsrv!scUDFReturningErr' +FENCED +NOT VARIANT +NO SQL +PARAMETER STYLE DB2GENERAL +LANGUAGE JAVA +NO EXTERNAL ACTION@ + +CREATE FUNCTION tableUDF ( DOUBLE ) +RETURNS TABLE ( name VARCHAR(20), job VARCHAR(20), salary DOUBLE ) +EXTERNAL NAME 'MYJAR1:UDFsrv!tableUDF' +LANGUAGE JAVA +PARAMETER STYLE DB2GENERAL +NOT DETERMINISTIC +FENCED +NO SQL +NO EXTERNAL ACTION +SCRATCHPAD 10 +FINAL CALL +DISALLOW PARALLEL +NO DBINFO@ + +connect reset@ diff --git a/java/jdbc/UDFDrop.db2 b/java/jdbc/UDFDrop.db2 new file mode 100644 index 0000000..edbd82e --- /dev/null +++ b/java/jdbc/UDFDrop.db2 @@ -0,0 +1,38 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFDrop.db2 +-- +-- SAMPLE: How to uncatalog the Java UDFs contained in UDFsrv.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +DROP FUNCTION scratchpadScUDF@ + +DROP FUNCTION scUDFReturningErr@ + +DROP FUNCTION tableUDF@ + +connect reset@ diff --git a/java/jdbc/UDFcli.java b/java/jdbc/UDFcli.java new file mode 100644 index 0000000..536df24 --- /dev/null +++ b/java/jdbc/UDFcli.java @@ -0,0 +1,284 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFcli.java +// +// SAMPLE: Call the UDFs in UDFsrv.java +// +// Parameter Style used in this program is "DB2GENERAL". +// +// Steps to run the sample with command line window: +// +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file UDFsrv (this will also compile +// the Utility file, erase the existing library/class files and +// copy the newly compiled class files, UDFsqlsv.class and +// Person.class from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make UDFsrv +// 2. Compile the client source file UDFcli (this will also call +// the script 'udfcat' to catalog the UDFs): +// nmake/make UDFcli +// 3. Run the client UDFcli: +// java UDFcli +// +// II) If you don't have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the utility file and the server source file with: +// javac Util.java +// javac UDFsrv.java +// 2. Erase the existing library/class files (if exists), +// UDFsrv.class and Person.class from the following path, +// $(DB2PATH)\function. +// 3. copy the class files, UDFsrv.class and Person.class from +// the current directory to the $(DB2PATH)\function. +// 4. Register/catalog the UDFs with: +// udfcat +// 5. Compile UDFcli with: +// javac UDFcli.java +// 6. Run UDFcli with: +// java UDFcli +// +// SQL Statements USED: +// SELECT +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: UDFcli.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; // JDBC classes + +class UDFcli +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO WORK WITH UDFs."); + + // connect database + db.connect(); + + demoExternalScratchpadScalarUDF(db.con); + demoExternalScalarUDFReturningErr(db.con); + demoExternalTableUDF(db.con); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void demoExternalScratchpadScalarUDF(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH SCRATCHPAD SCALAR UDF."); + + try + { + Statement stmt = con.createStatement(); + + // use SCRATCHPAD scalar UDF + System.out.println(); + System.out.println( + " Use the SCRATCHPAD scalar UDF:\n" + + " SELECT scratchpadScUDF(), name, job\n" + + " FROM staff\n" + + " WHERE name LIKE 'S%'"); + + ResultSet rs = stmt.executeQuery( + "SELECT scratchpadScUDF(), name, job " + + " FROM staff " + + " WHERE name LIKE 'S%' "); + + System.out.println(" COUNTER NAME JOB\n" + + " ------- ---------- -------"); + + int counter; + String name; + String job; + while (rs.next()) + { + counter = rs.getInt(1); + name = rs.getString(2); + job = rs.getString(3); + + System.out.println(" " + Data.format(counter, 7) + + " " + Data.format(name, 10) + + " " + Data.format(job, 7)); + } + rs.close(); + + // close statement + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demoExternalScratchpadScalarUDF + + static void demoExternalScalarUDFReturningErr(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH SCALAR UDF THAT RETURNS ERROR."); + + try + { + Statement stmt = con.createStatement(); + + // use scalar UDF + System.out.println(); + System.out.println( + " Use the scalar UDF that returns error:\n" + + " SELECT name, job, scUDFReturningErr(salary, 0.00)\n"+ + " FROM staff\n" + + " WHERE name LIKE 'S%'"); + + ResultSet rs = stmt.executeQuery( + "SELECT name, job, scUDFReturningErr(salary, 0.00)\n" + + " FROM staff " + + " WHERE name LIKE 'S%'"); + + System.out.println(" NAME JOB COMM\n" + + " ------- ---------- --------"); + + String name; + String job; + double comm; + while (rs.next()) + { + name = rs.getString(1); + job = rs.getString(2); + comm = rs.getDouble(3); + + System.out.println(" " + Data.format(name, 7) + + " " + Data.format(job, 10) + + " " + Data.format(comm, 7, 2)); + } + rs.close(); + + // close statement + stmt.close(); + } + catch (SQLException e) + { + if (e.getSQLState().equals("38999")) + { + System.out.println(); + System.out.println("--------- Expected Error ---------\n"); + } + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demoExternalscalarUDFReturningErr + + static void demoExternalTableUDF(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH TABLE UDF."); + + try + { + Statement stmt = con.createStatement(); + + // use table UDF + System.out.println(); + System.out.println( + " Use the table UDF:\n" + + " SELECT udfTb.name, udfTb.job, udfTb.salary\n" + + " FROM TABLE(TableUDF(1.5)) AS udfTb"); + + ResultSet rs = stmt.executeQuery( + "SELECT udfTb.name, udfTb.job, udfTb.salary " + + " FROM TABLE(TableUDF(1.5)) AS udfTb "); + + System.out.println(" NAME JOB SALARY\n" + + " ------- ---------- --------"); + + String name; + String job; + double newSalary; + while (rs.next()) + { + name = rs.getString(1); + job = rs.getString(2); + newSalary = rs.getDouble(3); + + System.out.println(" " + Data.format(name, 7) + + " " + Data.format(job, 10) + + " " + Data.format(newSalary, 7, 2)); + } + rs.close(); + + // close statement + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demoExternalTableUDF +} // UDFcli + diff --git a/java/jdbc/UDFcsvReader.java b/java/jdbc/UDFcsvReader.java new file mode 100644 index 0000000..c4044a6 --- /dev/null +++ b/java/jdbc/UDFcsvReader.java @@ -0,0 +1,329 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2010 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFcsvReader.java +// +// SAMPLE: Provide UDFs to be called by UDFcli.java +// +// Parameter Style used in this program is "DB2GENERAL". +// Dependency: This Java file has been written to compile with +// JDK 5+ (version 1.5). Please make sure you have +// an appropriate java compiler (javac) in your path. +// +// Steps to run the sample with command line window: +// +// 1. Compile the source file with: +// javac UDFcsvReader.java +// 2. Erase the existing library/class files (if exists), +// UDFcsvReader.class from the following path, +// $(DB2PATH)/function. +// 3. Copy the class file, UDFcsvReader.class, from the +// current directory to the $(DB2PATH)/function. +// 4. Drop any functions that are already created +// db2 -tvf DropGTF.db2 +// 5. Catalog the table functions: +// db2 -tvf CreateGTF.db2 +// 6. Change file path to sample.csv in GTFqueries.db2, and +// Issue query: +// db2 -tvf GTFqueries.db2 +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.net.URL; +import java.net.URLEncoder; +import COM.ibm.db2.app.UDF; + + +// This class has several Java Generic Table Functions +public class UDFcsvReader extends UDF +{ + + public String[] outRow; // row to output next (just a buffer) + public String tempString; + + private InputStream in; + + // holds output column types, if needed. + public String[] outCols; + + // Which element of in are we actually looking at? + private int pos = 0; + + // A file reader. For a more robust implementation, a csv reader + // can be used (available as open source) + private BufferedReader reader; + + /** + * Close all InputStreams + * @throws IOException + */ + public void disconnect() throws IOException { + in.close(); + } + + /** + * A Simple CSV Reader table function that takes a comma delimited file + * and returns rows. + * @param filename + **/ + public void csvReadString(String filename) throws Exception + { + int numInputs = 1; + switch (getCallType()) { + case SQLUDF_TF_OPEN: + in = new FileInputStream(filename); + reader = new BufferedReader(new InputStreamReader(in)); + break; + case SQLUDF_TF_FETCH: // read next row + tempString = reader.readLine(); + if(tempString != null) + { + outRow = (String[]) tempString.split(","); + return_row_as_str(numInputs); + } + else + { + this.disconnect(); + setSQLstate("02000"); + return; + } + break; + case SQLUDF_TF_CLOSE: // close + this.disconnect(); + break; + } // end switch + } // end csvReadString + + /** + * Sets the return columns as strings, and let's + * DB2 figure out the appropriate datatype and + * attempt to cast. An error will be throw if + * the cast cannot be done. This function allows + * the schema of the CSV to be omitted as input + * to the table function. + * @param numInputs + */ + public void return_row_as_str(int numInputs) throws Exception + { + // how many input parameters are there? + int n = numInputs; + + for(String s : outRow) + { + n = n+1; + set(n, s.trim()); + } + } + + /** + * Parse a comma delimited string of column types + * @param colString + */ + public void parseColString(String colString) + { + outCols = colString.split(","); + + int i = 0; + + for(String c: outCols) { + outCols[i] = outCols[i].trim(); + outCols[i] = outCols[i].toUpperCase(); + i++; + } + } + + /** + * A Simple CSV Reader table function that takes a delimited file, + * a comma delimited string of column types, and returns rows. + * @param filename + * @param colString + **/ + public void csvRead(String filename,String colString) throws Exception + { + int numInputs = 2; + switch (getCallType()) { + case SQLUDF_TF_OPEN: + in = new FileInputStream(filename); + reader = new BufferedReader(new InputStreamReader(in)); + parseColString(colString); + break; + case SQLUDF_TF_FETCH: // read next row + tempString = reader.readLine(); + if(tempString != null) + { + outRow = (String[]) tempString.split(","); + return_row(numInputs); + } + else + { + this.disconnect(); + setSQLstate("02000"); + return; + } + break; + case SQLUDF_TF_CLOSE: // close + this.disconnect(); + break; + } // end switch + } // end csvRead + + /** + * Return a row. + */ + public void return_row(int numInputs) throws Exception + { + // Get next row from HDFS (input) + + // how many input parameters are there? + int n = numInputs; + + // decimal, in case we need it + java.math.BigDecimal decimal; + + // Convert each column and set output + for (int i = 0; i < outCols.length; i++) { + // Get metadata (column type) + String db2type = outCols[i]; + + // parameter number to write back into in set() + n = n + 1; + + // Cast data to expected type and call a set + if (db2type.startsWith("SMALLINT")) { + set(n, Short.parseShort(outRow[i].trim())); + } else if (db2type.startsWith("INTEGER")) { + set(n, Integer.parseInt(outRow[i].trim())); + } else if (db2type.startsWith("BIGINT")) { + set(n, Long.parseLong(outRow[i].trim())); + } else if (db2type.startsWith("REAL")) { + set(n, Float.parseFloat(outRow[i].trim())); + } else if (db2type.startsWith("DOUBLE")) { + set(n, Double.parseDouble(outRow[i].trim())); + } else if (db2type.startsWith("DECIMAL")) { + decimal = new java.math.BigDecimal(outRow[i].trim()); + set(n, decimal); + } else if (db2type.startsWith("NUMERIC")) { + decimal = new java.math.BigDecimal(outRow[i].trim()); + set(n, decimal); + } else if (db2type.startsWith("CHAR") || db2type.startsWith("VARCHAR") || + db2type.startsWith("GRAPHIC") || db2type.startsWith("VARGRAPHIC")) { + set(n, outRow[i].trim()); + } else if (db2type.startsWith("DATE")) { + set(n, Date.parse(outRow[i].trim())); + } else if (db2type.startsWith("TIME")) { + set(n, Time.parse(outRow[i].trim())); + } else if (db2type.startsWith("TIMESTAMP")) { + set(n, Timestamp.parse(outRow[i].trim())); + } else { + // do something ... CLOB or so + set(n, outRow[i]); + } + } // end for each output column + } // end return_row + + /** + * A Http CSV Reader table function that takes a hostname, port, and filename + * and returns rows. + * @param filename + **/ + public void httpCsvReadString(String hostname, int port, String filename) throws Exception + { + int numInputs = 3; + switch (getCallType()) { + case SQLUDF_TF_OPEN: + URL stream = new URL("http://" + hostname + ":" + port + filename); + in = stream.openStream(); + reader = new BufferedReader(new InputStreamReader(in)); + break; + case SQLUDF_TF_FETCH: // read next row + tempString = reader.readLine(); + if(tempString != null) + { + outRow = (String[]) tempString.split(","); + return_row_as_str(numInputs); + } + else + { + this.disconnect(); + setSQLstate("02000"); + return; + } + break; + case SQLUDF_TF_CLOSE: // close + this.disconnect(); + break; + } // end switch + } // end httpCsvReadString + + /** + * A hadoop CSV Reader table function that takes a hostname, port, and + * filename and returns rows. + * @param filename + **/ + public void hadoopCsvReadString(String hostname, int port, String filename) throws Exception + { + int numInputs = 3; + switch (getCallType()) { + case SQLUDF_TF_OPEN: + URL stream = new URL("http://" + hostname + ":" + port + "/data" + filename); + in = stream.openStream(); + reader = new BufferedReader(new InputStreamReader(in)); + break; + case SQLUDF_TF_FETCH: // read next row + tempString = reader.readLine(); + if(tempString != null) + { + outRow = (String[]) tempString.split(","); + return_row_as_str(numInputs); + } + else + { + this.disconnect(); + setSQLstate("02000"); + return; + } + break; + case SQLUDF_TF_CLOSE: // close + this.disconnect(); + break; + } // end switch + } // end hadoopCsvReadString +} // end UDFcsvReader + diff --git a/java/jdbc/UDFjCreate.db2 b/java/jdbc/UDFjCreate.db2 new file mode 100644 index 0000000..16f4332 --- /dev/null +++ b/java/jdbc/UDFjCreate.db2 @@ -0,0 +1,43 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFjCreate.db2 +-- +-- SAMPLE: How to catalog the Java UDFs contained in UDFjsrv.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +CREATE FUNCTION scalarUDF(CHAR(5), DOUBLE) +RETURNS DOUBLE +EXTERNAL NAME 'UDFjsrv!scalarUDF' +LANGUAGE JAVA +PARAMETER STYLE JAVA +NOT VARIANT +FENCED +CALLED ON NULL INPUT +NO SQL +NO EXTERNAL ACTION@ + +connect reset@ diff --git a/java/jdbc/UDFjDrop.db2 b/java/jdbc/UDFjDrop.db2 new file mode 100644 index 0000000..6854c6d --- /dev/null +++ b/java/jdbc/UDFjDrop.db2 @@ -0,0 +1,34 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFjDrop.db2 +-- +-- SAMPLE: How to uncatalog the Java UDFs contained in UDFjsrv.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +DROP FUNCTION scalarUDF@ + +connect reset@ diff --git a/java/jdbc/UDFjcli.java b/java/jdbc/UDFjcli.java new file mode 100644 index 0000000..61fc1da --- /dev/null +++ b/java/jdbc/UDFjcli.java @@ -0,0 +1,175 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFjcli.java +// +// SAMPLE: Call the UDFs in UDFjsrv.java +// +// Parameter Style used in this program is "JAVA". +// +// Steps to run the sample with command line window: +// +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file UDFjsrv (this will also compile +// the Utility file, erase the existing library/class files and +// copy the newly compiled class files, UDFjsrv.class and +// Person.class from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make UDFjsrv +// 2. Compile the client source file UDFjcli (this will also call +// the script 'udfjcat' to catalog the UDFs): +// nmake/make UDFjcli +// 3. Run the client UDFjcli: +// java UDFjcli +// +// II) If you don't have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the utility file and the server source file with: +// javac Util.java +// javac UDFjsrv.java +// 2. Erase the existing library/class files (if exists), +// UDFjsrv.class and Person.class from the following path, +// $(DB2PATH)\function. +// 3. copy the class files, UDFjsrv.class and Person.class from +// the current directory to the $(DB2PATH)\function. +// 4. Register/catalog the UDFs with: +// udfjcat +// 5. Compile UDFjcli with: +// javac UDFjcli.java +// 6. Run UDFjcli with: +// java UDFjcli +// +// SQL Statements USED: +// SELECT +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: UDFjcli.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.Connection; +import java.sql.Statement; +import java.sql.ResultSet; + +class UDFjcli +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO WORK WITH UDFs."); + + // connect database + db.connect(); + + demoExternalScalarUDF(db.con); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void demoExternalScalarUDF(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE FUNCTION\n" + + " COMMIT\n" + + " SELECT\n" + + " DROP FUNCTION\n" + + "TO WORK WITH SCALAR UDF."); + + try + { + Statement stmt = con.createStatement(); + + // use scalar UDF + System.out.println(); + System.out.println( + " Use the scalar UDF:\n" + + " SELECT name, job, salary, scalarUDF(job, salary)\n" + + " FROM staff\n" + + " WHERE name LIKE 'S%'"); + + ResultSet rs = stmt.executeQuery( + "SELECT name, job, salary, scalarUDF(job, salary) " + + " FROM staff " + + " WHERE name LIKE 'S%' "); + + System.out.println(); + System.out.println( + " NAME JOB SALARY NEW_SALARY\n" + + " ---------- ------- -------- ----------"); + + String name; + String job; + double salary; + double newSalary; + while (rs.next()) + { + name = rs.getString(1); + job = rs.getString(2); + salary = rs.getDouble(3); + newSalary = rs.getDouble(4); + System.out.println(" " + Data.format(name, 10) + + " " + Data.format(job, 7) + + " " + Data.format(salary, 7, 2) + + " " + Data.format(newSalary, 7, 2)); + } + rs.close(); + + // close statement + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } +} // UDFjcli + diff --git a/java/jdbc/UDFjsrv.java b/java/jdbc/UDFjsrv.java new file mode 100644 index 0000000..cceb9c3 --- /dev/null +++ b/java/jdbc/UDFjsrv.java @@ -0,0 +1,105 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFjsrv.java +// +// SAMPLE: Provide UDFs to be called by UDFjcli.java +// +// Parameter Style used in this program is "JAVA". +// +// Steps to run the sample with the command line window: +// +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file UDFjsrv (this will also compile +// the Utility file, erase the existing library/class files and +// copy the newly compiled class files, UDFjsrv.class and +// Person.class from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make UDFjsrv +// 2. Compile the client source file UDFjcli (this will also call +// the script 'udfjcat' to catalog the UDFs): +// nmake/make UDFjcli +// 3. Run the client UDFjcli: +// java UDFjcli +// +// II) If you don't have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the utility file and the server source file with: +// javac Util.java +// javac UDFjsrv.java +// 2. Erase the existing library/class files (if exists), +// UDFjsrv.class and Person.class from the following path, +// $(DB2PATH)\function. +// 3. copy the class files, UDFjsrv.class and Person.class from +// the current directory to the $(DB2PATH)\function. +// 4. Register/catalog the UDFs with: +// udfjcat +// 5. Compile UDFjcli with: +// javac UDFjcli.java +// 6. Run UDFjcli with: +// java UDFjcli +// +// OUTPUT FILE: UDFjcli.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; // for String class +import java.io.*; // for ...Stream classes + +public class UDFjsrv +{ + // scalar UDF + public static double scalarUDF(String inJob, double inSalary) + throws Exception + { + double outNewSalary = 0.00; + + if (inJob.equals("Mgr ")) + { + outNewSalary = inSalary * 1.20; + } + else if (inJob.equals("Sales")) + { + outNewSalary = inSalary * 1.10; + } + else + { + // Job is clerk + outNewSalary = inSalary * 1.05; + } + + // set the output value + return outNewSalary; + } +} + diff --git a/java/jdbc/UDFsCreate.db2 b/java/jdbc/UDFsCreate.db2 new file mode 100644 index 0000000..6f4a970 --- /dev/null +++ b/java/jdbc/UDFsCreate.db2 @@ -0,0 +1,74 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFsCreate.db2 +-- +-- SAMPLE: How to catalog the UDFs contained in UDFsqlsv.java +-- +-- To run this script from the CLP, perform the following steps: +-- 1. connect to the database +-- 2. issue the command "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +CREATE FUNCTION Convert(CHAR(2), DOUBLE, CHAR(2)) +RETURNS DOUBLE +EXTERNAL NAME 'UDFsqlsv!Convert' +FENCED +CALLED ON NULL INPUT +NOT VARIANT +READS SQL DATA +PARAMETER STYLE DB2GENERAL +LANGUAGE JAVA +NO EXTERNAL ACTION@ + +CREATE FUNCTION sumSalary(CHAR(3)) +RETURNS DOUBLE +EXTERNAL NAME 'UDFsqlsv!sumSalary' +FENCED +CALLED ON NULL INPUT +NOT VARIANT +READS SQL DATA +PARAMETER STYLE DB2GENERAL +LANGUAGE JAVA +NO EXTERNAL ACTION@ + +CREATE FUNCTION tableUDFWITHSQL ( DOUBLE ) +RETURNS TABLE ( name VARCHAR(20), job VARCHAR(20), salary DOUBLE ) +EXTERNAL NAME 'UDFsqlsv!tableUDF' +LANGUAGE JAVA +PARAMETER STYLE DB2GENERAL +NOT DETERMINISTIC +FENCED +READS SQL DATA +NO EXTERNAL ACTION +SCRATCHPAD 10 +FINAL CALL +DISALLOW PARALLEL +NO DBINFO@ + +CREATE TABLE EXCHANGERATE (sourceCurrency char(2), + exchangeRate double, + resultCurrency char(2))@ + +INSERT INTO EXCHANGERATE VALUES ('US',1.5,'CA')@ + +INSERT INTO EXCHANGERATE VALUES ('CA', .67, 'US')@ + diff --git a/java/jdbc/UDFsDrop.db2 b/java/jdbc/UDFsDrop.db2 new file mode 100644 index 0000000..8f89f3b --- /dev/null +++ b/java/jdbc/UDFsDrop.db2 @@ -0,0 +1,37 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFsDrop.db2 +-- +-- SAMPLE: How to uncatalog the UDFs contained in UDFsqlsv.java +-- +-- To run this script from the CLP, perform the following steps: +-- 1. connect to the database +-- 2. issue the command "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +DROP FUNCTION convert@ + +DROP FUNCTION sumSalary@ + +DROP FUNCTION tableUDFWithSQL@ + +DROP TABLE exchangeRate@ diff --git a/java/jdbc/UDFsqlcl.java b/java/jdbc/UDFsqlcl.java new file mode 100644 index 0000000..7b5b108 --- /dev/null +++ b/java/jdbc/UDFsqlcl.java @@ -0,0 +1,287 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFsqlcl.java +// +// SAMPLE: Call the UDFs in UDFsqlsv.java +// +// Steps to run the sample with the command line window: +// +// I) If you have a compatible make/nmake program on your system, +// all you have to do is: +// 1. Compile the server source file UDFsqlsv (this will also compile +// the Utility file, erase the existing library/class files and +// copy the newly compiled class files, UDFsqlsv.class and +// Person.class from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make UDFsqlsv +// 2. Connect to the sample database, type: +// db2 connect to sample +// 3. Catalog the UDFs defined in UDFsqlsv.java: +// db2 -td@ -vf UDFsCreate.db2 +// 4. Compile the client source file UDFsqlcl.java: +// nmake/make UDFsqlcl +// 5. Run the client UDFsqlcl +// java UDFsqlcl +// 6. Uncatalog the UDFs using the following command: +// db2 -td@ -vf@ UDFsDrop.db2 +// +// II) If you don't have a compatible make/nmake program on your system, +// all you have to do is: +// 1. Compile the utility file and the server source file with: +// javac Util.java +// javac UDFsqlsv.java +// 2. Erase the existing library/class files (if exists), +// UDFsqlsv.class and Person.class from the following path, +// $(DB2PATH)\function. +// 3. copy the class files, UDFsqlsv.class and Person.class from +// the current directory to the $(DB2PATH)\function. +// 4. Connect to the sample database, type: +// db2 connect to sample +// 5. Catalog the UDFs defined in UDFsqlsv.java: +// db2 -td@ -vf UDFsCreate.db2 +// 6. Compile UDFsqlcl with: +// javac UDFsqlcl.java +// 7. Run UDFsqlcl with: +// java UDFsqlcl +// 8. Uncatalog the UDFs using the following command: +// db2 -td@ -vf@ UDFsDrop.db2 +// +// SQL Statements USED: +// SELECT +// +// OUTPUT FILE: UDFsqlcl.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; // JDBC classes +import java.lang.*; +import java.math.BigDecimal; + +class UDFsqlcl +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO WORK WITH UDFs."); + + // connect database + db.connect(); + + demoExternalScalarUDFWithSQL(db.con); + demoExternalScalarUDFWithNesting(db.con); + demoExternalTableUDFWithSQL(db.con); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void demoExternalScalarUDFWithSQL(Connection con) + throws Exception + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH SCALAR UDF WITH SQL."); + + try + { + Statement stmt = con.createStatement(); + + // use SCRATCHPAD scalar UDF + System.out.println(); + System.out.println( + " Use the scalar UDF with SQL:\n" + + " SELECT name, job, salary, convert(CHAR('CA'), salary, CHAR('US'))\n" + + " FROM staff\n" + + " WHERE name LIKE 'S%'"); + + ResultSet rs = stmt.executeQuery( + "SELECT name, job, salary, convert(CHAR('CA'), salary, CHAR('US')) " + + " FROM staff " + + " WHERE name LIKE 'S%' "); + + System.out.println(" NAME JOB SALARY SALARY IN US\n" + + " ---------- ------- -------- ------------"); + + String name; + String job; + BigDecimal salary; + double salaryInUS; + while (rs.next()) + { + name = rs.getString(1); + job = rs.getString(2); + salary = rs.getBigDecimal(3); + salaryInUS = rs.getDouble(4); + + System.out.println(" " + Data.format(name, 10) + + " " + Data.format(job, 7) + + " " + Data.format(salary, 7, 2) + + " " + Data.format(salaryInUS, 7, 2)); + } + rs.close(); + + // close statement + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demoExternalScratchpadScalarUDF + + static void demoExternalScalarUDFWithNesting(Connection con) + throws Exception + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH SCALAR UDF WITH NESTING."); + + try + { + Statement stmt = con.createStatement(); + + // use scalar UDF + System.out.println(); + System.out.println( + " Use the scalar UDF that returns error:\n" + + " SELECT deptno, deptname, sumSalary(deptno)\n"+ + " FROM department\n"); + + ResultSet rs = stmt.executeQuery( + "SELECT deptno, deptname, sumSalary(deptno)\n" + + " FROM department "); + + System.out.println(" DEPTNO Department name SUM SALARY\n" + + " ------ ----------------------------- ----------"); + + String deptno; + String deptname; + double sumSalary; + + while (rs.next()) + { + deptno = rs.getString(1); + deptname = rs.getString(2); + sumSalary = rs.getDouble(3); + + System.out.println(" " + Data.format(deptno, 6) + + " " + Data.format(deptname, 29) + + " " + Data.format(sumSalary, 7, 2)); + } + rs.close(); + + // close statement + stmt.close(); + } + catch (SQLException e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demoExternalscalarUDFReturningErr + + static void demoExternalTableUDFWithSQL(Connection con) + throws Exception + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH TABLE UDF WITH SQL."); + + try + { + Statement stmt = con.createStatement(); + + // use table UDF + System.out.println(); + System.out.println( + " Use the table UDF:\n" + + " SELECT udfTb.name, udfTb.job, udfTb.salary\n" + + " FROM TABLE(TableUDF(1.5)) AS udfTb"); + + ResultSet rs = stmt.executeQuery( + "SELECT udfTb.name, udfTb.job, udfTb.salary " + + " FROM TABLE(TableUDFWITHSQL(1.5)) AS udfTb "); + + System.out.println(" NAME JOB SALARY\n" + + " ------- ---------- --------"); + + String name; + String job; + double newSalary; + while (rs.next()) + { + name = rs.getString(1); + job = rs.getString(2); + newSalary = rs.getDouble(3); + + System.out.println(" " + Data.format(name, 7) + + " " + Data.format(job, 10) + + " " + Data.format(newSalary, 7, 2)); + } + rs.close(); + + // close statement + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // demoExternalTableUDF +} // UDFcli + + + + + + + + diff --git a/java/jdbc/UDFsqlsv.java b/java/jdbc/UDFsqlsv.java new file mode 100644 index 0000000..ce48493 --- /dev/null +++ b/java/jdbc/UDFsqlsv.java @@ -0,0 +1,364 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFsqlsv.java +// +// SAMPLE: Provide UDFs to be called by UDFsqlcl.java +// +// Steps to run the sample with the command line window: +// +// I) If you have a compatible make/nmake program on your system, +// all you have to do is: +// 1. Compile the server source file UDFsqlsv (this will also compile +// the Utility file, erase the existing library/class files and +// copy the newly compiled class files, UDFsqlsv.class and +// Person.class from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make UDFsqlsv +// 2. Connect to the sample database, type: +// db2 connect to sample +// 3. Catalog the UDFs defined in UDFsqlsv.java: +// db2 -td@ -vf UDFsCreate.db2 +// 4. Compile the client source file UDFsqlcl.java: +// nmake/make UDFsqlcl +// 5. Run the client UDFsqlcl +// java UDFsqlcl +// 6. Uncatalog the UDFs using the following command: +// db2 -td@ -vf@ UDFsDrop.db2 +// +// II) If you don't have a compatible make/nmake program on your system, +// all you have to do is: +// 1. Compile the utility file and the server source file with: +// javac Util.java +// javac UDFsqlsv.java +// 2. Erase the existing library/class files (if exists), +// UDFsqlsv.class and Person.class from the following path, +// $(DB2PATH)\function. +// 3. copy the class files, UDFsqlsv.class and Person.class from +// the current directory to the $(DB2PATH)\function. +// 4. Connect to the sample database, type: +// db2 connect to sample +// 5. Catalog the UDFs defined in UDFsqlsv.java: +// db2 -td@ -vf UDFsCreate.db2 +// 6. Compile UDFsqlcl with: +// javac UDFsqlcl.java +// 7. Run UDFsqlcl with: +// java UDFsqlcl +// 8. Uncatalog the UDFs using the following command: +// db2 -td@ -vf@ UDFsDrop.db2 +// +// SQL Statements USED: +// SELECT +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// OUTPUT FILE: UDFsqlcl.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; // for String class +import COM.ibm.db2.app.*; // UDF and associated classes +import java.sql.*; +import java.math.*; +import java.io.*; + +public class UDFsqlsv extends UDF +{ + Person[] staff; + int maxRows; + + public void Convert (String inSourceCurrency, + double inAmount, + String inResultCurrency, + double result) + throws Exception + { + if (isNull(1) || isNull(2) || isNull(3)) + { + return; + } + + try + { + // Get caller's connection to the database + Connection con = + DriverManager.getConnection("jdbc:default:connection"); + + String query = "SELECT exchangeRate " + + "FROM exchangeRate " + + "WHERE SourceCurrency = ? AND " + + "ResultCurrency = ?"; + + PreparedStatement stmt = con.prepareStatement(query); + stmt.setString(1, inSourceCurrency); + stmt.setString(2, inResultCurrency); + + ResultSet rs = stmt.executeQuery(); + + // move to first row of result set + if (!rs.next()) + { + setSQLstate("38990"); + setSQLmessage("Can't find corresponding exchange rate"); + return; + } + + // set value for the output parameter + double exchangeRate = rs.getDouble(1); + + set(4, exchangeRate * inAmount); + + // clean up resources + rs.close(); + stmt.close(); + con.close(); + } + catch (SQLException sqle) + { + setSQLstate("38999"); + setSQLmessage("SQLCODE = " + String.valueOf(sqle.getErrorCode())); + return; + } + } //Convert + + public void sumSalary(String inDeptNo, + double outAmount) + throws Exception + { + + double result = 0; + + if (isNull(1)) + { + return; + } + + try + { + // Get caller's connection to the database + Connection con = + DriverManager.getConnection("jdbc:default:connection"); + + String query = "SELECT Convert(CHAR('CA'), salary, CHAR('US')) " + + "FROM employee " + + "WHERE workdept = ?"; + + PreparedStatement stmt = con.prepareStatement(query); + stmt.setString(1, inDeptNo); + + ResultSet rs = stmt.executeQuery(); + + while(rs.next()) + { + result += rs.getDouble(1); + } + + set(2, result); + + rs.close(); + stmt.close(); + con.close(); + + } + catch (SQLException sqle) + { + setSQLstate("38999"); + setSQLmessage("SQLCODE = " + sqle.getSQLState()); + return; + } + + } // sumSalary + + + // the table UDF + public void tableUDF(double inSalaryFactor, + String outName, + String outJob, + double outNewSalary) + throws Exception + { + int intRow = 0; + + byte[] scratchpad = getScratchpad(); + + // variables to read from SCRATCHPAD area + ByteArrayInputStream + byteArrayIn = new ByteArrayInputStream(scratchpad); + DataInputStream + dataIn = new DataInputStream(byteArrayIn); + + // variables to write into SCRATCHPAD area + byte[] byteArrayRow; + int i; + ByteArrayOutputStream + byteArrayOut = new ByteArrayOutputStream(10); + DataOutputStream + dataOut = new DataOutputStream(byteArrayOut); + + switch (getCallType()) + { + case SQLUDF_TF_FIRST: + // do initialization for the whole statement + // (the statement may invoke tableUDF more than once) + break; + case SQLUDF_TF_OPEN: + // do initialization valid for this invokation of tableUDF + + intRow = 1; + // save data in SCRATCHPAD area + + try + { + // Get caller's connection to the database + Connection con = + DriverManager.getConnection("jdbc:default:connection"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT count(*) FROM STAFF"); + + rs.next(); + + maxRows = rs.getInt(1); + staff = new Person[maxRows]; + + rs.close(); + + rs = stmt.executeQuery("SELECT NAME, JOB, DOUBLE(SALARY) FROM STAFF"); + + int counter = 0; + while(rs.next()) + { + staff[counter] = new Person(rs.getString(1), rs.getString(2), rs.getDouble(3)); + counter ++; + } + + rs.close(); + stmt.close(); + con.close(); + } + catch(SQLException sqle) + { + setSQLstate("38999"); + setSQLmessage("SQLCODE = " + sqle.getSQLState()); + return; + } + + dataOut.writeInt(intRow); + byteArrayRow = byteArrayOut.toByteArray(); + for(i = 0; i < byteArrayRow.length; i++) + { + scratchpad[i] = byteArrayRow[i]; + } + setScratchpad(scratchpad); + break; + case SQLUDF_TF_FETCH: + // get data from SCRATCHPAD area + intRow = dataIn.readInt(); + // work with data + if(intRow > maxRows) + { + // Set end-of-file signal and return + setSQLstate ("02000"); + } + else + { + // Set the current output row and increment the row number + set(2, staff[intRow - 1].getName()); + set(3, staff[intRow - 1].getJob()); + set(4, staff[intRow - 1].getSalary() * inSalaryFactor); + intRow++; + } + + // save data in SCRATCHPAD area + dataOut.writeInt(intRow); + byteArrayRow = byteArrayOut.toByteArray(); + for(i = 0; i < byteArrayRow.length; i++) + { + scratchpad[i] = byteArrayRow[i]; + } + setScratchpad(scratchpad); + break; + case SQLUDF_TF_CLOSE: + break; + case SQLUDF_TF_FINAL: + break; + } + } // tableUDF +} + +// the class Person is used by the table UDF +class Person +{ + String name; + String job; + double salary; + + Person() + { + name = null; + job = null; + salary = 0.00; + } + + Person(String n , String j, double s) + { + name = n; + job = j; + salary = s; + } + + public String getName() + { + return name; + } + + public String getJob() + { + return job; + } + + public double getSalary() + { + return salary; + } +} // Person class + + + + + diff --git a/java/jdbc/UDFsrv.java b/java/jdbc/UDFsrv.java new file mode 100644 index 0000000..9a46b27 --- /dev/null +++ b/java/jdbc/UDFsrv.java @@ -0,0 +1,284 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFsrv.java +// +// Compile: the utility file and the source file with: +// javac Util.java +// javac .java +// +// Run: java [] +// or +// java [] +// +// SAMPLE: Provide UDFs to be called by UDFcli.java +// +// Parameter Style used in this program is "DB2GENERAL". +// +// Steps to run the sample with command line window: +// +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file UDFsrv (this will also compile +// the Utility file, erase the existing library/class files and +// copy the newly compiled class files, UDFsrv.class and +// Person.class from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make UDFsrv +// 2. Compile the client source file UDFcli (this will also call +// the script 'udfcat' to create and catalog the UDFs): +// nmake/make UDFcli +// 3. Run the client UDFcli: +// java UDFcli +// +// II) If you don't have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the utility file and the server source file with: +// javac Util.java +// javac UDFsrv.java +// 2. Erase the existing library/class files (if exists), +// UDFsrv.class and Person.class from the following path, +// $(DB2PATH)\function. +// 3. copy the class files, UDFsrv.class and Person.class from +// the current directory to the $(DB2PATH)\function. +// 4. Register the UDFs and UDT and create the UDT table with: +// udfcat +// 5. Compile UDFcli with: +// javac UDFcli.java +// 6. Run UDFcli with: +// java UDFcli +// +// OUTPUT FILE: UDFcli.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; // for String class +import java.io.*; // for ...Stream classes +import COM.ibm.db2.app.UDF; // UDF classes + +// Java user-defined functions are in this class +public class UDFsrv extends UDF +{ + // SCRATCHPAD scalar UDF + public void scratchpadScUDF(int outCounter) throws Exception + { + int intCounter = 0; + byte[] scratchpad = getScratchpad(); + + // variables to read from SCRATCHPAD area + ByteArrayInputStream + byteArrayIn = new ByteArrayInputStream(scratchpad); + DataInputStream + dataIn = new DataInputStream(byteArrayIn); + + // variables to write into SCRATCHPAD area + byte[] byteArrayCounter; + int i; + ByteArrayOutputStream + byteArrayOut = new ByteArrayOutputStream(10); + DataOutputStream + dataOut = new DataOutputStream(byteArrayOut); + + + switch(getCallType()) + { + case SQLUDF_FIRST_CALL: + // initialize data + intCounter = 1; + // save data into SCRATCHPAD area + dataOut.writeInt(intCounter); + byteArrayCounter = byteArrayOut.toByteArray(); + for(i = 0; i < byteArrayCounter.length; i++) + { + scratchpad[i] = byteArrayCounter[i]; + } + setScratchpad(scratchpad); + break; + case SQLUDF_NORMAL_CALL: + // read data from SCRATCHPAD area + intCounter = dataIn.readInt(); + // work with data + intCounter = intCounter + 1; + // save data into SCRATCHPAD area + dataOut.writeInt(intCounter); + byteArrayCounter = byteArrayOut.toByteArray(); + for(i = 0; i < byteArrayCounter.length; i++) + { + scratchpad[i] = byteArrayCounter[i]; + } + setScratchpad(scratchpad); + break; + } + // set the output value + set(1, intCounter); + } // scratchpadScUDF + + public void scUDFReturningErr(double inOperand1, + double inOperand2, + double outResult) + throws Exception + { + if (inOperand2 == 0.00) + { + setSQLstate("38999"); + setSQLmessage("DIVIDE BY ZERO ERROR"); + } + else + { + outResult = inOperand1 / inOperand2; + } + set(3, outResult); + } // scUDFReturningErr + + // variable for tableUDF + static final Person[] staff = + { + new Person("Pearce" , "Mgr" , 17300.00), + new Person("Wagland", "Sales", 15000.00), + new Person("Davis" , "Clerk", 10000.00) + }; + + // the table UDF + public void tableUDF(double inSalaryFactor, + String outName, + String outJob, + double outNewSalary) + throws Exception + { + int intRow = 0; + byte[] scratchpad = getScratchpad(); + + // variables to read from SCRATCHPAD area + ByteArrayInputStream + byteArrayIn = new ByteArrayInputStream(scratchpad); + DataInputStream + dataIn = new DataInputStream(byteArrayIn); + + // variables to write into SCRATCHPAD area + byte[] byteArrayRow; + int i; + ByteArrayOutputStream + byteArrayOut = new ByteArrayOutputStream(10); + DataOutputStream + dataOut = new DataOutputStream(byteArrayOut); + + switch (getCallType()) + { + case SQLUDF_TF_FIRST: + // do initialization for the whole statement + // (the statement may invoke tableUDF more than once) + break; + case SQLUDF_TF_OPEN: + // do initialization valid for this invokation of tableUDF + + intRow = 1; + // save data in SCRATCHPAD area + dataOut.writeInt(intRow); + byteArrayRow = byteArrayOut.toByteArray(); + for(i = 0; i < byteArrayRow.length; i++) + { + scratchpad[i] = byteArrayRow[i]; + } + setScratchpad(scratchpad); + break; + case SQLUDF_TF_FETCH: + // get data from SCRATCHPAD area + intRow = dataIn.readInt(); + // work with data + if(intRow > staff.length) + { + // Set end-of-file signal and return + setSQLstate ("02000"); + } + else + { + // Set the current output row and increment the row number + set(2, staff[intRow - 1].getName()); + set(3, staff[intRow - 1].getJob()); + set(4, staff[intRow - 1].getSalary() * inSalaryFactor); + intRow++; + } + + // save data in SCRATCHPAD area + dataOut.writeInt(intRow); + byteArrayRow = byteArrayOut.toByteArray(); + for(i = 0; i < byteArrayRow.length; i++) + { + scratchpad[i] = byteArrayRow[i]; + } + setScratchpad(scratchpad); + break; + case SQLUDF_TF_CLOSE: + break; + case SQLUDF_TF_FINAL: + break; + } + } // tableUDF +} // UDFsrv class + +// the class Person is used by the table UDF +class Person +{ + String name; + String job; + double salary; + + Person() + { + name = null; + job = null; + salary = 0.00; + } + + Person(String n , String j, double s) + { + name = n; + job = j; + salary = s; + } + + public String getName() + { + return name; + } + + public String getJob() + { + return job; + } + + public double getSalary() + { + return salary; + } +} // Person class + diff --git a/java/jdbc/Util.java b/java/jdbc/Util.java new file mode 100644 index 0000000..954b84b --- /dev/null +++ b/java/jdbc/Util.java @@ -0,0 +1,340 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Util.java +// +// SAMPLE: Utilities for JDBC sample programs +// +// This sample has 3 classes: +// 1. Data - Display the data in the table +// 2. Db - Connect to or disconnect from the 'sample' database +// 3. JdbcException - Handle Java Exceptions +// +// JAVA 2 CLASSES USED: +// DriverManager +// Connection +// Exception +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.util.*; +import java.sql.*; +import java.math.BigDecimal; + +class Data +{ + public static String format(String strData, int finalLen) throws Exception + { + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = strData; + for (int i = strData.length(); i < finalLen; i++) + { + finalStr = finalStr + " "; + } + } + return (finalStr); + } // format(String, int) + + public static String format(int intData, int finalLen) throws Exception + { + String strData = String.valueOf(intData); + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + return (finalStr); + } // format(int, int) + + public static String format(Integer integerData, int finalLen) + throws Exception + { + int intData; + String finalStr; + + intData = integerData.intValue(); + finalStr = format(intData, finalLen); + + return (finalStr); + } // format(Integer, int) + + public static String format(double doubData, int precision, int scale) + throws Exception + { + BigDecimal decData = new BigDecimal(doubData); + decData = decData.setScale(scale, BigDecimal.ROUND_HALF_EVEN); + String strData = decData.toString(); + + // prepare the final string + int finalLen = precision + 1; + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + + return (finalStr); + } // format(double, int, int) + + public static String format(BigDecimal decData, int precision, int scale) + throws Exception + { + decData = decData.setScale(scale, BigDecimal.ROUND_HALF_EVEN); + String strData = decData.toString(); + + // prepare the final string + int finalLen = precision + 1; + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + + return (finalStr); + } // format(BigDecimal, int, int) + + public static String format(Double doubleData, int precision, int scale) + throws Exception + { + double doubData; + String finalStr; + + doubData = doubleData.doubleValue(); + return (format(doubData, precision, scale)); + } // format(Double, int, int) +} // Data + +class Db +{ + public String alias; + public String server; + public int portNumber = -1; // < 0 use universal type 2 connection + // > 0 use universal type 4 connection + public String userId; + public String password; + public Connection con = null; + + public Db() + { + } + + public Db(String argv[]) throws Exception + { + if( argv.length > 5 || + ( argv.length == 1 && + ( argv[0].equals( "?" ) || + argv[0].equals( "-?" ) || + argv[0].equals( "/?" ) || + argv[0].equalsIgnoreCase( "-h" ) || + argv[0].equalsIgnoreCase( "/h" ) || + argv[0].equalsIgnoreCase( "-help" ) || + argv[0].equalsIgnoreCase( "/help" ) ) ) ) + { + throw new Exception( + "Usage: prog_name [dbAlias] [userId passwd] (use universal JDBC type 2 driver)\n" + + " prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)" ); + } + + switch (argv.length) + { + case 0: // Type 2, use all defaults + alias = "sample"; + userId = ""; + password = ""; + break; + case 1: // Type 2, dbAlias specified + alias = argv[0]; + userId = ""; + password = ""; + break; + case 2: // Type 2, userId & passwd specified + alias = "sample"; + userId = argv[0]; + password = argv[1]; + break; + case 3: // Type 2, dbAlias, userId & passwd specified + alias = argv[0]; + userId = argv[1]; + password = argv[2]; + break; + case 4: // Type 4, use default dbAlias + alias = "sample"; + server = argv[0]; + portNumber = Integer.valueOf( argv[1] ).intValue(); + userId = argv[2]; + password = argv[3]; + break; + case 5: // Type 4, everything specified + alias = argv[0]; + server = argv[1]; + portNumber = Integer.valueOf( argv[2] ).intValue(); + userId = argv[3]; + password = argv[4]; + break; + } + } // Db Constructor + + public Connection connect() throws Exception + { + String url = null; + + // In Partitioned Database environment, set this to the node number + // to which you wish to connect (leave as "0" in non-Partitioned Database environment) + String nodeNumber = "0"; + + Properties props = new Properties(); + + if ( portNumber < 0 ) + { + url = "jdbc:db2:" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 2 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + else + { + url = "jdbc:db2://" + server + ":" + portNumber + "/" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 4 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + + if( null != userId ) + { + props.setProperty("user", userId); + props.setProperty("password", password); + } + + props.setProperty("CONNECTNODE", nodeNumber); + + con = DriverManager.getConnection( url, props ); + + // enable transactions + con.setAutoCommit(false); + return con; + } // connect + + public void disconnect() throws Exception + { + System.out.println(); + System.out.println(" Disconnect from '" + alias + "' database."); + + // makes all changes made since the previous commit/rollback permanent + // and releases any database locks currrently held by the Connection. + con.commit(); + + // immediately disconnects from database and releases JDBC resources + con.close(); + } // disconnect +} // Db + +class JdbcException extends Exception +{ + Connection conn; + + public JdbcException(Exception e) + { + super(e.getMessage()); + conn = null; + } + + public JdbcException(Exception e, Connection con) + { + super(e.getMessage()); + conn = con; + } + + public void handle() + { + System.out.println(getMessage()); + System.out.println(); + + if (conn != null) + { + try + { + System.out.println("--Rollback the transaction-----"); + conn.rollback(); + System.out.println(" Rollback done!"); + } + catch (Exception e) + { + }; + } + } // handle + + public void handleExpectedErr() + { + System.out.println(); + System.out.println( + "**************** Expected Error ******************\n"); + System.out.println(getMessage()); + System.out.println( + "**************************************************"); + } // handleExpectedError +} // JdbcException + diff --git a/java/jdbc/bonus_calculate.db2 b/java/jdbc/bonus_calculate.db2 new file mode 100644 index 0000000..165cff6 --- /dev/null +++ b/java/jdbc/bonus_calculate.db2 @@ -0,0 +1,90 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +------------------------------------------------------------------------------- +-- SOURCE FILE NAME: bonus_calculate.db2 +-- +-- DESCRIPTION: This is the set up script for the sample Arrays_Sqlpl.java +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT +-- SELECT +-- DROP +-- CREATE PROCEDURE +-- +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to the database +CONNECT TO sample@ + +-- Drop the ARRAY types +DROP TYPE projects@ +DROP TYPE employees@ +DROP TYPE bonus@ + +-- Create the ARRAY types +-- Create the ARRAY type "projects". +CREATE TYPE projects AS VARCHAR(20) ARRAY[10]@ + +-- Create the ARRAY type "employee" +CREATE TYPE employees AS VARCHAR(6) ARRAY[20]@ + +-- Create the ARRAY type "bonus" +CREATE TYPE bonus AS DOUBLE ARRAY[20]@ + +-- Drop the table "bonus_temp" if already exists +drop table bonus_temp@ + +-- Create the table "bonus_temp" to store employee ID and corresponding +-- bonus information. +CREATE TABLE bonus_temp (empno varchar(6), bonus double)@ + +-- Drop the procedure if already exists +DROP PROCEDURE bonus_calculate@ +-- Create the procedure +CREATE PROCEDURE bonus_calculate (IN projs projects, IN percentage integer) +BEGIN +DECLARE emp_array employees; +DECLARE bonus_array bonus; + +-- Select the IDs and corresponding bonus in corresponding ARRAY type +-- "employees" and "bonus" using aggregate function +-- ARRAY_AGG. +SELECT cast(array_agg(employee.empno) AS employees), + cast(array_agg(.10*salary) AS bonus) INTO emp_array,bonus_array + FROM vempprojact, unnest(projs) AS P(id), employee + WHERE P.id=vempprojact.projno AND employee.empno=vempprojact.empno; + +-- Use UNNEST function to select the ARRAY elements from ARRAY +-- variables and insert the same in "bonus_temp" table. +INSERT INTO bonus_temp + SELECT T.empno, T.bonus + FROM unnest(emp_array, bonus_array) + WITH ORDINALITY AS T(empno,bonus, idx); +END@ diff --git a/java/jdbc/db2evmonfmt.java b/java/jdbc/db2evmonfmt.java new file mode 100755 index 0000000..e92e4f1 --- /dev/null +++ b/java/jdbc/db2evmonfmt.java @@ -0,0 +1,2738 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2008 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: db2evmonfmt.java +// +// SAMPLE: Extract the XML report from the event monitor +// +// Steps to run the sample with command line window: +// +// 1) Copy the following file to your working directory and ensure that +// directory has write permission: +// +// /samples/java/jdbc/db2evmonfmt.java +// /samples/java/jdbc/*.xsl +// +// 2) Modify the CLASSPATH to include: +// +// /sqllib/java/db2java.zip +// /sqllib/java/db2jcc.jar +// /sqllib/java/db2jcc_license_cu.jar +// /sqllib/java//lib +// /sqllib/lib +// /sqllib/function +// /sqllib/java/sqlj.zip +// where is the name of the +// jdk directory under /sqllib/java. +// +// 3) Modify the PATH to include /sqllib/java//bin, +// /sqllib/lib. +// +// 4) Modify the LD_LIBRARY_PATH to include /sqllib/lib +// +// 5) Compile the source file with: javac db2evmonfmt.java +// +// 6) Run the program: java db2evmonfmt -h +// for command line options. +// +// USAGE: +// +// db2evmonfmt -d [-ue | -wtt ] [ -u userid -p passwd ] +// < -fxml | -ftext [-ss stylesheet] > +// [ -id ] +// [ -type ] +// [ -hours ] +// [ -w ] +// [ -s ] +// [ -a ] +// +// OR +// +// db2evmonfmt -f xmlfile < -fxml | -ftext [-ss stylesheet] > +// +// where: +// +// dbname : Database name +// uetable : Name of the unformatted event table +// wttEvmonName : Name of the write to table event monitor. Note: event monitor name is case sensitive. +// userid : User ID +// passwd : Password +// +// xmlfile : Input XML file to format +// +// fxml : Pretty print the XML document to stdout +// ftext : Format XML document to text using the default XSLT +// stylesheet, pipe to stdout +// +// stylesheet : Use the following XSLT stylesheet to format to format +// the XML documents +// +// id : Display all events matching +// type : Display all events matching event type +// hours : Display all events that have occurred in the last +// hours +// w : Display all events where the event is part of +// workload +// +// For the Lock Event monitor, this will display all events +// where the lock requestor is part of +// +// s : Display all events where the event is part of +// service class +// +// For the Lock Event monitor, this will display all events +// where the lock requestor is part of +// +// a : Display all events where the event is part of +// application name +// +// For the Lock Event monitor, this will display all events +// where the lock requestor is part of +// +// For write to table event monitors, only dbname, wtt tag, output type(text or pretty print) are supported. +// See example No.4. +// +// Examples: +// +// 1. Get all events that are part of workload PAYROLL in the last 32 hours from +// UE table PKG in database SAMPLE. +// +// java db2evmonfmt -d SAMPLE -ue PKG -ftext -hours 32 -w PAYROLL +// +// 2. Get all events of type LOCKTIMEOUT that have occurred in the last 48 +// from UE table LOCK in database SAMPLE. +// +// java db2evmonfmt -d SAMPLE -ue LOCK -ftext -hours 48 -type LOCKTIMEOUT +// +// 3. Format the event contained in the file LOCK.XML using stylesheet +// MYREPORT.xsl +// +// java db2evmonfmt -f lock.xml -ftext -ss myreport.xsl +// +// 4. Get all events from the write to table event monitor T1 in database sample: +// java db2evmonfmt -d sample -wtt T1 -ftext +// +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; // for String class +import java.io.*; // for ...Stream classes +import java.io.Writer; // for ...Stream classes +import COM.ibm.db2.app.StoredProc; // Stored Proc classes +import java.sql.*; // for JDBC classes +import com.ibm.db2.jcc.*; // for XML class +import java.util.*; // Utility classes + +import javax.xml.transform.*; +import javax.xml.transform.stream.*; + +import org.w3c.dom.Document; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.DocumentBuilder; +import org.w3c.dom.*; + +import org.xml.sax.*; +import javax.xml.parsers.*; +import org.xml.sax.helpers.*; +import javax.xml.validation.*; +import javax.xml.transform.*; +import javax.xml.transform.stream.StreamSource; + +/*! + * /brief Class db2evmonfmt + * + * Class extracts the XML records from an Event Monitor Raw Table and + * formats the XML report to stdout. + */ +public class db2evmonfmt +{ + static String dbName = ""; + static String userid = ""; + static String passwd = ""; + static String uetable = ""; + static String wttEvmonName = ""; + + static String styleSheet = ""; + static String xmlInputFilename = ""; + static String xmlSchemaInputFilename = ""; + + static Boolean bPrettyPrint = false; + static Boolean bFormatText = false; + + static String workloadName = ""; + static String serviceClass = ""; + static String applName = ""; + + static SAXParserFactory fFactory; + static SAXParser parser; + + static int eventID = -1; + static String eventType = ""; + static int hours = 0; + static String mode = ""; + + public static final int EVENT_ID = 0; + public static final int EVENT_TYPE = 1; + public static final int EVENT_WORKLOAD = 2; + public static final int EVENT_SRVCLASS = 3; + public static final int EVENT_APPLNAME = 4; + + static String lockEvent = ")) + // + //---------------------------------------------------------- + String queryUETable = + "SELECT evmon.xmlreport FROM TABLE ( " + + "EVMON_FORMAT_UE_TO_XML( 'LOG_TO_FILE'," + + "FOR EACH ROW OF ( " + + "SELECT * FROM " + uetable.trim() + " "; + + //---------------------------------------------------------- + // Setup the the WHERE clause + //---------------------------------------------------------- + if ( (hours != 0) + || (eventType.length() != 0) + || (eventID > 0) + || (workloadName.length() > 0) + || (serviceClass.length() > 0) + || (applName.length() > 0) + ) + { + queryUETable += " WHERE"; + + if (eventID > 0) + { + if (bFirstCondition == false) + { + queryUETable += " AND"; + } + bFirstCondition = false; + + queryUETable += " EVENT_ID = ?"; + paramIndex[EVENT_ID] = (++paramCount); + } + + if (hours != 0) + { + if (bFirstCondition == false) + { + queryUETable += " AND"; + } + bFirstCondition = false; + + queryUETable += + " EVENT_TIMESTAMP >= CURRENT_TIMESTAMP - " + hours + " hours"; + } + + if (eventType.length() != 0) + { + if (bFirstCondition == false) + { + queryUETable += " AND"; + } + bFirstCondition = false; + + queryUETable += " EVENT_TYPE = ?"; + paramIndex[EVENT_TYPE] = (++paramCount); + } + + if (workloadName.length() != 0) + { + if (bFirstCondition == false) + { + queryUETable += " AND"; + } + bFirstCondition = false; + + queryUETable += " WORKLOAD_NAME = ?"; + paramIndex[EVENT_WORKLOAD] = (++paramCount); + } + + if (serviceClass.length() != 0) + { + if (bFirstCondition == false) + { + queryUETable += " AND"; + } + bFirstCondition = false; + + queryUETable += " SERVICE_SUBCLASS_NAME = ?"; + paramIndex[EVENT_SRVCLASS] = (++paramCount); + } + + if (applName.length() != 0) + { + if (bFirstCondition == false) + { + queryUETable += " AND"; + } + bFirstCondition = false; + + queryUETable += " APPL_NAME = ?"; + paramIndex[EVENT_APPLNAME] = (++paramCount); + } + } + queryUETable += " ORDER BY EVENT_ID, " + + "EVENT_TIMESTAMP, " + + "EVENT_TYPE, " + + "MEMBER ))) AS evmon"; + + //---------------------------------------------------------- + // Setup the Input and Output parameters + //---------------------------------------------------------- + stmt = con.prepareStatement(queryUETable); + + if (paramIndex[EVENT_ID] > 0) + { + stmt.setInt(paramIndex[EVENT_ID]++, eventID); + } + + if (paramIndex[EVENT_TYPE] > 0) + { + stmt.setString(paramIndex[EVENT_TYPE]++, eventType.toUpperCase()); + } + + if (paramIndex[EVENT_WORKLOAD] > 0) + { + stmt.setString(paramIndex[EVENT_WORKLOAD]++, workloadName.toUpperCase()); + } + + if (paramIndex[EVENT_SRVCLASS] > 0) + { + stmt.setString(paramIndex[EVENT_SRVCLASS]++, serviceClass.toUpperCase()); + } + + if (paramIndex[EVENT_APPLNAME] > 0) + { + stmt.setString(paramIndex[EVENT_APPLNAME]++, applName); + } + + //---------------------------------------------------------- + // Execute the SQL statement + //---------------------------------------------------------- + System.out.println(queryUETable); + System.out.println(" "); + + ResultSet rs = stmt.executeQuery(); + + //---------------------------------------------------------- + // Retrieve the data from the result set + //---------------------------------------------------------- + if (rs.next()) + { + do + { + xmlRow = rs.getBlob("XMLREPORT"); + + //---------------------------------------------------------- + // Pretty Print the XML document to stdout + //---------------------------------------------------------- + if (bPrettyPrint == true) + { + System.out.println("Row Number: " + rs.getRow()); + System.out.println(" "); + PrettyPrintXML(xmlRow.getBinaryStream()); + System.out.println(" "); + } + + //---------------------------------------------------------- + // Format the XML document to stdout based on the XML + // stylesheet + //---------------------------------------------------------- + else if (bFormatText == true) + { + docHeader = xmlRow.getBytes(1, 100); + reportType = new String(docHeader); + + //---------------------------------------------------------- + // The XML report is from the Lock Event Monitor. + // Call the XML to handle the db2LockReport + //---------------------------------------------------------- + if (reportType.indexOf(lockEvent) != -1) + { + LockReportFormatter(xmlRow.getBinaryStream()); + } + else if (reportType.indexOf(uowEvent) != -1) + { + UOWReportFormatter(xmlRow.getBinaryStream()); + } + else if (reportType.indexOf(pkgCacheEvent) != -1) + { + PkgCacheReportFormatter(xmlRow.getBinaryStream()); + } + else + { + System.out.println(" "); + System.out.println("Tool does not support the XML document type"); + System.out.println(reportType); + System.out.println(" "); + } + + } + } + while (rs.next()); + } + else + { + System.out.println("Result set is empty"); + } + System.out.println(" "); + + //---------------------------------------------------------- + // Close the statement and result set + //---------------------------------------------------------- + rs.close(); + stmt.close(); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + System.out.println(); + + if (con != null) + { + try + { + con.rollback(); + } + catch (Exception error ) + { + } + } + else + { + System.out.println("Connection to db " + dbName + " can't be established."); + System.err.println(e) ; + } + + System.exit(1); + } + catch (Exception e) + { + System.out.println(e.getMessage()); + System.out.println(); + System.exit(1); + } + } + + /*! + * /brief FormatInputXMLFile + * + * Formats the input XML file + */ + public static void FormatInputXMLFile() throws Exception + { + File xmlFile = new File(xmlInputFilename); + + if (xmlFile.exists()) + { + InputStream xmlFileStream = new FileInputStream(xmlFile); + + //---------------------------------------------------------- + // Pretty Print the XML document to stdout + //---------------------------------------------------------- + if (bPrettyPrint == true) + { + PrettyPrintXML(xmlFileStream); + } + //---------------------------------------------------------- + // Format the XML document to stdout based on the XML + // stylesheet + //---------------------------------------------------------- + else if (bFormatText == true) + { + char [] docHeader = new char[101]; + InputStreamReader xmlHeader = new InputStreamReader( + new FileInputStream(xmlFile)); + + xmlHeader.read(docHeader, 1, 100); + String reportType = new String(docHeader); + + //---------------------------------------------------------- + // The XML report is from the Lock Event Monitor. + // Call the XML to handle the db2LockReport + //---------------------------------------------------------- + if (reportType.indexOf(lockEvent) != -1) + { + LockReportFormatter(xmlFileStream); + } + else if (reportType.indexOf(uowEvent) != -1) + { + UOWReportFormatter(xmlFileStream); + } + else if (reportType.indexOf(pkgCacheEvent) != -1) + { + PkgCacheReportFormatter(xmlFileStream); + } + else + { + System.out.println(" "); + System.out.println("Tool does not support XML document type"); + System.out.println(" "); + } + } + } + else + { + System.out.println(" "); + System.out.println("Input XML file '"+xmlInputFilename+"' does not exist."); + System.out.println(" "); + } + } + + /*! + * /brief PrettyPrintXML + * + * Function will pretty print the XML document using the XML + * stylesheet. + */ + public static void PrettyPrintXML(InputStream xmlSource) + { + try + { + TransformerFactory tFactory = TransformerFactory.newInstance(); + + String xmlStyleSheet = ""; + xmlStyleSheet += " "; + xmlStyleSheet += ""; + xmlStyleSheet += ""; + xmlStyleSheet += ""; + xmlStyleSheet += ""; + xmlStyleSheet += ""; + xmlStyleSheet += ""; + xmlStyleSheet += ""; + xmlStyleSheet += ""; + xmlStyleSheet += ""; + + Source xsl = new StreamSource( + new ByteArrayInputStream(xmlStyleSheet.getBytes())); + Transformer xmlTrans = tFactory.newTransformer(xsl); + + Source xmlData = new StreamSource(xmlSource); + Result output = new StreamResult(System.out); + + xmlTrans.transform(xmlData, output); + + } + catch (TransformerConfigurationException s) + { + System.out.println(s.getMessage()); + System.out.println(); + System.exit(1); + } + catch (TransformerException f) + { + System.out.println(f.getMessage()); + System.out.println(); + System.exit(1); + } + } + + /*! + * brief ChangeHistoryReportFormatter + * + * Function will format the Change History report based on the XML stylesheet + */ + public static void ChangeHistoryReportFormatter(InputStream xmlSource) + { + try + { + TransformerFactory tFactory = TransformerFactory.newInstance(); + File stylesheet = null; + if (styleSheet.length() == 0) + { + stylesheet = new File("DB2EvmonChangeHistory.xsl"); + } + else + { + stylesheet = new File(styleSheet); + } + Source xsl = new StreamSource(stylesheet); + Transformer xmlTrans = tFactory.newTransformer(xsl); + Source xmlData = new StreamSource(xmlSource); + Result output = new StreamResult(System.out); + xmlTrans.transform(xmlData, output); + } + catch (TransformerConfigurationException s) + { + System.out.println(s.getMessage()); + System.out.println(); + System.exit(1); + } + catch (TransformerException f) + { + System.out.println(f.getMessage()); + System.out.println(); + System.exit(1); + } + } + + /*! + * /brief LockReportFormatter + * + * Function will format the Lock Report based on the XML stylesheet + */ + public static void LockReportFormatter(InputStream xmlSource) + { + try + { + TransformerFactory tFactory = TransformerFactory.newInstance(); + + //---------------------------------------------------------- + // Load the XML stylesheet from the current directory + //---------------------------------------------------------- + File stylesheet = null; + if (styleSheet.length() == 0) + { + stylesheet = new File("DB2EvmonLocking.xsl"); + } + else + { + stylesheet = new File(styleSheet); + } + + Source xsl = new StreamSource(stylesheet); + Transformer xmlTrans = tFactory.newTransformer(xsl); + + Source xmlData = new StreamSource(xmlSource); + Result output = new StreamResult(System.out); + + xmlTrans.transform(xmlData, output); + + } + catch (TransformerConfigurationException s) + { + System.out.println(s.getMessage()); + System.out.println(); + System.exit(1); + } + catch (TransformerException f) + { + System.out.println(f.getMessage()); + System.out.println(); + System.exit(1); + } + } + + /*! + * /brief UOWReportFormatter + * + * Function will format the UOW Report based on the XML stylesheet + */ + public static void UOWReportFormatter(InputStream xmlSource) + { + try + { + TransformerFactory tFactory = TransformerFactory.newInstance(); + + //---------------------------------------------------------- + // Load the XML stylesheet from the current directory + //---------------------------------------------------------- + File stylesheet = null; + if (styleSheet.length() == 0) + { + stylesheet = new File("DB2EvmonUOW.xsl"); + } + else + { + stylesheet = new File(styleSheet); + } + Source xsl = new StreamSource(stylesheet); + Transformer xmlTrans = tFactory.newTransformer(xsl); + Source xmlData = new StreamSource(xmlSource); + Result output = new StreamResult(System.out); + + xmlTrans.transform(xmlData, output); + + } + catch (TransformerConfigurationException s) + { + System.out.println(s.getMessage()); + System.out.println(); + System.exit(1); + } + catch (TransformerException f) + { + System.out.println(f.getMessage()); + System.out.println(); + System.exit(1); + } + } + /*! + * /brief PkgCacheReportFormatter + * + * Function will format the Pkg Cache Report based on the XML stylesheet + */ + public static void PkgCacheReportFormatter(InputStream xmlSource) + { + try + { + TransformerFactory tFactory = TransformerFactory.newInstance(); + + //---------------------------------------------------------- + // Load the XML stylesheet from the current directory + //---------------------------------------------------------- + File stylesheet = null; + if (styleSheet.length() == 0) + { + stylesheet = new File("DB2EvmonPkgCache.xsl"); + } + else + { + stylesheet = new File(styleSheet); + } + + Source xsl = new StreamSource(stylesheet); + Transformer xmlTrans = tFactory.newTransformer(xsl); + + Source xmlData = new StreamSource(xmlSource); + Result output = new StreamResult(System.out); + + xmlTrans.transform(xmlData, output); + } + catch (TransformerConfigurationException s) + { + System.out.println(s.getMessage()); + System.out.println(); + System.exit(1); + } + catch (TransformerException f) + { + System.out.println(f.getMessage()); + System.out.println(); + System.exit(1); + } + } + + /*! + * /brief ParseArguments + * + * Parse the command line arguements. + * + */ + public static void ParseArguments(String argv[]) throws Exception + { + int count = 0; + char value; + char optionChar; + Boolean bDisplayHelp = false; + Exception usage = new Exception( + "USAGE: \n" + + " \n" + + " db2evmonfmt -d [-ue | -wtt ] [ -u userid -p passwd ] \n" + + " < -fxml | -ftext [-ss stylesheet] > \n" + + " [ -id ] \n" + + " [ -type ] \n" + + " [ -hours ] \n" + + " [ -w ] \n" + + " [ -s ] \n" + + " [ -a ] \n" + + " \n" + + " OR \n" + + " \n" + + " db2evmonfmt -f xmlfile < -fxml | -ftext [-ss stylesheet] > \n" + + " \n" + + " where: \n" + + " \n" + + " dbname : Database name \n" + + " uetable : Name of the unformatted event monitor \n" + + " wttEvmonName : Name of the unit of work event monitor \n" + + " userid : User ID \n" + + " passwd : Password \n" + + " \n" + + " xmlfile : Input XML file to format \n" + + " \n" + + " fxml : Pretty print the XML document to stdout \n" + + " ftext : Format XML document to text using the default XSLT \n" + + " stylesheet, pipe to stdout \n" + + " \n" + + " stylesheet : Use the following XSLT stylesheet to format to format \n" + + " the XML documents \n" + + " \n" + + " id : Display all events matching \n" + + " type : Display all events matching event type \n" + + " hours : Display all events that have occurred in the last \n" + + " hours \n" + + " w : Display all events where the event is part of \n" + + " workload \n" + + " \n" + + " For the Lock Event monitor, this will display all \n" + + " events where the lock requestor is part of \n" + + " \n" + + " \n" + + " s : Display all events where the event is part of \n" + + " service class \n" + + " \n" + + " For the Lock Event monitor, this will display all \n" + + " events where the lock requestor is part of \n" + + " \n" + + " \n" + + " a : Display all events where the event is part of \n" + + " application name \n" + + " \n" + + " For the Lock Event monitor, this will display all \n" + + " events where the lock requestor is part of \n" + + " \n" + + " For WTT events, only dbname, wtt tag, output type(text or pretty print) \n" + + " are supported. \n" + + " \n" + + " Examples: \n" + + " \n" + + " 1. Get all events that are part of workload PAYROLL in the last 32 hours \n" + + " from UE table PKG in database SAMPLE. \n" + + " \n" + + " java db2evmonfmt -d SAMPLE -ue PKG -ftext -hours 32 -w PAYROLL \n" + + " \n" + + " 2. Get all events of type LOCKTIMEOUT that have occurred in the last 24 \n" + + " hours from UE table LOCK in database SAMPLE. \n" + + " \n" + + " java db2evmonfmt -d SAMPLE -ue LOCK -ftext -hours 24 -type LOCKTIMEOUT \n" + + " \n" + + " 3. Format the event contained in the file LOCK.XML using stylesheet \n" + + " MYREPORT.xsl \n" + + " \n" + + " java db2evmonfmt -f lock.xml -ftext -ss myreport.xsl \n" + + " \n" + + " 4. Get all events from WTT table T1 in database sample: \n" + + " \n" + + " java db2evmonfmt -d SAMPLE -wtt T1 -ftext \n" + + "\n"); + + if( argv.length < 2 || + ( argv.length == 1 && + ( argv[0].equals( "?" ) || + argv[0].equals( "-?" ) || + argv[0].equals( "/?" ) || + argv[0].equalsIgnoreCase( "-h" ) || + argv[0].equalsIgnoreCase( "/h" ) || + argv[0].equalsIgnoreCase( "-help" ) || + argv[0].equalsIgnoreCase( "/help" ) ) ) ) + { + throw usage; + } + + while ((count + 1 <= argv.length) && (bDisplayHelp == false)) + { + if (argv[count].equals("-d")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + dbName = "jdbc:db2:" + argv[count+1]; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-u")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + userid = argv[count+1]; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-p")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + passwd = argv[count+1]; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-ue")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + uetable = argv[count+1]; + mode = "UE"; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-wtt")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + wttEvmonName = argv[count+1]; + mode = "WTT"; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-id")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + eventID = Integer.parseInt(argv[count+1]); + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-type")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + eventType = argv[count+1]; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-hours")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + hours = Integer.parseInt(argv[count+1]); + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-fxml")) + { + bPrettyPrint = true; + count++; + continue; + } + else if (argv[count].equals("-ftext")) + { + bFormatText = true; + count++; + continue; + } + else if (argv[count].equals("-ss")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + styleSheet = argv[count+1]; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-f")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + xmlInputFilename = argv[count+1]; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-w")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + workloadName = argv[count+1]; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-s")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + serviceClass = argv[count+1]; + } + else + { + bDisplayHelp = true; + } + } + else if (argv[count].equals("-a")) + { + if ( (count + 1 < argv.length) + && (!argv[count+1].startsWith("-")) + ) + { + applName = argv[count+1]; + } + else + { + bDisplayHelp = true; + } + } + else + { + bDisplayHelp = true; + } + count = count + 2; + } + + // Display help if: + // + // 1. dbname or evmon name is set to zero and no format options + // are specified + // 2. Or input XML file is not specified + if ( bDisplayHelp + || ( ((dbName.length() == 0) || ((uetable.length() == 0) && (wttEvmonName.length() == 0))) + && (xmlInputFilename.length() == 0) + ) + || ( (bFormatText == false) + && (bPrettyPrint == false) + ) + ) + { + throw usage; + } + } + +} + +/*! + * /brief Class SimpleErrorHandler + * + * SimpleErrorHandler handles all SAX parsing errors. + */ +class SimpleErrorHandler implements ErrorHandler +{ + public void warning(SAXParseException e) throws SAXParseException { + System.out.format("Warning (%d:%d): %s\n", + e.getLineNumber(), + e.getColumnNumber(), + e.getMessage()); + throw(e); + } + + public void error(SAXParseException e) throws SAXParseException { + System.out.format("Error (%d:%d): %s\n", + e.getLineNumber(), + e.getColumnNumber(), + e.getMessage()); + throw(e); + } + + public void fatalError(SAXParseException e) throws SAXParseException { + System.out.format("Fatal Error (%d:%d): %s\n", + e.getLineNumber(), + e.getColumnNumber(), + e.getMessage()); + throw(e); + } +} + diff --git a/java/jdbc/makefile b/java/jdbc/makefile new file mode 100644 index 0000000..6e7c13a --- /dev/null +++ b/java/jdbc/makefile @@ -0,0 +1,402 @@ +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# +# MAKEFILE for JDBC samples on Unix +# +# Enter one of the following commands +# +# make - Builds the program designated by . +# +# make all - Builds all supplied sample programs except GSS API +# plugin samples. +# +# make srv - Builds samples that can only be run on the server, +# including routines, stored procedures and UDFs. +# +# make rtn - Builds all routines, stored procedures and UDFs. +# +# make all_client - Builds all client samples (all programs in the +# 'call_rtn' and 'client_run' categories). +# +# make call_rtn - Builds all client programs that call routines, +# stored procedures and UDFs. +# +# make client_run - Builds all programs that run completely on the +# client (not ones that call routines, stored +# procedures or UDFs). +# +# make java_beans - Builds all Java Beans samples +# +# make jcc_plugins - Builds all Java GSS-API Plugins samples (this requires +# IBM DB2 Universal Driver to be installed in the CLASSPATH) +# +# make clean - Erases all intermediate files produced in the +# build process. +# +# make cleanall - Erases all files produced in the build process +# (all files except the original source files). +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +############################################################################## +# 1 -- VARIABLES +############################################################################## + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +COPY=cp +ERASE=rm -f + +############################################################################# +# Generic rule to make a class from a java source file +############################################################################# + +.SUFFIXES : .class .java + +.java.class : + javac $< + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all (srv + all_client) +# 2b - make srv +# 2c - make rtn +# 2d - make all_client (call_rtn + client_run + java_beans) +# 2e - make call_rtn +# 2f - make client_run +# 2g - make java_beans +# 2h - make jcc_plugins +# 2i - make clean +# 2j - make cleanall +############################################################################# + +#**************************************************************************** +# 2a - make all (srv + all_client) +#**************************************************************************** + +all : \ + srv \ + all_client + +#**************************************************************************** +# 2b - make srv +#**************************************************************************** + +srv : \ + rtn + +#**************************************************************************** +# 2c - make rtn +#**************************************************************************** + +rtn : \ + SpServer \ + UDFsrv \ + UDFsqlsv \ + UDFjsrv + +#**************************************************************************** +# 2d - make all_client (call_rtn + client_run + java_beans) +#**************************************************************************** + +all_client : \ + call_rtn \ + client_run \ + java_beans + +#**************************************************************************** +# 2e - make call_rtn +#**************************************************************************** + +call_rtn : \ + SpClient \ + UDFcli \ + UDFsqlcl \ + UDFjcli + +#**************************************************************************** +# 2f - make client_run +#**************************************************************************** + +client_run : \ + AdmCmdAutoCfg AdmCmdContacts AdmCmdDescribe \ + AdmCmdExport AdmCmdImport AdmCmdOnlineBackup AdmCmdQuiesce \ + AdmCmdUpdateCfg Applt \ + DbAuth DbConn DbInfo DbMCon DbNative DbSeq DbUse \ + DtInfo DtLob DtUdt \ + GetDBCfgParams GetDBMCfgParams GetLogs GetMessage LargeRid IlInfo \ + SetIntegrity TbAST TbCompress TbConstr TbCreate TbGenCol TbIdent TbInfo \ + TbInTrig TbMerge TbMod TbOnlineInx Temporal \ + TbPriv TbRead TbRowcompress TbRunstats TbSel TbTemp TbTrig TbUMQT \ + TbUnion Array_Stack Arrays_Sqlpl \ + TrustedContext ScalarFunctions ImplicitCasting Cgtt + +#**************************************************************************** +# 2g - make java_beans +#**************************************************************************** + +java_beans : \ + CreateEmployee \ + GeneratePayroll + +#**************************************************************************** +# 2h - make jcc_plugins +#**************************************************************************** + +jcc_plugins : \ + JCCKerberosPluginTest \ + JCCSimpleGSSPluginTest + +#**************************************************************************** +# 2i - make clean +#**************************************************************************** + +clean : + +#**************************************************************************** +# 2j - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) *.class + $(ERASE) $(DB2PATH)/function/SpServer.class + $(ERASE) $(DB2PATH)/function/UDFsrv.class + $(ERASE) $(DB2PATH)/function/Person.class + $(ERASE) $(DB2PATH)/function/UDFjsrv.class + $(ERASE) $(DB2PATH)/function/UDFsqlsv.class + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3b - applet +# 3c - standalone applications +# 3d - client/server applications +# 3e - Java Beans applications +# 3f - Java GSS-API Plugin applications +############################################################################# + +#**************************************************************************** +# 3b - applet +#**************************************************************************** + +Applt : Applt.class + +#**************************************************************************** +# 3c - standalone applications +#**************************************************************************** + +AdmCmdAutoCfg : Util.class AdmCmdAutoCfg.class + +AdmCmdContacts : Util.class AdmCmdContacts.class + +AdmCmdDescribe : Util.class AdmCmdDescribe.class + +AdmCmdExport : Util.class AdmCmdExport.class + +AdmCmdImport : Util.class AdmCmdImport.class + +AdmCmdOnlineBackup : Util.class AdmCmdOnlineBackup.class + +AdmCmdQuiesce : Util.class AdmCmdQuiesce.class + +AdmCmdUpdateCfg : Util.class AdmCmdUpdateCfg.class + +DbAuth : Util.class DbAuth.class + +DbConn : Util.class DbConn.class + +DbInfo : Util.class DbInfo.class + +DbMCon : Util.class DbMCon.class +# Re-catalog sample database as sample2, +# ignore errors since it may be cataloged already + -db2 catalog db sample as sample2 + +DbNative : Util.class DbNative.class + +DbRsHold : Util.class DbRsHold.class +# Sample DbRsHold.java requires jdk/jre 1.4 + +DbSeq : Util.class DbSeq.class + +DbUse : Util.class DbUse.class + +DtInfo : Util.class DtInfo.class + +DtLob : Util.class DtLob.class + +DtUdt : Util.class DtUdt.class + +GetDBCfgParams : Util.class GetDBCfgParams.class + +GetDBMCfgParams : Util.class GetDBMCfgParams.class + +GetLogs : Util.class GetLogs.class + +GetMessage : Util.class GetMessage.class + +IlInfo : Util.class IlInfo.class + +LargeRid : Util.class LargeRid.class + +SetIntegrity : Util.class SetIntegrity.class + +TbAST : Util.class TbAST.class + +TbCompress : Util.class TbCompress.class + +TbConstr : Util.class TbConstr.class + +TbCreate : Util.class TbCreate.class + +TbGenCol : Util.class TbGenCol.class + +TbIdent : Util.class TbIdent.class + +TbInfo : Util.class TbInfo.class + +TbInTrig : Util.class TbInTrig.class + +TbMerge : Util.class TbMerge.class + +TbMod : Util.class TbMod.class + +TbOnlineInx : Util.class TbOnlineInx.class + +TbPriv : Util.class TbPriv.class + +TbRead : Util.class TbRead.class + +TbRowcompress : Util.class TbRowcompress.class + +TbRunstats : Util.class TbRunstats.class + +TbSel : Util.class TbSel.class + +TbTemp : Util.class TbTemp.class + +TbTrig : Util.class TbTrig.class + +TbUMQT : Util.class TbUMQT.class + +TbUnion : Util.class TbUnion.class + +Temporal : Util.class Temporal.class + +Arrays_Sqlpl : Util.class Arrays_Sqlpl.class + +Array_Stack : Util.class Array_Stack.class + +TrustedContext : Util.class TrustedContext.class + +ScalarFunctions : Util.class ScalarFunctions.class + +ImplicitCasting : Util.class ImplicitCasting.class + +Cgtt : Cgtt.class + +#**************************************************************************** +# 3d - client/server applications +#**************************************************************************** + +#--------------------SpClient / SpServer------------------------------------# +# Note: before you execute SpClient for the first time, you must call the +# SpCreate.db2 CLP script to catalog the methods in SpServer as stored +# procedures. Call SpDrop.db2 to uncatalog the methods in SpServer. + +SpCat : + spcat + +SpClient : Util.class SpClient.class + +SpServer : SpServer.class + $(ERASE) $(DB2PATH)/function/SpServer.class + $(COPY) SpServer.class $(DB2PATH)/function + spcat + +#--------------------UDFcli / UDFsrv---------------------------------------# +# Note: before you execute UDFcli for the first time, you must call the +# UDFCreate.db2 CLP script to register the functions in UDFsrv as +# User Defined Functions (UDFs). + +UDFcat : + udfcat + +UDFcli : UDFcat Util.class UDFcli.class + +UDFsrv : UDFsrv.class + $(ERASE) $(DB2PATH)/function/UDFsrv.class + $(ERASE) $(DB2PATH)/function/Person.class + $(COPY) UDFsrv.class $(DB2PATH)/function + $(COPY) Person.class $(DB2PATH)/function + +#-------------------- UDFjcli / UDFjsrv ------------------------------# +# Note: before you execute UDFjcli for the first time, you must call the +# UDFjCreate.db2 CLP script to register the functions in UDFjsrv as +# User Defined Functions (UDFs). + +UDFjcat : + udfjcat + +UDFjcli : UDFjcat Util.class UDFjcli.class + +UDFjsrv : UDFjsrv.class + $(ERASE) $(DB2PATH)/function/UDFjsrv.class + $(COPY) UDFjsrv.class $(DB2PATH)/function + + +#-------------------- UDFjcli / UDFjsrv ------------------------------# +# Note: before you execute UDFsqlcl for the first time, you must call the +# UDFsCreate.db2 CLP script to register the functions in UDFsqlsv as +# User Defined Functions (UDFs). + +UDFsqlcl : Util.class UDFsqlcl.class + +UDFsqlsv : UDFsqlsv.class + $(ERASE) $(DB2PATH)/function/UDFsqlsv.class + $(ERASE) $(DB2PATH)/function/Person.class + $(COPY) UDFsqlsv.class $(DB2PATH)/function + $(COPY) Person.class $(DB2PATH)/function + +#**************************************************************************** +# 3e - Java Beans applications +#**************************************************************************** + +CreateEmployee : Util.class CreateEmployee.class + +GeneratePayroll : Util.class GeneratePayroll.class + +#**************************************************************************** +# 3f - JCC Plugins applications +#**************************************************************************** + +JCCKerberosPluginTest : JCCKerberosPluginTest.class JCCKerberosPlugin.class \ + JCCSimpleGSSException.class + +JCCSimpleGSSPluginTest: JCCSimpleGSSContext.class JCCSimpleGSSCredential.class \ + JCCSimpleGSSException.class JCCSimpleGSSName.class \ + JCCSimpleGSSPlugin.class JCCSimpleGSSPluginTest.class diff --git a/java/jdbc/sample.csv b/java/jdbc/sample.csv new file mode 100644 index 0000000..8829945 --- /dev/null +++ b/java/jdbc/sample.csv @@ -0,0 +1,5 @@ +John,Doe,120 jefferson st.,Riverside, NJ, 08075, 26, 46000,56255333387,2.5,53234.098304918 +Jack,McGinnis,220 hobo Av.,Phila, PA,09119,42, 650,482525320,3.0,234.532320498 +"John ""Da Man""",Repici,120 Jefferson St.,Riverside, NJ,08075, 76, 1000000,222332859,3.76,53.00000000001 +Stephen,Tyler,"7452 Terrace ""At the Plaza"" road",SomeTown,SD, 91234,99, 32000,-1,4.33,5.550293840293 +,Blankman,,SomeTown, SD, 00298, 55,-1, 234053983,3.33,863202342342 diff --git a/java/jdbc/spcat b/java/jdbc/spcat new file mode 100755 index 0000000..685da8f --- /dev/null +++ b/java/jdbc/spcat @@ -0,0 +1,58 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: spcat +# To catalog JDBC stored procedures on UNIX +# Catalogs the stored procedures in the SpServer library +# SpDrop.db2 uncatalogs the stored procedures if previously cataloged +# SpCreate.db2 catalogs the stored procedures +# Both CLP scripts can be run on their own +# Usage: spcat +############################################################################# + +# Uncatalog the stored procedures if previously cataloged +db2 -td@ -vf SpDrop.db2 + +# Connect to 'sample' database +db2 connect to sample + +# Uninstall the jar file if already installed +db2 "CALL sqlj.remove_jar('MYJAR')" + +# Remove the jar file if it already exists +rm SpServer.jar + +# Create a jar file 'SPServer.jar' using the class file 'SpServer.class' +# Compile 'SpServer.java' to get the class file 'SpServer.class' +echo "Executing 'javac SpServer.java'..." +javac SpServer.java + +# Create the jar file +echo "Executing 'jar cf SpServer.jar SpServer.class'..." +jar cf $HOME/SpServer.jar SpServer.class + +# Install the jar file using a unique jar-id. +db2 "CALL sqlj.install_jar('file:$HOME/SpServer.jar', 'MYJAR')" + +# Disconnect from 'sample' database +db2 connect reset + +# Catalog the stored procedures +db2 -td@ -vf SpCreate.db2 diff --git a/java/jdbc/stack_functions.db2 b/java/jdbc/stack_functions.db2 new file mode 100644 index 0000000..7c81387 --- /dev/null +++ b/java/jdbc/stack_functions.db2 @@ -0,0 +1,144 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: stack_functions.db2 +-- +-- DESCRIPTION: This is the set up script for the sample Array_Stack.java +-- +-- SQL STATEMENTS USED: +-- SELECT +-- DROP +-- CALL +-- CREATE PROCEDURE +-- +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to the database +CONNECT TO sample@ + +-- Drop the database objects if already exists. +DROP PROCEDURE push @ +DROP PROCEDURE top @ +DROP PROCEDURE pop @ +DROP PROCEDURE stack_2_resultset @ +DROP PROCEDURE use_stack @ +DROP TYPE int_stack @ + +---------------------------------------------------------------------------- +-- +-- 1. Create an ARRAY type to implement a stack. +-- +----------------------------------------------------------------------------- + +CREATE TYPE int_stack AS INTEGER ARRAY[] @ + +---------------------------------------------------------------------------- +-- +-- 2. Create a procedure to push a value in the stack. +-- +----------------------------------------------------------------------------- + +-- Create a stored procedure to insert value in the stack. +CREATE PROCEDURE push(INOUT s int_stack, IN element INTEGER) +BEGIN + IF (s is NULL) THEN + SET s[1] = element; + ELSE + SET s[cardinality(s) + 1] = element; + END IF; +END @ + +---------------------------------------------------------------------------- +-- +-- 3. Create a procedure to pop/retrieve value from the stack. +-- +----------------------------------------------------------------------------- + +-- Create a procedure to pop/retrieve a value from the stack. +CREATE PROCEDURE pop(INOUT s int_stack, OUT element INTEGER) +BEGIN + IF NOT(s is NULL) AND cardinality(s) > 0 THEN + SET element = s[cardinality(s)]; + SET s = trim_array(s, 1); + END IF; +END @ + +---------------------------------------------------------------------------- +-- +-- 4. Create a procedure to select the topmost value from the stack. +-- +----------------------------------------------------------------------------- + +-- Create a procedure to select the topmost value in the stack. +CREATE PROCEDURE top(IN s int_stack, OUT element INTEGER) +BEGIN + IF NOT(s is NULL) AND cardinality(s) > 0 THEN + SET element = s[cardinality(s)]; + END IF; +END @ + +---------------------------------------------------------------------------- +-- +-- 5. Create a procedure to return all the stack values as a result set. +-- +----------------------------------------------------------------------------- + +-- Create a procedure to return the stack values as a result set +CREATE PROCEDURE stack_2_resultset(IN s int_stack) +BEGIN + DECLARE cur CURSOR WITH RETURN TO CLIENT FOR + SELECT elem, idx FROM unnest(s) WITH ORDINALITY AS t(elem, idx); + + OPEN cur; + +END @ + +---------------------------------------------------------------------------- +-- +-- 6. Create a procedure to show case the stack functionalities. +-- +----------------------------------------------------------------------------- + +-- Create a procedure to show case the stack functionalities. +CREATE PROCEDURE use_stack(INOUT s int_stack, + OUT val1 INTEGER, + OUT val2 INTEGER) +BEGIN + CALL push(s, 100); + CALL push(s, 200); + CALL push(s, 300); + CALL push(s, 400); + + CALL pop(s, val1); + CALL top(s, val2); + + CALL stack_2_resultset(s); +END @ + diff --git a/java/jdbc/udfcat b/java/jdbc/udfcat new file mode 100755 index 0000000..1a4a76f --- /dev/null +++ b/java/jdbc/udfcat @@ -0,0 +1,58 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: udfcat +# To catalog JDBC user-defined functions on UNIX +# Catalogs the user-defined functions in the UDFsrv library +# UDFDrop.db2 uncatalogs the functions if previously cataloged +# UDFCreate.db2 catalogs the user-defined functions +# Both CLP scripts can be run on their own +# Usage: udfcat +############################################################################# + +# Uncatalog the functions if previously cataloged +db2 -td@ -vf UDFDrop.db2 + +# Connect to 'sample' database +db2 connect to sample + +# Uninstall the jar file if already installed +db2 "CALL sqlj.remove_jar('MYJAR1')" + +# Remove the jar file if already exists +rm UDFsrv.jar + +# Create a jar file 'UDFsrv.jar' using the class file 'UDFsrv.class' +# Compile 'UDFsrv.java' to get the class file 'UDFsrv.class' +echo "Executing 'javac UDFsrv.java'..." +javac UDFsrv.java + +# Create the jar file +echo "Executing 'jar cf UDFsrv.jar UDFsrv.class'..." +jar cf $HOME/UDFsrv.jar UDFsrv.class Person.class + +# Install the jar file using a unique jar-id. +db2 "CALL sqlj.install_jar('file:$HOME/UDFsrv.jar', 'MYJAR1')" + +# Disconnect from 'sample' database +db2 connect reset + +# Catalog the user-defined functions +db2 -td@ -vf UDFCreate.db2 diff --git a/java/jdbc/udfjcat b/java/jdbc/udfjcat new file mode 100755 index 0000000..69ca05a --- /dev/null +++ b/java/jdbc/udfjcat @@ -0,0 +1,31 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: udfjcat +# To catalog JDBC user-defined functions on UNIX +# Catalogs the user-defined functions in the UDFjsrv library +# UDFjDrop.db2 uncatalogs the functions if previously cataloged +# UDFjCreate.db2 catalogs the user-defined functions +# Both CLP scripts can be run on their own +# Usage: udfjcat + +db2 -td@ -vf UDFjDrop.db2 +db2 -td@ -vf UDFjCreate.db2 + diff --git a/java/sqlj/Applt.html b/java/sqlj/Applt.html new file mode 100644 index 0000000..cc358ba --- /dev/null +++ b/java/sqlj/Applt.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + DB2 SQLJ Sample Applet + + + +

DB2 SQLJ Sample Applet

+
+ + + + + + +
+ + + diff --git a/java/sqlj/Applt.sqlj b/java/sqlj/Applt.sqlj new file mode 100644 index 0000000..fc123cc --- /dev/null +++ b/java/sqlj/Applt.sqlj @@ -0,0 +1,221 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Applt.sqlj +// +// SAMPLE: An SQLJ applet that uses a JDBC applet driver to access a database +// +// This sample shows how to write an SQLJ applet that uses the +// JDBC Type 4 driver to access a DB2 database. +// +// This sample uses JDBC Type 4 driver to connect to +// the "sample" database. Run this sample using the +// following steps: +// 1. Create and populate the "sample" database with the following +// command: db2sampl +// +// 2. Customize Applt.html with your server, port, user ID, and +// password. Refer to Applt.html for details. +// +// 3. Compile the program with the following command (you have to +// hardcode the userid and password in the build file, bldsqlj, +// and update the port number if needed): +// bldsqlj Applt +// +// Alternatively, you can compile the program with the following +// command if you have a compatible make/nmake program on +// your system: +// make/nmake Applt +// +// 4. Ensure that your working directory is accessible by your web +// browser. If it is not, copy Applt.class and Applt.html into +// a directory that is accessible. +// +// 5. To use the JDBC Type 4 driver, copy sqllib\java\db2jcc.jar on +// Windows or sqllib/java/db2jcc.jar on UNIX, into the same +// directory as Applt.class and Applt.html. +// +// 6. To run this sample, start your web browser (which must support +// Java 1.3) and load Applt.html on your client machine. +// You can view it locally with the following command: +// appletviewer Applt.html +// +// +// SQL Statements USED: +// SELECT +// UPDATE +// ROLLBACK +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import java.awt.*; +import java.applet.Applet; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator Applt_Cursor1(String empno, String firstnme); +#sql iterator Applt_Cursor2(String); + +public class Applt extends Applet +{ + Connection con; + + public void init() + { + try + { + DefaultContext ctx = DefaultContext.getDefaultContext(); + if (ctx == null) + { + // get parameter values from the html page + String server = getParameter("server"); + String port = getParameter("port"); + + // construct the URL (sample is the database name) + String url = "jdbc:db2://"+server+":"+port+"/sample"; + + String userid = getParameter("userid"); + String password = getParameter("password"); + String driverType = getParameter("driverType"); + + // use driverType=4 + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database with user ID and password + con = DriverManager.getConnection(url, userid, password); + con.setAutoCommit(false); + + ctx = new DefaultContext(con); + DefaultContext.setDefaultContext(ctx); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public void paint(Graphics g) + { + try + { + Applt_Cursor1 cursor1; + Applt_Cursor2 cursor2; + + String str1 = null; + String str2 = null; + long count1; + + // retrieve data from database + g.drawString( + "First, let's retrieve some data from the database...", 10, 10); + + #sql cursor1 = {SELECT empno, firstnme FROM employee}; + g.drawString("Received results:", 10, 25); + + // display the result set + // cursor1.next() returns false when there are no more rows + int y = 50; + int i = 0; + while (cursor1.next() && (i < 2)) + { + i++; + str1 = cursor1.empno(); + str2 = cursor1.firstnme(); + String oneLine = " empno= " + str1 + " firstname= " + str2; + g.drawString(oneLine, 20, y); + y = y + 15; + } + cursor1.close(); + + // retrieve data from the database + y = y + 40; + g.drawString( + "Retrieve the number of rows in employee table...", 10, y); + #sql {SELECT count(*) INTO :count1 FROM employee}; + + y = y + 15; + if (1 == count1) + { + g.drawString( + "There is " + count1 + " row in employee table.", 10, y); + } + else + { + g.drawString( + "There are " + count1 + " rows in employee table.", 10, y); + } + + // update the database + y = y + 40; + g.drawString("Now, update the database...", 10, y); + #sql {UPDATE employee set firstnme = 'SHILI' where empno = '000010'}; + + // retrieve the updated data from the database + y = y + 40; + g.drawString( + "Retrieve the updated data from the database...", 10, y); + str1 = "000010"; + #sql cursor2 = {SELECT firstnme from employee where empno = :str1}; + + // display the result set + // cursor2.next() returns false when there are no more rows + y = y + 15; + g.drawString("Received results:", 10, y); + y = y + 25; + while (true) + { + #sql {FETCH :cursor2 INTO :str2}; + if (cursor2.endFetch()) break; + + String oneLine = " empno= " + str1 + " firstname= " + str2; + g.drawString(oneLine, 20, y); + y = y + 15; + } + cursor2.close(); + + // roll back the update + y = y + 40; + g.drawString("Now, roll back the update...", 10, y); + #sql {ROLLBACK work}; + y = y + 15; + g.drawString("Rollback done.", 10, y); + } + catch (Exception e) + { + e.printStackTrace(); + } + } +} // Applt + diff --git a/java/sqlj/Batch1Demo.sqlj b/java/sqlj/Batch1Demo.sqlj new file mode 100644 index 0000000..bd33c25 --- /dev/null +++ b/java/sqlj/Batch1Demo.sqlj @@ -0,0 +1,171 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Batch1Demo.sqlj +// +// SAMPLE: SQLJ batching -- How SQLJ batching works +// +// This sample program shows how batching works in SQLJ. +// If setBatching() is true and any non-batchable statements (e.g. +// SELECT) or batch incompatible statement (e.g. INSERT with 3 +// parameters) is encountered, SQLJ will implicitly execute the +// pending batch. +// +// This sample program uses the DataSource jdbc/DB2SimpleDataSource_ds1 +// from JNDI. The DataSource is registered using createRegisterDS.java +// and DS1.prop. Refer to the README file for details on how to run +// this sample. +// +// +// SQL Statements USED: +// SELECT +// +// Classes used from Util.sqlj are: +// Data +// +// OUTPUT FILE: Batch1Demo.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator bd1_simpleNameIter(int c1, String c2); +#sql context Batch1_Ctx with (dataSource="jdbc/DB2SimpleDataSource_ds1"); + +class Batch1Demo +{ + + static Batch1_Ctx ctx = null; + + public static void main(String argv[]) throws SQLException + { + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW BATCHING WORKS IN SQLJ. \n"); + + // Obtain Connection Context from DataSource jdbc/DB2SimpleDataSource_ds1 + ctx = new Batch1_Ctx(); + + try + { + // Shows how batching works in SQLJ + batchingInSQLJ(ctx); + cleanup(); + } + catch(Exception ex) + { + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + + ((java.sql.SQLException)(ex)).getErrorCode()); + System.out.println("error message: " + ex.getMessage()); + } + ex.printStackTrace(); + } + } + + + static void batchingInSQLJ( Batch1_Ctx ctx2 ) + { + try + { + ExecutionContext exCtx2 = ctx2.getExecutionContext(); + System.out.println(" Execution Contexts exCtx2 is created.\n"); + + exCtx2.setBatching(true); + System.out.println(" SetBatching() is set to true for exCtx2.\n"); + + exCtx2.setBatchLimit(2); + System.out.println( + " **************************************************\n" + + " ** Batch Limit is set to '2' rows for exCtx2. **\n" + + " **************************************************\n"); + + // Insert one row into the testing table Batch_Test1 + System.out.println(" Insert one row into the table Batch_test1: \n"); + + int index=1; + String col2 = "ACE"; + #sql [ctx2, exCtx2] { INSERT INTO Batch_Test1 VALUES(:index, :col2) }; + System.out.println( + " INSERT INTO Batch_Test1 VALUES(" + index + ", " + col2 + ")\n"); + + // Retrieve and display the data in the table Batch_Test1 + // NOTE: This will trigger implicit execute and updates will go through + // without executeBatch() + System.out.println( + " Display the content of the table Batch_Test1 by performing\n" + + " the following SQL statement in 'SQLJ':\n\n" + + " SELECT * from Batch_Test1\n"); + + bd1_simpleNameIter nameIter1 = null; + #sql [ctx2] nameIter1 = { SELECT * FROM Batch_Test1 }; + + System.out.println( + " Results:\n\n" + + " INDEX VALUE \n" + + " ------ -------- "); + + while (nameIter1.next()) + { + System.out.println(" "+Data.format(nameIter1.c1(),6)+ + " "+Data.format(nameIter1.c2(),8)); + System.out.println(""); + } + + System.out.println(""); + System.out.println( + " Note: The data we inserted in the table is returned without\n" + + " waiting for the second insert or explicit batch execute.\n" + + " Although the INSERT statement is a batch compatible \n" + + " statement but because the SQLJ SELECT is not batchable, \n" + + " an implicit batch execute has been triggered. \n"); + } + catch(Exception ex) + { + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + + ((java.sql.SQLException)(ex)).getErrorCode()); + System.out.println("error message: " + ex.getMessage()); + } + ex.printStackTrace(); + } + } + + private static void cleanup() throws SQLException + { + #sql [ctx] { DELETE FROM Batch_Test1 WHERE 1=1 }; + } +} diff --git a/java/sqlj/Batch2Demo.sqlj b/java/sqlj/Batch2Demo.sqlj new file mode 100644 index 0000000..e4c3e31 --- /dev/null +++ b/java/sqlj/Batch2Demo.sqlj @@ -0,0 +1,282 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Batch2Demo.sqlj +// +// SAMPLE: SQLJ batching - Association of ExecutionContext with BatchContext +// +// This sample program shows how batching works and the use of +// ExecutionContext with BatchContext. +// +// This sample program uses the DataSource jdbc/DB2SimpleDataSource_ds1 +// from JNDI. The DataSource is registered using createRegisterDS.java +// and DS1.prop. Refer to the README file for details on how to run +// this sample. +// +// SQL Statements USED: +// SELECT +// +// Classes used from Util.sqlj are: +// Data +// +// OUTPUT FILE: Batch2Demo.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator bd2_simpleNameIter(int c1, String c2); +#sql context Batch2_Ctx with (dataSource="jdbc/DB2SimpleDataSource_ds1"); + +class Batch2Demo +{ + + static Batch2_Ctx ctx1 = null; + + public static void main(String argv[]) throws SQLException + { + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW BATCHING WORKS WHILE USING \n" + + "ExecutionContext WITH BatchContext. \n"); + + // Obtain Connection Context from DataSource jdbc/DB2SimpleDataSource_ds1 + ctx1 = new Batch2_Ctx(); + + try + { + Statement stmt = null; + ResultSet rs = null; + Connection conn = null; + + // Create one Connection Context + conn = ctx1.getConnection(); + stmt = conn.createStatement(); + + conn = ctx1.getConnection(); + // Create two Execution Context + ExecutionContext exCtx1 = ctx1.getExecutionContext(); + ExecutionContext exCtx2 = ctx1.getExecutionContext(); + System.out.println(""); + System.out.println( + " Execution Context exCtx1 and exCtx2 are created.\n"); + + exCtx1.setBatching(true); + exCtx1.setBatchLimit(4); + + System.out.println(" SetBatching() is set to true.\n"); + + System.out.println(" Value returned from isBatching(): " + + exCtx1.isBatching() + "\n"); + + System.out.println( + " *******************************\n" + + " ** Batch Limit is set to 4 **\n" + + " *******************************\n"); + + bd2_simpleNameIter nameIter1 = null; + + // Insert some data into the testing table Batch_Test2 + System.out.println( + " Insert some data into the table Batch_test2 using host \n" + + " variables by performing the following SQL statement: \n\n" + + " INSERT INTO Batch_Test2 \n" + + " VALUES(:i, :col2, :col3)\n"); + + String col2 = ""; + String col3 = ""; + String s1 = "someVal"; + String s2 = "col3Val"; + int ret = 0; + + for (int i=1; i<=3; ++i) + { + col2=s1+i; + col3=s2+i; + #sql [ctx1, exCtx1] { INSERT INTO Batch_Test2 VALUES(:i, :col2, :col3) }; + System.out.println(" INSERT INTO Batch_Test2 VALUES(" + i + ", " + + col2 + ", " + col3 + ")"); + } + System.out.println(""); + + // Retrieve and display the data in the table Batch_Test1 + System.out.println( + " Display the content of the table Batch_Test1 by performing\n" + + " the following SQL statement in 'JDBC':\n\n" + + " SELECT * from Batch_Test2\n"); + + rs = stmt.executeQuery("SELECT * FROM Batch_Test2"); + + System.out.println( + " Results:\n\n" + + " INDEX COLUMN 2 COLUMN 3\n" + + " ------ --------- --------- "); + + int row=1; + while (rs.next()) + { + System.out.println(" "+Data.format(rs.getInt(1),6) + + " "+Data.format(rs.getString(2),8) + + " "+Data.format(rs.getString(2),8)); + System.out.println(""); + row++; + } + if (row == 1) + { + System.out.println(""); + System.out.println(" The table Batch_Test2 is empty with 0 rows.\n"); + } + + System.out.println( + " NOTE: \n" + + " Table Batch_Test2 should return no rows because no\n" + + " implicitly executed batch is obtained.\n"); + + // Reset Batch limit to 1 + exCtx1.setBatchLimit(1); + + System.out.println( + "----------------------------------------------------------\n\n" + + " *******************************\n" + + " ** Batch Limit is set to 1 **\n" + + " *******************************\n"); + + + System.out.println(" Perform the following SQL statement in SQLJ:\n"); + + int j = 1; + col2 = "newVal"; + #sql [ctx1, exCtx2] { INSERT INTO Batch_Test1 VALUES(:j, :col2) }; + System.out.println(" INSERT INTO Batch_Test1 VALUES(" + j + ", " + + col2 + ")\n"); + + // Display the content of the table Batch_Test1 + System.out.println( + " Display the content of the table Batch_Test1 by performing\n" + + " the following SQL statement in 'SQLJ':\n\n" + + " SELECT * FROM Batch_Test1\n"); + + #sql[ctx1, exCtx2] nameIter1 = { SELECT * FROM Batch_Test1 }; + + System.out.println( + " Results:\n\n" + + " INDEX COLUMN 2 \n" + + " ------ --------- "); + + while (nameIter1.next()) + { + System.out.println(" "+Data.format(nameIter1.c1(),6) + + " "+Data.format(nameIter1.c2(),8)); + } + System.out.println(""); + + System.out.println( + " NOTE: \n" + + " The above SELECT statement in SQLJ has created a new\n" + + " batch. The previous batch is then implicitly executed. \n"); + + // Get update counts + getCounts(exCtx1); + + // Retrieve and display table Batch_Test2 using JDBC to verify that + // it has 3 rows now + System.out.println( + "----------------------------------------------------------\n" + + " Display the content of the table Batch_Test2 by performing\n" + + " the following SQL statement in 'JDBC':\n\n" + + " SELECT * FROM Batch_Test2\n"); + + rs = stmt.executeQuery("SELECT * from Batch_Test2"); + + System.out.println( + " Results:\n\n" + + " INDEX COLUMN 2 COLUMN 3\n" + + " ------ --------- --------- "); + + row = 1; + while (rs.next()) + { + System.out.println(" "+Data.format(rs.getInt(1),6) + + " "+Data.format(rs.getString(2),8) + + " "+Data.format(rs.getString(2),8)); + System.out.println(""); + row++; + } + + System.out.println( + " NOTE: \n" + + " 3 rows should be returned from the above SELECT statement\n" + + " as an implicitly executed batch was obtained after the \n" + + " SELECT statement made in SQLJ.\n"); + + cleanup(); + } + catch(Exception ex) + { + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + + ((java.sql.SQLException)(ex)).getErrorCode()); + System.out.println("error message: " + ex.getMessage()); + } + ex.printStackTrace(); + } + } + + static void getCounts( ExecutionContext exeContext ) + { + int[] batchUpdateCount = exeContext.getBatchUpdateCounts(); + System.out.println(" Update Count Length: " + batchUpdateCount.length); + System.out.println(""); + + for (int i=0; i< batchUpdateCount.length; ++i) + { + System.out.println(" Update Count Value batchUpdateCount[" + i + "]: " + + batchUpdateCount[i] + "\n"); + } + + int ret = exeContext.getUpdateCount(); + if (ret == ExecutionContext.EXEC_BATCH_COUNT) + { + System.out.println(" BatchConstant returned : " + + "ExecutionContext.EXEC_BATCH_COUNT\n" ); + } + } + + private static void cleanup() throws SQLException + { + #sql [ctx1] { DELETE FROM Batch_Test1 WHERE 1=1 }; + #sql [ctx1] { DELETE FROM Batch_Test2 WHERE 1=1 }; + } +} diff --git a/java/sqlj/Batch3Demo.sqlj b/java/sqlj/Batch3Demo.sqlj new file mode 100644 index 0000000..e3006db --- /dev/null +++ b/java/sqlj/Batch3Demo.sqlj @@ -0,0 +1,212 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Batch3Demo.sqlj +// +// SAMPLE: SQLJ Batching - When do we need to implicitly execute a batch +// +// This sample shows that when you use a batching limit constant, +// for example, ExecutionContext.UNLIMITED_BATCH and +// ExecutionContext.AUTO_BATCH, you will have to do an explicit +// batch execution in SQLJ to execute the batch. +// +// In this program AUTO_BATCH has been set currently to 100, +// so implicit batch execution will trigger at 100th statement. + +// This sample program uses the DataSource jdbc/DB2SimpleDataSource_ds1 +// from JNDI. The DataSource is registered using createRegisterDS.java +// and DS1.prop. Refer to the README file for details on how to run +// this sample. +// +// SQL Statements USED: +// SELECT +// +// OUTPUT FILE: Batch3Demo.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + + +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql context Batch3_Ctx with (dataSource="jdbc/DB2SimpleDataSource_ds1"); + +class Batch3Demo +{ + + static Batch3_Ctx ctx1 = null; + + public static void main(String argv[]) throws SQLException + { + + // Obtain Connection Context from DataSource jdbc/DB2SimpleDataSource_ds1 + ctx1 = new Batch3_Ctx(); + + try + { + Statement stmt = null; + ResultSet rs = null; + Connection conn = null; + + conn = ctx1.getConnection(); + stmt = conn.createStatement(); + ExecutionContext exCtx1 = ctx1.getExecutionContext(); + System.out.println(""); + System.out.println(" Execution Context exCtx1 is created.\n"); + + // Set batch limit to 'unlimited' + exCtx1.setBatching(true); + exCtx1.setBatchLimit(ExecutionContext.UNLIMITED_BATCH); + + System.out.println( + " ***************************************************\n" + + " ** Batch Limit is set to 'unlimited' for exCtx1 **\n" + + " ***************************************************\n"); + + // Insert some data into the testing table Batch_Test2 + System.out.println( + " Insert some data into the table Batch_test2 using host \n" + + " variables by performing the following SQL statement \n" + + " 25 times:\n\n" + + " INSERT INTO Batch_Test2 \n" + + " VALUES(:i, :col2, :col3) }\n"); + + String col2 = ""; + String col3 = ""; + String s1 = "someVal"; + String s2 = "col3Val"; + + for (int i=1; i<=25; ++i) + { + col2=s1+i; + col3=s2+i; + #sql [ctx1] { INSERT INTO Batch_Test2 VALUES(:i, :col2, :col3) }; + System.out.println(" INSERT INTO Batch_Test2 VALUES(" + i + ", " + + col2 + ", " + col3 + ")"); + } + System.out.println (""); + + // Retrieve and display table Batch_Test2 using JDBC + System.out.println( + "----------------------------------------------------------\n" + + " Display the content of the table Batch_Test2 by performing\n" + + " the following SQL statement in 'JDBC':\n\n" + + " SELECT * FROM Batch_Test2\n"); + + rs = stmt.executeQuery("SELECT * from Batch_Test2"); + + displayTableContent(rs); + + System.out.println(""); + System.out.println( + " Note: Since we have set batch limit to the constant \n" + + " UNLIMITED_BATCH, an explicit batch execute is needed \n" + + " to execute the batch.\n"); + + // Check Batch Update Counts + int[] batchUpdateCount = exCtx1.executeBatch(); + System.out.println(" Executed batch explicitly.\n"); + + batchUpdateCount = exCtx1.getBatchUpdateCounts(); + System.out.println (" Batch update Count Length: " + + batchUpdateCount.length + "\n"); + + // Retrieve and display table Batch_Test2 using JDBC to verify that + // it has 25 rows now + System.out.println( + "----------------------------------------------------------\n" + + " After an explicit batch execution... \n\n" + + " Display the content of the table Batch_Test2 by performing\n" + + " the following SQL statement in 'JDBC':\n\n" + + " SELECT * FROM Batch_Test2\n"); + + rs = stmt.executeQuery("SELECT * from Batch_Test2"); + + displayTableContent(rs); + + System.out.println(""); + cleanup(); + } + catch(Exception ex) + { + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + + ((java.sql.SQLException)(ex)).getErrorCode()); + System.out.println("error message: " + ex.getMessage()); + } + ex.printStackTrace(); + } + } + + static void displayTableContent(ResultSet rs) + { + try + { + System.out.println( + " Results:\n\n" + + " INDEX COLUMN 2 COLUMN 3\n" + + " ------ --------- --------- "); + + int row=1; + while (rs.next()) + { + System.out.println(" "+Data.format(rs.getInt(1),6) + + " "+Data.format(rs.getString(2),9) + + " "+Data.format(rs.getString(2),9)); + row++; + } + if (row == 1) + { + System.out.println(""); + System.out.println(" The table Batch_Test2 is empty with 0 rows.\n"); + } + } + catch(Exception ex) + { + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + + ((java.sql.SQLException)(ex)).getErrorCode()); + System.out.println("error message: " + ex.getMessage()); + } + ex.printStackTrace(); + } + } + + private static void cleanup() throws SQLException + { + #sql [ctx1] { DELETE FROM Batch_Test1 WHERE 1=1 }; + #sql [ctx1] { DELETE FROM Batch_Test2 WHERE 1=1 }; + } +} diff --git a/java/sqlj/BlobClobDemo.sqlj b/java/sqlj/BlobClobDemo.sqlj new file mode 100644 index 0000000..63e65e2 --- /dev/null +++ b/java/sqlj/BlobClobDemo.sqlj @@ -0,0 +1,168 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: BlobClobDemo.sqlj +// +// SAMPLE: How to access Blob or Clob fields in DB2 tables +// +// This sample program shows how to access Blob or Clob fields in +// DB2 tables. To access LOBs in S/390 DB2, additional auxilaiary +// tables and indexes need to be created on server side. +// +// This sample program uses the DataSource jdbc/DB2SimpleDataSource_ds1 +// from JNDI. The DataSource is registered using createRegisterDS.java +// and DS1.prop. Refer to the README file for details on how to run +// this sample. +// +// +// SQL Statements USED: +// SELECT +// +// Classes used from Util.sqlj are: +// Data +// +// OUTPUT FILE: BlobClobDemo.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + + +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql context BlobClobCtx with (dataSource="jdbc/DB2SimpleDataSource_ds1"); + +class BlobClobDemo +{ + #sql public iterator lobIter(int id, java.sql.Blob blobcol, + java.sql.Clob clobcol); + + public static void main(String argv[]) + { + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO ACCESS BLOB OR BLOB FIELDS IN DB2 TABLES.\n"); + + BlobClobDemo bc_o = new BlobClobDemo(); + try + { + bc_o.runThis(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + static BlobClobCtx ctx1 = null; + + public void runThis() throws SQLException + { + // Obtain Connection Context from DataSource jdbc/DB2SimpleDataSource_ds1 + ctx1 = new BlobClobCtx(); + + Connection conn = ctx1.getConnection(); + conn.setAutoCommit(false); + + try + { + lobIter n1 = null; + int col1 = 0; + Blob blob = null; + Clob clob = null; + int id1 = 100; + byte[] blobval1 = {(byte)0x0a, (byte)0x0b, (byte)0x0c}; + String clobval1 = "Clob Text1"; + int id2 = 200; + byte[] blobval2 = {(byte)0x0d, (byte)0x0e, (byte)0x0f}; + String clobval2 = "Clob Text2"; + System.out.println(" Insert 2 rows into the table BlobClob_Tab. \n"); + + #sql { INSERT INTO BlobClob_Tab(id, blobcol, clobcol) + VALUES( :id1, :blobval1, :clobval1 ) }; + System.out.println( + " INSERT INTO BlobClob_Tab(id, blobcol, clobcol)\n"+ + " VALUES ( :id1, :blobval1, :clobval1 )\n"); + + #sql { INSERT INTO BlobClob_Tab(id, blobcol, clobcol) + VALUES( :id2, :blobval2, :clobval2 ) }; + System.out.println( + " INSERT INTO BlobClob_Tab(id, blobcol, clobcol) \n"+ + " VALUES ( :id2, :blobval2, :clobval2 )\n"); + + System.out.println (" Now Fetch From BlobClobTab.\n"); + #sql n1 = { select id, blobcol, clobcol from BlobClob_Tab }; + System.out.println(" SELECT id, blobcol, clobcol FROM BlobClob_Tab\n"); + + String clob_str = null; + Clob temp_clob = null; + Blob temp_blob = null; + + while (n1.next()) + { + temp_clob = n1.clobcol(); + temp_blob = n1.blobcol(); + byte[] barr = temp_blob.getBytes(1,(int)temp_blob.length()); + clob_str = temp_clob.getSubString(1,(int)temp_clob.length()); + System.out.print(" ID = " + n1.id() + ", Clob Value = " + + clob_str + ", Blob Value: "); + for (int i=0; i 11 || + ( argv.length == 1 && + ( argv[0].equals( "?" ) || + argv[0].equals( "-?" ) || + argv[0].equals( "/?" ) || + argv[0].equalsIgnoreCase( "-h" ) || + argv[0].equalsIgnoreCase( "/h" ) || + argv[0].equalsIgnoreCase( "-help" ) || + argv[0].equalsIgnoreCase( "/help" ) ) ) ) + { + throwUsageException(); + } + + // Initialize default database names + db1.alias = "sample"; + db1.server = ""; + db1.portNumber = -1; + db1.userId = ""; + db1.password = ""; + + db2.alias = "sample2"; + db2.server = ""; + db2.portNumber = -1; + db2.userId = ""; + db2.password = ""; + + switch (argv.length) { + case 0: // Use type 2 driver + break; + + case 1: + db1.alias = argv[0]; + break; + + case 2: + // Use type 2 driver with userid/password specified + db1.userId = argv[0]; + db1.password = argv[1]; + break; + + case 3: + // Use type 2 driver with dbname/userid/password specified + db1.alias = argv[0]; + db1.userId = argv[1]; + db1.password = argv[2]; + break; + + case 11: + // Universal type 4 driver + + db1.alias = argv[1]; + db1.server = argv[2]; + db1.portNumber = Integer.valueOf( argv[3] ).intValue(); + db1.userId = argv[4]; + db1.password = argv[5]; + + db2.alias = argv[6]; + db2.server = argv[7]; + db2.portNumber = Integer.valueOf( argv[8] ).intValue(); + db2.userId = argv[9]; + db2.password = argv[10]; + break; + + default: //throw exception + throwUsageException(); + break; + } + + } // setup + + private static void throwUsageException() throws Exception + { + throw new Exception( + "\n" + + "Usage: prog_name [\"connection 1 information\" [\"connection 2 information\"]]\n" + + "\n" + + " where \"connection N information\" is:\n" + + "\n" + + " [dbAlias] [userId passwd] (use JDBC Universal type 2 driver)\n" + + " -u4 [dbAlias] server portNum userId passwd (use JDBC type 4 driver)\n" + + "\n" + + " dbAlias defaults to 'sample' for connection 1 and 'sample2' for connection 2" ); + } + + private static void createTable( MyContext ctx ) + { + System.out.println(); + System.out.println( + " CREATE TABLE books(title VARCHAR(21), price DECIMAL(7, 2))\n"); + + try + { + #sql [ctx] {CREATE TABLE books(title VARCHAR(21), price DECIMAL(7, 2))}; + + System.out.println(" COMMIT\n"); + #sql [ctx] {COMMIT}; + } + catch (Exception e) + { + System.out.println(e); + } + } // createTable + + private static void dropTable( MyContext ctx ) + { + System.out.println(" DROP TABLE books\n"); + + try + { + #sql [ctx] {DROP TABLE books}; + + System.out.println(" COMMIT\n"); + #sql [ctx] {COMMIT}; + } + catch (Exception e) + { + System.out.println(e); + } + } // dropTable + +} // DbMCon diff --git a/java/sqlj/DbUse.sqlj b/java/sqlj/DbUse.sqlj new file mode 100644 index 0000000..db2a901 --- /dev/null +++ b/java/sqlj/DbUse.sqlj @@ -0,0 +1,168 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DbUse.sqlj +// +// SAMPLE: How to use a database +// +// SQL Statements USED: +// CREATE TABLE +// DROP TABLE +// DELETE +// COMMIT +// ROLLBACK +// +// Classes used from Util.sqlj are: +// Db +// +// OUTPUT FILE: DbUse.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class DbUse +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO USE A DATABASE."); + + // connect to the 'sample' database + db.getDefaultContext(); + + StaticStmtInvoke(); + StaticStmtInvokeWithHostVars(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + System.out.println(e); + } + } // main + + static void StaticStmtInvoke() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " DROP TABLE\n" + + "TO SHOW HOW TO INVOKE SQL STATEMENTS."); + + // create a table + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " CREATE TABLE table1(col1 INTEGER)"); + + #sql {CREATE TABLE table1(col1 INTEGER)}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + + // drop a table + System.out.println(); + System.out.println(" Invoke the statement:\n" + + " DROP TABLE table1"); + + #sql {DROP TABLE table1}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + System.out.println(e); + } + } // StaticStmtInvoke + + static void StaticStmtInvokeWithHostVars() + { + try + { + int hostVar1; + String hostVar2; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DELETE\n" + + " ROLLBACK\n" + + "TO SHOW HOW TO USE HOST VARIABLES."); + + // execute a statement with host variables + System.out.println(); + System.out.println( + " Execute:\n" + + " DELETE FROM org\n" + + " WHERE deptnumb = :hostVar1\n" + + " AND division = :hostVar2\n" + + " for\n" + + " hostVar1 = 15\n" + + " hostVar2 = 'Eastern'"); + + hostVar1 = 15; + hostVar2 = "Eastern"; + + #sql {DELETE FROM org + WHERE deptnumb = :hostVar1 AND + division = :hostVar2}; + + // rollback the transaction + System.out.println(); + System.out.println(" Rollback the transaction."); + #sql {ROLLBACK}; + } + catch (Exception e) + { + System.out.println(e); + } + } // StaticStmtInvokeWithHostVars +} // DbUse + diff --git a/java/sqlj/DtUdt.sqlj b/java/sqlj/DtUdt.sqlj new file mode 100644 index 0000000..ad1fc1f --- /dev/null +++ b/java/sqlj/DtUdt.sqlj @@ -0,0 +1,250 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: DtUdt.sqlj +// +// SAMPLE: How to create, use and drop user defined distinct types +// +// SQL statements USED: +// CREATE DISTINCT TYPE +// CREATE TABLE +// DROP DISTINCT TYPE +// DROP TABLE +// INSERT +// COMMIT +// +// Classes used from Util.sqlj are: +// Db +// SqljException +// +// OUTPUT FILE: DtUdt.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class DtUdt +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO CREATE, USE AND DROP\n" + + "USER DEFINED DISTINCT TYPES."); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + create(); + use( ctx.getConnection() ); + drop(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // This function creates a few user defined distinct types + static void create() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE DISTINCT TYPE\n" + + " COMMIT\n" + + "TO CREATE UDTs."); + + System.out.println(); + System.out.println( + " CREATE DISTINCT TYPE udt1 AS INTEGER WITH COMPARISONS"); + + #sql {CREATE DISTINCT TYPE udt1 AS INTEGER WITH COMPARISONS}; + + System.out.println( + " CREATE DISTINCT TYPE udt2 AS CHAR(2) WITH COMPARISONS"); + + #sql {CREATE DISTINCT TYPE udt2 AS CHAR(2) WITH COMPARISONS}; + + System.out.println( + " CREATE DISTINCT TYPE udt3 AS DECIMAL(7, 2) WITH COMPARISONS"); + + #sql {CREATE DISTINCT TYPE udt3 AS DECIMAL(7, 2) WITH COMPARISONS}; + + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // create + + // This function uses the user defined distinct types that we created + // at the beginning of this program. + static void use(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " EXECUTE IMMEDIATE\n" + + " COMMIT\n" + + "TO USE UTDs."); + + // create udt_table + try + { + String strStmt; + System.out.println(); + System.out.println( + " CREATE TABLE udt_table(col1 udt1, col2 udt2, col3 udt3)"); + + strStmt = "CREATE TABLE udt_table(col1 udt1, col2 udt2, col3 udt3)"; + Statement stmt = con.createStatement(); + stmt.execute(strStmt); + + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // insert udt_table + try + { + String strStmt; + System.out.println(); + System.out.println( + " INSERT INTO udt_table \n" + + " VALUES(CAST(77 AS udt1),\n" + + " CAST('ab' AS udt2),\n" + + " CAST(111.77 AS udt3))"); + + strStmt = "INSERT INTO udt_table VALUES (CAST(77 AS udt1), " + + " CAST('ab' AS udt2), " + + " CAST(111.77 AS udt3))"; + Statement stmt = con.createStatement(); + stmt.execute(strStmt); + + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop udt_table + try + { + String strStmt; + System.out.println(); + System.out.println(" DROP TABLE udt_table"); + + strStmt = "DROP TABLE udt_table "; + Statement stmt = con.createStatement(); + stmt.execute(strStmt); + + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // use + + // This function drops all of the user defined distinct types that + // we created at the beginning of this program + static void drop() + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DROP\n" + + " COMMIT\n" + + "TO DROP UDTs."); + + try + { + System.out.println(); + System.out.println(" DROP USER DISTINCT TYPE udt1"); + + #sql {DROP DISTINCT TYPE udt1}; + + System.out.println(" DROP USER DISTINCT TYPE udt2"); + + #sql {DROP DISTINCT TYPE udt2}; + + System.out.println(" DROP USER DISTINCT TYPE udt3"); + + #sql {DROP DISTINCT TYPE udt3}; + + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // drop +} // DtUdt + diff --git a/java/sqlj/GeneratePayroll.sqlj b/java/sqlj/GeneratePayroll.sqlj new file mode 100644 index 0000000..c69829d --- /dev/null +++ b/java/sqlj/GeneratePayroll.sqlj @@ -0,0 +1,367 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: GeneratePayroll.sqlj +// +// SAMPLE: Geneate payroll reports by department +// +// SQL Statements USED: +// SELECT +// +// Classes used from Util.sqlj are: +// Db +// SqljException +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.io.*; +import java.sql.*; +import java.util.Vector; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + + +#sql iterator EmployeeInfo(String, String, String, String, String, String, String, String); +#sql iterator DepartNum(String); + +class GeneratePayroll +{ + public static void main(String argv[]) + { + String workdept=null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE GENERATES THE PAYROLL REPORTS BY DEPARTMENT."); + + // connect to the 'sample' database + db.getDefaultContext(); + + // list all department numbers in the database + listDepart(); + + // get the Department number that user enters. + workdept = getDepartNum("Please enter the department number:"); + + Vector employeelist = new Vector(); + + payrollReport(workdept, employeelist); + + Object[] temp = employeelist.toArray(); + Payroll[] pl = new Payroll[temp.length]; + + for(int i = 0; i < temp.length; i++) + { + pl[i] = (Payroll)employeelist.get(i); + } + + // print the payroll report + printReport(pl); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + + static void printReport(Payroll[] pl) + { + EmployeeInfo results; + String empno = null; + String firstnme = null; + String midinit = null; + String lastname = null; + String workdept = null; + String salary = null; + String bonus = null; + String comm = null; + + + for(int i = 0; i < pl.length; i++) + { + empno = pl[i].getEmpno(); + firstnme = pl[i].getFirstnme(); + midinit = pl[i].getMidinit(); + lastname = pl[i].getLastname(); + workdept = pl[i].getWorkdept(); + salary = pl[i].getSalary(); + bonus = pl[i].getBonus(); + comm = pl[i].getComm(); + + System.out.println("Payroll report\n "); + System.out.println("----------------------------------------------------\n "); + System.out.println("Employee Id: " + empno + "\n"); + System.out.println("Employee name: " + firstnme + " " + midinit + " " + lastname + "\n"); + System.out.println("Department: " + workdept + "\n"); + System.out.println("Payment: " + salary + "\n"); + System.out.println("Bonus: " + bonus + "\n"); + System.out.println("Commission: " + comm + "\n"); + System.out.println("----------------------------------------------------\n "); + } + + } //printReport + + + static void payrollReport(String department, Vector employeelist) + { + EmployeeInfo results; + String empno = null; + String firstnme = null; + String midinit = null; + String lastname = null; + String workdept = null; + String salary = null; + String bonus = null; + String comm = null; + + try + { + System.out.println(); + + #sql results={SELECT empno, firstnme, midinit, lastname, workdept, salary, bonus, comm FROM EMPLOYEE WHERE workdept=:department}; + + while (true) + { + + #sql {FETCH :results INTO :empno, :firstnme, :midinit, :lastname, + :workdept,:salary, :bonus, :comm}; + + if (results.endFetch()) + { + break; + } + + Payroll user = new Payroll(); + user.setEmpno(empno); + user.setFirstnme(firstnme); + user.setMidinit(midinit); + user.setLastname(lastname); + user.setWorkdept(workdept); + user.setSalary(salary); + user.setBonus(bonus); + user.setComm(comm); + + employeelist.add(user); + } + + results.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + } + // employeeAdd + + + static String getDepartNum(String text) + { + // prompt the user to enter information + System.out.print(text); + + // open up standard input + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + + String data = null; + + try { + data = br.readLine(); + } + catch (IOException ioe) { + System.out.println("IO error trying to read input!"); + System.exit(1); + } + return data; + } + + + static void listDepart() + { + DepartNum results; + String department = null; + try + { + System.out.println(); + System.out.println("Department"); + System.out.println("----------"); + + #sql results={SELECT distinct workdept FROM EMPLOYEE}; + + while (true) + { + #sql {FETCH :results INTO :department}; + + if (results.endFetch()) + { + break; + } + + System.out.println(department); + } + + System.out.println("----------"); + System.out.println(); + + results.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + } + +//CreateEmployee +} + +class Payroll +{ + + private String empno=null; + private String firstnme=null; + private String midinit=null; + private String lastname=null; + private String workdept=null; + private String phoneno=null; + private String hiredate=null; + private String job=null; + private String edlevel=null; + private String sex=null; + private String birthdate=null; + private String salary=null; + private String bonus=null; + private String comm=null; + +//--------set method---------------- + + public void setEmpno(String empno) { + this.empno = empno; + } + public void setFirstnme(String firstnme) { + this.firstnme = firstnme; + } + public void setMidinit(String midinit) { + this.midinit = midinit; + } + public void setLastname(String lastname) { + this.lastname = lastname; + } + public void setWorkdept(String workdept) { + this.workdept = workdept; + } + public void setPhoneno(String phoneno) { + this.phoneno = phoneno; + } + public void setHiredate(String hiredate) { + this.hiredate = hiredate; + } + public void setJob(String job) { + this.job = job; + } + public void setEdlevel(String edlevel) { + this.edlevel = edlevel; + } + public void setSex(String sex) { + this.sex = sex; + } + public void setBirthdate(String birthdate) { + this.birthdate = birthdate; + } + public void setSalary(String salary) { + this.salary = salary; + } + public void setBonus(String bonus) { + this.bonus = bonus; + } + public void setComm(String comm) { + this.comm = comm; + } + +//-----------get method ----------------- + + public String getEmpno() { + return empno; + } + public String getFirstnme() { + return firstnme; + } + public String getMidinit() { + return midinit; + } + public String getLastname() { + return lastname; + } + public String getWorkdept() { + return workdept; + } + public String getPhoneno() { + return phoneno; + } + public String getHiredate() { + return hiredate; + } + public String getJob() { + return job; + } + public String getEdlevel() { + return edlevel; + } + public String getSex() { + return sex; + } + public String getBirthdate() { + return birthdate; + } + public String getSalary() { + return salary; + } + public String getBonus() { + return bonus; + } + public String getComm() { + return comm; + } + +//payroll +} diff --git a/java/sqlj/LargeRid.sqlj b/java/sqlj/LargeRid.sqlj new file mode 100644 index 0000000..a7592ac --- /dev/null +++ b/java/sqlj/LargeRid.sqlj @@ -0,0 +1,399 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: LargeRid.sqlj +// +// SAMPLE: How to enable Large RIDs support on both new tables/tablespaces +// and existing tables/tablespaces. +// +// SQL Statements USED: +// ALTER TABLESPACE +// INSERT +// REORG +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// +// Classes used from Util.sqlj are: +// Db +// Data +// SqljException +// +// PREQUISITES : 1. Create the pre-requisite tablespaces and tables by running the command: +// LargeRidScrpt +// Alternatively,you can run the command: +// db2 -tvf LargeRid_setup.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj LargeRid +// 2. Run the sample as: +// java LargeRid +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf LargeRid_cleanup.db2 +// +// OUTPUT FILE: LargeRid.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator LargeRid_Cursor(int); + +class LargeRid +{ + + public static void main(String argv[]) + { + try + { + String userId; + Connection con = null; + DefaultContext ctx; + + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + ctx = new DefaultContext(con); + DefaultContext.setDefaultContext(ctx); + + userId = argv[0]; + System.out.println( + "THIS SAMPLE SHOWS HOW TO ENABLE LARGE RID SUPPORT ON TABLES AND\n" + + " TABLESPACES\n"); + + System.out.println( + "\nDMS tablespaces dms_tspace, dms_tspace1, dms_tspace2 \n" + + "and dms_tspace3 have been created using the setup script \n" + + "LargeRid_setup.db2 \n"); + + System.out.println + ("\n************************************************************\n"); + System.out.println + ("THE FOLLOWING SCENARIO SHOWS HOW TO ENABLE LARGE RID SUPPORT"); + System.out.println(" FOR A NON-PARTITIONED TABLE\n"); + System.out.println + ("************************************************************"); + + System.out.println( + "\nThe table 'large' is created in the DMS tablespace 'dms_tspace' \n" + + "in the setup script LargeRid_setup.db2 using the command \n" + + "'CREATE TABLE large (max INT, min INT) IN dms_tspace' \n"); + + System.out.println( + "\nAn index called 'large_ind' on the table 'large' is created \n" + + "in the setup script LargeRid_setup.db2 using the command \n" + + "'CREATE INDEX large_ind ON large (max)' \n"); + + tbAlterSpace(); + reorgIndex(); + + System.out.println + ("\n************************************************************\n"); + System.out.println + ("THE FOLLOWING SCENARIO SHOWS HOW TO ENABLE LARGE RID SUPPORT"); + System.out.println + (" FOR A PARTITIONED TABLE\n"); + System.out.println + ("************************************************************"); + + System.out.println( + "\nA partitioned table called 'large_ptab' is created in \n" + + "DMS tablespace i.e; part1 is placed at dms_tspace1, part2\n" + + "is placed at dms_tspace2 and part3 at dms_tspace3, \n" + + "using the setup script LargeRid_setup.db2 with the command \n" + + "\n'CREATE TABLE large_ptab (max SMALLINT NOT NULL, \n" + + " CONSTRAINT CC CHECK (max>0)) \n" + + " PARTITION BY RANGE (max) \n" + + " (PART part1 STARTING FROM (1) ENDING (3) IN dms_tspace1, \n" + + " PART part2 STARTING FROM (4) ENDING (6) IN dms_tspace2, \n" + + " PART part3 STARTING FROM (7) ENDING (9) IN dms_tspace3)' \n"); + + insertData(); + tbDetachPartition(con, userId); + convertTbSpace(); + tbReorganize(); + tbAttachPartition(); + + con.close(); + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // Changes table space from regular to large. + static void tbAlterSpace() throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLESPACE \n" + + "TO ALTER A TABLESPACE \n" + + "\n Perform:\n" + + " ALTER TABLESPACE dms_tspace CONVERT TO LARGE"); + + // convert regular DMS tablespace 'dms_tspace' to large DMS tablespace + #sql {ALTER TABLESPACE dms_tspace CONVERT TO LARGE}; + + #sql {COMMIT}; + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // tbAlterSpace + + // Reorganize indexes defined on a table. + static void reorgIndex() throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " REORG INDEXES \n" + + "TO REORG INDEXES FOR A TABLE \n" + + "\n Perform:\n" + + " REORG INDEXES ALL FOR TABLE large"); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + #sql {CALL SYSPROC.ADMIN_CMD('REORG INDEXES ALL FOR TABLE large')}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // reorgIndex + + // Insert data into the table. + static void insertData() throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " INSERT INTO \n" + + "TO INSERT DATA IN A TABLE \n" + + "\n Perform:\n" + + " INSERT INTO large_ptab VALUES (1), (2), (3),\n" + + " (4), (5), (6),\n" + + " (7), (8), (9)"); + + // insert data into the table + #sql {INSERT INTO large_ptab VALUES (1), (2), (3), + (4), (5), (6), + (7), (8), (9)}; + + #sql {COMMIT}; + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // insertData + + // If a partitioned table has data partitions in different regular DMS + // tablespaces, then the tablespaces cannot be converted to large + // with the current definition. + // To do this, first detach all the partitions of the table, later + // convert all the tablespaces to large, reorg all the detached + // partitions to support large RID. Finally, reattach the partitions. + // Now the entire table supports large RIDs. + + // Remove partition from a partitioned table. + static void tbDetachPartition(Connection con, String userId) throws SQLException + { + try + { + CallableStatement callStmt1 = null; + + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLE \n" + + "TO DETACH THE PARTITIONS \n" + + "\n Perform:\n" + + " ALTER TABLE large_ptab\n" + + " DETACH PARTITION PART3\n" + + " INTO TABLE detach_part3\n\n" + + " ALTER TABLE large_ptab\n" + + " DETACH PARTITION PART3\n" + + " INTO TABLE detach_part2"); + + // detach partitions from base table into some temporary tables + #sql {ALTER TABLE large_ptab + DETACH PARTITION part3 INTO TABLE detach_part3}; + #sql {COMMIT}; + String sql1 = "CALL waitForDetach(?, ?, 'LARGE_PTAB')"; + callStmt1 = con.prepareCall(sql1); + callStmt1.registerOutParameter(1, java.sql.Types.VARCHAR, 30); + callStmt1.setString(2, userId); + callStmt1.execute(); + #sql{COMMIT}; + + #sql {ALTER TABLE large_ptab + DETACH PARTITION part2 INTO TABLE detach_part2}; + #sql {COMMIT}; + String sql = "CALL waitForDetach(?, ?, 'LARGE_PTAB')"; + callStmt1 = con.prepareCall(sql); + callStmt1.registerOutParameter(1, java.sql.Types.VARCHAR, 30); + callStmt1.setString(2, userId); + callStmt1.execute(); + #sql{COMMIT}; + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // tbDetachPartition + + // Changes table space from regular to large. + static void convertTbSpace() throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLE \n" + + "TO DETACH THE PARTITIONS \n" + + "\n Perform:\n" + + " ALTER TABLESPACE dms_tspace1 CONVERT TO LARGE\n" + + " ALTER TABLESPACE dms_tspace2 CONVERT TO LARGE\n" + + " ALTER TABLESPACE dms_tspace3 CONVERT TO LARGE"); + + // convert regular DMS tablespaces to large DMS tablespaces + #sql {ALTER TABLESPACE dms_tspace3 CONVERT TO LARGE}; + #sql {ALTER TABLESPACE dms_tspace2 CONVERT TO LARGE}; + #sql {ALTER TABLESPACE dms_tspace1 CONVERT TO LARGE}; + + #sql {COMMIT}; + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // convertTbSpace + + // Reorganize table. + static void tbReorganize() throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " REORG TABLE \n" + + "TO REORG THE DETACHED PARTITIONS \n" + + "\n Perform:\n" + + " REORG TABLE large_ptab ALLOW NO ACCESS\n" + + " REORG TABLE detach_part2 ALLOW NO ACCESS\n" + + " REORG TABLE detach_part3 ALLOW NO ACCESS"); + + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + #sql {CALL SYSPROC.ADMIN_CMD('REORG TABLE large_ptab ALLOW NO ACCESS')}; + #sql {CALL SYSPROC.ADMIN_CMD('REORG TABLE detach_part2 ALLOW NO ACCESS')}; + #sql {CALL SYSPROC.ADMIN_CMD('REORG TABLE detach_part3 ALLOW NO ACCESS')}; + + #sql {COMMIT}; + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // tbReorganize + + // Add partition to a partitioned table. + static void tbAttachPartition() throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " REORG TABLE \n" + + "TO REORG THE DETACHED PARTITIONS \n" + + "\n Perform:\n" + + " ALTER TABLE large_ptab\n" + + " ATTACH PARTITION part2\n" + + " STARTING FROM (4) ENDING (6)\n" + + " FROM TABLE detach_part2\n\n" + + " ALTER TABLE large_ptab\n" + + " ATTACH PARTITION part2\n" + + " STARTING FROM (7) ENDING (9)\n" + + " FROM TABLE detach_part3"); + + // reattach the reorganized detached partitions for table to support + // large RIDs. + #sql {ALTER TABLE large_ptab + ATTACH PARTITION part2 STARTING FROM (4) ENDING (6) FROM TABLE detach_part2}; + + + #sql {ALTER TABLE large_ptab + ATTACH PARTITION part3 STARTING FROM (7) ENDING (9) FROM TABLE detach_part3}; + + #sql {COMMIT}; + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // tbattachPartition + +} diff --git a/java/sqlj/LargeRidScrpt b/java/sqlj/LargeRidScrpt new file mode 100644 index 0000000..f9193d0 --- /dev/null +++ b/java/sqlj/LargeRidScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: LargeRidScrpt +# LargeRid_cleanup.db2 drops tables created by LargeRid_setup.db2 for the +# sample LargeRid.sqlj +# LargeRid_setup.db2 creates tables necessary for execution of the sample +# LargeRid.sqlj +# Both CLP scripts can be run on their own +# Usage: LargeRidScrpt + +db2 -tvf LargeRid_cleanup.db2 +db2 -td@ -vf LargeRid_setup.db2 diff --git a/java/sqlj/LargeRid_cleanup.db2 b/java/sqlj/LargeRid_cleanup.db2 new file mode 100644 index 0000000..65c44af --- /dev/null +++ b/java/sqlj/LargeRid_cleanup.db2 @@ -0,0 +1,64 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: LargeRid_cleanup.db2 +-- +-- SAMPLE: Cleanup script for the sample LargeRid.sqlj +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf LargeRid_cleanup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +---------------------------------------------------------------------------- + +connect to sample; + +-- Drop indexes defined on a table + +DROP INDEX large_ind; + +-- Drop tables + +DROP TABLE large; +DROP TABLE large_ptab; + +-- Drop tablespaces + +DROP TABLESPACE dms_tspace; +DROP TABLESPACE dms_tspace1; +DROP TABLESPACE dms_tspace2; +DROP TABLESPACE dms_tspace3; + +drop procedure waitForDetach; +drop procedure tableExists; + +connect reset; diff --git a/java/sqlj/LargeRid_setup.db2 b/java/sqlj/LargeRid_setup.db2 new file mode 100644 index 0000000..b243a81 --- /dev/null +++ b/java/sqlj/LargeRid_setup.db2 @@ -0,0 +1,173 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: LargeRid_setup.db2 +-- +-- SAMPLE: This sample serves as the setup script for the sample +-- LargeRid.sqlj +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf LargeRid_setup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad + +---------------------------------------------------------------------------- + +connect to sample@ + +-- create regular DMS table space dms_tspace + +CREATE REGULAR TABLESPACE dms_tspace + MANAGED BY DATABASE + USING (FILE 'dms_cont.dat' 10000)@ + +-- create regular DMS table space dms_tspace1 + +CREATE REGULAR TABLESPACE dms_tspace1 + MANAGED BY DATABASE + USING (FILE 'dms_cont1.dat' 10000)@ + +-- create regular DMS table space dms_tspace2 + +CREATE REGULAR TABLESPACE dms_tspace2 + MANAGED BY DATABASE + USING (FILE 'dms_cont2.dat' 10000)@ + +-- create regular DMS table space dms_tspace3 + +CREATE REGULAR TABLESPACE dms_tspace3 + MANAGED BY DATABASE + USING (FILE 'dms_cont3.dat' 10000)@ + +-- create table in 'dms_tspace' regular DMS tablespace + +CREATE TABLE large (max INT, min INT) IN dms_tspace@ + +-- create index + +CREATE INDEX large_ind ON large (max)@ + +-- create a partitioned table in regular DMS tablespaces i.e; part1 is +-- placed at dms_tspace1, part2 is placed at dms_tspace2 and +-- part3 at dms_tspace3 + +CREATE TABLE large_ptab (max SMALLINT NOT NULL, + CONSTRAINT CC CHECK (max>0)) + PARTITION BY RANGE (max) + (PART part1 STARTING FROM (1) ENDING (3) IN dms_tspace1, + PART part2 STARTING FROM (4) ENDING (6) IN dms_tspace2, + PART part3 STARTING FROM (7) ENDING (9) IN dms_tspace3)@ + + +create procedure tableExists (IN schemaName varchar(128), IN tableName varchar(128), OUT notFound int) + specific tableExists + language SQL +BEGIN + + declare dpid int; + + declare tabCheck cursor for + select DATAPARTITIONID from sysibm.sysdatapartitions where tabschema = schemaName and tabname = tableName; + declare exit handler for NOT FOUND + set notFound = 1; + + open tabCheck; + fetch tabCheck into dpid; + close tabCheck; + +END@ + +create procedure waitForDetach (OUT msg varchar(128), IN schemaName varchar(128), IN tableName varchar(128), IN partName varchar(128) DEFAULT NULL) + specific waitForDetach + language SQL +BEGIN + + declare dpid int; + declare dpstate char; + declare done int default 0; + declare tabNotFound int default 0; + + declare allDetachCheck cursor for + select DATAPARTITIONID, STATUS from sysibm.sysdatapartitions + where tabschema = schemaName and tabname = tableName and (status = 'L' OR status = 'D'); + + declare oneDetachCheck cursor for + select DATAPARTITIONID, STATUS from sysibm.sysdatapartitions + where tabschema = schemaName and tabname = tableName and datapartitionname = partName; + + declare continue handler for NOT FOUND + set done = 1; + + set current lock timeout 120; + + -- if table does not exist in sysdatapartitions, return error + call tableExists (schemaName, tableName, tabNotFound); + if tabNotFound = 1 + THEN + set msg = 'Table not found'; + RETURN -1; + END IF; + +wait_loop: + LOOP + if partName IS NOT NULL + THEN + open oneDetachCheck; + fetch oneDetachCheck into dpid, dpstate; + + -- two cases here: + -- (i) detach has already completed hence partition entry not found in catalogs (indicated by done == 1, handled later) + -- (ii) detach in progress, partition state should not be visible + IF done <> 1 AND (dpstate = '' OR dpstate = 'A') + THEN + set msg = 'Cannot waitForDetach if DETACH was not issued on this partition'; + return -1; + END IF; + + close oneDetachCheck; + ELSE + open allDetachCheck; + fetch allDetachCheck into dpid, dpstate; + close allDetachCheck; + END IF; + + if done = 1 + THEN + set msg = 'DETACH completed'; + LEAVE wait_loop; + + END IF; + END LOOP; + +END@ + +connect reset@ diff --git a/java/sqlj/README b/java/sqlj/README new file mode 100644 index 0000000..9ef0597 --- /dev/null +++ b/java/sqlj/README @@ -0,0 +1,704 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for SQLJ Samples on Unix +* +* The /sqllib/samples/java/sqlj directory contains this README +* file. Where is the location of DB2 9.7 on your hard drive. +* The default location for is +* $HOME +* +* This README describes how to build and run sqlj sample code for DB2 9.7. +* The DB2 9.7 sqlj samples are located in the following directory: +* /sqllib/samples/java/sqlj +* +* Copy the files from this directory to your working directory prior to +* building the sample programs. The sample programs directory is +* typically read-only on most platforms and some samples produce output +* files that require write permissions on the directory. +* +* WARNING: Some of these samples may change your database or database +* manager configuration. Execute the samples against a test database +* only, such as the DB2 SAMPLE database. +* +****************************************************************************** +* +* Prepare your DB2 sample development environment +* +* 1) Copy the files in /sqllib/samples/java/sqlj/* to your +* working directory and ensure that directory has write permission. +* +* 2) Modify the CLASSPATH to include: +* /sqllib/java/db2java.zip +* /sqllib/java/db2jcc.jar +* /sqllib/java/db2jcc_license_cu.jar +* /sqllib/java//lib +* /sqllib/lib +* /sqllib/function +* /sqllib/java/sqlj.zip +* where is the name of the +* jdk directory under /sqllib/java. +* +* Modify the PATH to include /sqllib/java//bin, +* /sqllib/lib. +* +* Please make sure that JDK_PATH( db2 +* database manager configuration parameter) is +* pointing to the /sqllib/java/. +* +* To see the dbm cfg parameter value, run the following from db2 +* command window and look for the value of JDK_PATH. +* db2 get dbm cfg +* +* 3) To build and run SQLj samples, you need to: +* +* 1. Enable tcpip: +* db2set DB2COMM=tcpip +* db2stop +* db2start +* +* 2. By default, your database configuration parameter SVCENAME is +* set to an available port_number. If it is not, update the database +* configuration with an available port number using the following +* command: +* db2 update dbm cfg using SVCENAME +* where is an available port_number. +* +* After you have updated the database configuration manually, you have +* to restart DB2 using the following commands: +* db2 terminate +* db2stop +* db2start +* +* 4) Start the Database Manager with the following command: +* db2start +* +* 5) Create the sample database with the following command: +* db2sampl +* +* 6) Connect to the database with the following command: +* db2 connect to sample +* +* 7) To build Stored Procedures and User Defined Functions, ensure +* that you have write permission on the +* /sqllib/function directory. +* +* 8) cd to the directory containing the files copied in step 1. +* +****************************************************************************** +* +* Building DB2 Samples +* +* There are two ways to build DB2 samples: using a make utility or +* using the build files that are included with the DB2 sample +* programs. +* +* o To build samples using the make utility see +* 'BUILDING SAMPLES USING make UTILITY'. +* o To build samples using the build files or when you do not +* have a compatible make utility see 'BUILDING +* SAMPLES USING BUILD FILES' +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING make UTILITY *** +* +* If you have a compatible make utility on your system, you +* can use the makefile provided. Modify the PATH +* variable to include the directory containing the make +* utility. +* +* Depending on your environment, the makefile has to be +* modified. To run SQLj samples with the makefile provided, you +* need to hardcode the password in the makefile. Here is a +* list of variables you can set in the SQLj makefile: +* o set DB to the database you want to work with. +* o set UID to a valid user ID if needed (By default, UID is +* set to the current user id). +* o set PWD to the password of the user ID. +* o set SERVER_NAME to the server's name. +* o set PORT_NUMBER to an available port number (By default, +* PORT_NUMBER is set to 50000). +* For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'make' command in your working +* directory: +* +* o make - builds the sample identified by +* +* Do not include the file extension for the +* program name. E.g. make DbAuth +* For any dependencies refer to the individual sample. +* +* o make srv - builds only samples that can be run on the +* server,including routines (stored procedures and User +* Defined Functions). +* +* o make rtn - builds only routines. +* +* o make call_rtn - builds only client programs that call +* routines. +* +* o make client_run - builds only programs that run +* completely on the client (not ones that call routines). +* +* o make all_client - builds all client samples (all +* programs in the 'call_rtn' and 'client_run' categories). +* +* o make all - builds all supplied sample programs including +* routines, stored procedures and UDFs. +* +* o After compiling the sample, run it using normal java invocation: +* java +* +* Note: +* The makefile provided will only work if a compatible make +* executable program is resident on your system in a directory +* included in your PATH variable. Such a make utility may be +* provided by another language compiler. +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING BUILD FILES *** +* +* As an alternative to the makefile, the build files provided +* can be used to build the sqlj samples. +* +* If you do not have a compatible make utility you can use +* the SQLj build files to build SQLj programs. +* +* Building and Executing Standalone Samples +* ----------------------------------------- +* +* a) To build an SQLj program without a compatible make +* utility: +* +* bldsqlj +* +* Note: +* When you build SQLj programs with the build files, do not +* include the file extension for the program name. +* +* Like the SQLj makefile, the SQLj build files need to be +* updated with a valid user ID, password and an available +* port number. +* +* bldsqlj - Builds an SQLj program. Here is the usage of +* this build file: +* +* bldsqlj (requires hardcoding user ID and +* password in the bldsqlj file) +* bldsqlj +* bldsqlj +* bldsqlj +* +* bldsqlj +* +* +* Where, +* o - the name of the sample program without the +* .sqlj extension. +* o - user ID needed connect to the database. +* o - password needed to connect to the +* database. +* o - server's name that you work with. +* o - an available port_number on the server. +* o - the name of the database where the SQL +* package will be created. +* The default is "sample". +* +* NOTE: The following sqlj sample programs containing DDL statements +* need to be pre-compiled using sqlj .sqlj +* instead of the build file: +* +* TbConstr.sqlj +* TbTemp.sqlj +* TbUMQT.sqlj +* +* o After compiling the sample, run it using normal java invocation: +* java +* +* Building and Executing Stored Procedures +* ---------------------------------------- +* +* o Build the server file using: +* bldsqlj (requires hardcoding user ID and +* password in the bldsqlj file.) +* bldsqlj +* bldsqlj +* bldsqlj +* +* bldsqlj +* +* +* Where, +* o - the name of the sample program without +* the .sqlj extension. +* o - user ID needed connect to the database. +* o - password needed to connect to the +* database. +* o - server's name that you work with. +* o - an available port_number on the server. +* o - the name of the database where the SQL +* package will be created. The default is +* "sample". +* +* o Build stored procedure using the build file: +* spcat +* +* o Build the corresponding client file sample using +* bldsqlj as shown above. +* +* o Run the sample using normal java invocation: +* java +* +* Building and Executing User Defined Functions: +* ---------------------------------------------- +* +* o Build server file using: +* bldsqlj (requires hardcoding user ID and +* password in the bldsqlj file.) +* bldsqlj +* bldsqlj +* bldsqlj +* +* bldsqlj +* +* Where, +* o - the name of the sample program without +* the .sqlj extension. +* o - user ID needed connect to the database. +* o - password needed to connect to the +* database. +* o - server's name that you work with. +* o - an available port_number on the server. +* o - the name of the database where the SQL +* package will be created. The default is +* "sample". +* +* o Build the User Defined Functions using build files: +* udfcat or udfjcat. +* +* o Build the corresponding client file sample using +* bldsqlj as shown above. +* +* o Run the sample using normal java invocation: +* java +* +* Building and Running the Data Source Samples +* -------------------------------------------- +* +* 1. Obtain and set up non DB2 packages +* +* The following packages must be installed in order to build and run +* the Data Source Samples. +* +* Package Location of Package +* ==================================================================== +* JNDI 1.2.1 class http://java.sun.com/products/jndi/ +* #downloadLibraries +* +* File System Service http://java.sun.com/products/jndi/ +* #downloadProvider 1.2 +* +* JDBC 2.0 Optional http://java.sun.com/products/jdbc/download.html +* #spec Package +* +* To build this set of SQLJ samples, update your CLASSPATH to +* include the following files: +* jndi.jar +* fscontext.jar +* providerutil.jar +* jdbc20_stdext.jar +* +* For instance, if you have these jar files located at $HOME/JAR, your +* CLASSPATH should looks like: +* CLASSPATH=...:$HOME/JAR/jndi.jar:$HOME/JAR/fscontext.jar: +* $HOME/JAR/providerutil.jar:$HOME/JAR/jdbc2_0-stdext.jar +* +* You also have to update your CLASSPATH to include the path to the +* directory where jndi.properties is located. For instance, if +* jndi.properties is located under $HOME/JAR, your CLASSPATH should +* looks like: +* CLASSPATH=...:$HOME/JAR/jndi.jar:$HOME/JAR/fscontext.jar: +* $HOME/JAR/providerutil.jar:$HOME/JAR/jdbc2_0-stdext.jar:$HOME/JAR/ +* +* NOTE: +* The SPI (Service Provider Interface) for storing and lookup of +* DataSources in the JNDI is used as the File System. You can +* modify jndi.properties if you want to use any other SPI for the +* JNDI, for instance, LDAP, DNS, etc. +* +* Please note that the appropriate jar files have to be presented +* in the CLASSPATH. No changes are required to run the SQLJ sample +* programs. +* +* 2. Modify Property Files +* +* Modify the property files DS1.prop, DS2.prop, DS3.prop to reflect +* your environment. +* Here is a list of variables you have to modify in these property +* files: +* +* o serverName - set to the server name. +* o portNumber - set to an available port number (by default set +* to 50000) +* o databaseName - set to the database (by default set to +* 'sample') +* o userName - set to a valid user ID. +* o password - set to the user ID's password. +* +* 3. Create the DataSources used in this set of SQLJ programs +* +* a) Compile the program createRegisterDS.java with the following +* command: +* +* javac createRegisterDS.java +* +* b) Run the createRegisterDS.java program with the following +* command: +* +* java createRegisterDS +* +* There are three sample property files. They are as follows: +* +* 1. DS1.prop: jdbc/defaultDataSource +* - used in DataSource1.sqlj +* +* 2. DS2.prop: jdbc/DB2SimpleDataSource_ds1 +* - used in Batch1Demo.sqlj, Batch2Demo.sqlj, Batch3Demo.sqlj, +* DataSource2.sqlj, ScrollIterDemo.sqlj +* +* 3. DS3.prop: jdbc/DB2SimpleDataSource_ds2 +* - used in DataSource2.sqlj +* +* The DataSources are then created and registered in the JNDI. +* +* 4. Create a few sample tables in the SAMPLE database +* +* a) Compile the CreateDemoSchema.sqlj sample program: +* +* sqlj CreateDemoSchema.sqlj +* +* b) Run the CreateDemoSchema.sqlj sample program: +* +* java CreateDemoSchema +* +* This will create a schema and four tables in the SAMPLE +* database. +* The four tables are as follows: +* +* Batch_Test1 // used in Batch1Demo, Batch2Demo +* Batch_Test2 // used in Batch2Demo +* Scroll_Test +* BlobClob_Tab +* +* 5. Compile and Customize +* +* Compile and Customize the demo sample programs using the provided +* build file +* bldsqljds: +* +* bldsqljds +* +* For instance, if you want to compile and customize +* DbConnDataSource.sqlj, do the following: +* +* bldsqljds DbConnDataSource +* +* Run demo sample programs by the following command: +* +* java +* +* For instance, if you want to run Batch1Demo.sqlj, do the following +* command: +* +* java Batch1Demo +* +****************************************************************************** +* +* Common file Descriptions +* +* The following are the common files for SQLj samples. For more +* information on these files, refer to the program source files. +* +****************************************************************************** +* +* Batch files +* +* bldsqlj - build file for application programs +* +****************************************************************************** +* +* Common Utility Function files +* +* makefile - Makefile for sample programs +* Util.sqlj - utilities used by most programs. +* +****************************************************************************** +* +* SQLj Samples Design +* +* The Java SQLj sample programs form an object-based design reflecting +* the component nature of DB2. Related samples demonstrate a specific +* level of database programming. Each level is identified by the first +* two characters of the sample name. Here are the database levels +* represented by the samples: +* +* Identifier DB2 Level +* +* Ap Applet Level. +* Db Database Level. +* Tb Table Level. +* Dt Data Type Level. +* Ud UDF Level. +* Sp Stored Procedure Level. +* +****************************************************************************** +* +* SQLj Sample File Descriptions +* +* The following are the SQLj sample files included with DB2. For more +* information on the sample programs, refer to the program source +* files. +* +****************************************************************************** +* +* Applet Level +* +* Applt.html - HTML file for Applt.sqlj +* Applt.sqlj - How to create applets +* +****************************************************************************** +* +* Database Level +* +* DbAuth.sqlj - How to grant/display/revoke authorities at database +* level. +* DbConn.sqlj - How to connect and disconnect from a database. +* DbMCon.sqlj - How to connect and disconnect from multiple +* databases. +* DbUse.sqlj - How to use database objects. +* +****************************************************************************** +* +* Table Level +* +* LargeRid.sqlj - How to enable Large RIDs support on both new +* tables/ +* tablespaces and existing tables/tablespaces. +* +* PREREQUISITE: Run the script LargeRid_setup.db2 +* before running this sample. Run the LargeRid_cleanup.db2 +* script to cleanup the database objects after running the +* sample. +* +* LargeRidScrpt - CLP script that calls two scripts LargeRid_cleanup.db2 +* and LargeRid_setup.db2 respectively +* +* LargeRid_setup.db2 - CLP script that issues CREATE TABLE statements for +* the sample LargeRid.sqlj +* +* LargeRid_cleanup.db2 - CLP script that issues DROP TABLE statements for +* the sample LargeRid.sqlj +* +* TbAST.sqlj - How to use staging table for updating deferred +* AST. +* +* PREREQUISITE: Run the script TbAST_setup.db2 +* before running this sample. Run the TbAST_cleanup.db2 +* script to cleanup the database objects after running +* the sample. +* +* TbASTScrpt - CLP script that calls two scripts TbAST_cleanup.db2 +* and TbAST_setup.db2 respectively +* +* TbAST_setup.db2 - CLP script that issues CREATE TABLE statements for +* the sample TbAST.sqlj +* +* TbAST_cleanup.db2 - CLP script that issues DROP TABLE statements for +* the sample TbAST.sqlj +* +* TbCompress.sqlj - How to create tables with null and default +* value compression option. +* TbConstr.sqlj - How to work with table constraints. +* TbCreate.sqlj - How to create, alter, and drop tables. +* TbIdent.sqlj - How to use Identity Columns. +* TbInfo.sqlj - How to get and set information at a table +* level. +* TbMod.sqlj - How to modify information in a table. +* TbOnlineInx.sqlj - How to create and reorg indexes on a table. +* TbPriv.sqlj - How to grant/display/revoke privileges at a +* table level. +* TbRead.sqlj - How to read information in a table. +* TbRowcompress.sqlj - How to perform row compression on a table. +* +* PREREQUISITE: Run the script TbRowcompress_setup.db2 +* before running this sample. Run the +* TbRowcompress_cleanup.db2 script to cleanup the +* database objects after running the sample. +* +* TbRowcompressScrpt - CLP script that calls two scripts +* TbRowcompress_cleanup.db2 and TbRowcompress_setup.db2 +* respectively +* +* TbRowcompress_setup.db2 - CLP script that issues CREATE TABLE statements for +* the sample TbRowcompress.sqlj +* +* TbRowcompress_cleanup.db2 - CLP script that issues DROP TABLE statements for +* the sample TbRowcompress.sqlj +* +* TbRunstats.sqlj - How to perform runstats on a table. +* TbSel.sqlj - How to select from each of: insert, update, +* delete. +* TbTemp.sqlj - How to use Declared Temporary Table. +* TbTrig.sqlj - How to use a trigger on a table. +* TbUMQT.sqlj - How to use user materialzed query tables +* (summary tables). +* SetIntegrity.sqlj - How to perform online SET INTEGRITY on a table. +* +* PREREQUISITE: Run the script SetIntegrity_setup.db2 +* before running this sample. Run the +* SetIntegrity_cleanup.db2 script to cleanup the +* database objects after running the sample. +* +* SetIntegrityScrpt - CLP script that calls two scripts SetIntegrity_cleanup.db2 +* and SetIntegrity_setup.db2 respectively +* +* SetIntegrity_setup.db2 - CLP script that issues CREATE TABLE statements for +* the sample SetIntegrity.sqlj +* +* SetIntegrity_cleanup.db2 - CLP script that issues DROP TABLE statements for +* the sample SetIntegrity.sqlj +* +****************************************************************************** +* +* Data Type Level +* +* DtUdt.sqlj - How to create/use/drop user defined distinct types. +* +****************************************************************************** +* +* UDF Level +* +* UDFcli.sqlj - Call the UDFs in UDFsrv.java. +* UDFCreate.db2 - CLP script to catalog the Java UDFs contained in +* UDFsrv.java. +* UDFDrop.db2 - CLP script to uncatalog the Java UDFs contained in +* UDFsrv.java. +* UDFjcli.sqlj - Call the UDFs in UDFjsrv.java. +* UDFjCreate.db2 - CLP script to catalog the Java UDFs contained in +* UDFjsrv.java. +* UDFjDrop.db2 - CLP script to uncatalog the Java UDFs contained in +* UDFjsrv.java. +* UDFjsrv.java - Provide UDFs to be called by UDFjcli.sqlj. +* UDFsrv.java - Provide UDFs to be called by UDFcli.sqlj. +* +****************************************************************************** +* +* Stored Procedure Level +* +* SpCreate.db2 - CLP script to issue CREATE PROCEDURE statements +* SpDrop.db2 - CLP script to drop stored procedures from the catalog +* SpClient.sqlj - Client application that calls the stored procedures. +* SpServer.sqlj - Stored procedure functions built and run on the +* server +* SpIterat.sqlj - Iterator class file for SpServer.sqlj. +* +****************************************************************************** +* +* Java Beans Samples +* +* CreateEmployee.sqlj - How to create an employee record. +* GeneratePayroll.sqlj - How to generate payroll reports by +* department. +* +****************************************************************************** +* +* Data Source Sample Files +* +* Batch1Demo.sqlj: - setBatchLimit(2) creates two Execution Contexts +* ex1/ex2.Inserts two rows using ex1 and perform +* executeBatch()Does a JDBC select to verify 2 rows +* in table.Runs two update statements for the two +* rows with ex2(DOES NOT do an executeBatch()) +* Performs an SQLJ select to verify that the two +* rows were updated - The SQLJ select will trigger +* an implicit Batch Execute +* +* Batch2Demo.sqlj: - setBatching(true) BatchLimit(4) Uses two tables +* Batch_Test1/Batch_Test2. Loops for three times +* (insert statement on Batch_Test2). +* Batch_Test2 should have no rows +* Verifies through JDBC select (as implicit Execute +* OR executeBatch() has not been called) +* setBatchLimit(1) +* Inserts one row into Batch_Test1. This should +* create new Batch and previous batch should be +* implicitly executed.Batch_Test2 should have three +* rows. Batch_Test1 should have +* one row (after SQLJ select has been executed) +* +* Batch3Demo.sqlj - setBatching(true) setBatchLimit(UNLIMITED_BATCH) +* inserts fifty rows into Batch_Test1 +* executeBatch().Verifies the number of rows +* through SELECT count(*) from Batch_Test1 +* +* DbConnDataSource.sqlj - This is a sample program using the +* defaultContext.Because there is no context +* specified in the SELECT statement, the +* underlying context should be obtained from the +* DataSource jdbc/defaultDataSource, which is +* registered using createRegisterDS.java and DS1.prop +* +* DbConMDataSources.sqlj - This sample program is using the contexts +* TesCtx1 & TestCtx2.The underlying connection +* from ctx1 is obtained from the DataSource +* jdbc/DB2SimpleDataSource_ds1.Another +* connection from ctx2 is obtained from +* jdbc/DB2SimpleDataSource_ds2 +* +* ScrollIterDemo.sqlj - This program illustrates usage of Named and +* Positional Scrollable Iterators in SQLJ. Also, it +* shows how a Scrollable Iterator can be +* used for positioned update by implementing +* ForUpdate Clause. However, +* updates will work only when the program is +* customized. +* +* BlobClobDemo.sqlj - This sample program shows the way to access +* Blob/Clob fields in DB2 tables. For accessing +* LOBs in S/390 Db2 additional auxiliary tables +* and indexes need to be created on server side. +* +* createRegisterDS.java - Creates and registers dataSources as specified +* by the property files.The DataSources will be +* created in the temp directory. The file uses +* File System SPI to create a .bindings file in +* the temp directory C:/temp (as defined in +* jndi.properties). +* +* CreateDemoSchema.sqlj - This program creates the schema for the +* DataSource Demo programs. +* +****************************************************************************** + diff --git a/java/sqlj/ScrollIterDemo.sqlj b/java/sqlj/ScrollIterDemo.sqlj new file mode 100644 index 0000000..d69a6f4 --- /dev/null +++ b/java/sqlj/ScrollIterDemo.sqlj @@ -0,0 +1,235 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: ScrollIterDemo.sqlj +// +// SAMPLE: How to use Named and Positional Scrollable Iterators in SQLJ +// +// This program shows how to use Named and Positional Scrollable +// Iterators in SQLJ. It also shows how a Scrollable Iterator +// can be used for Positioned update by implementing ForUpdate +// Clause. However, updates will work only when the program +// is customized. +// +// This sample program uses the DataSource jdbc/DB2SimpleDataSource_ds1 +// from JNDI. The DataSource is registered using createRegisterDS.java +// and DS1.prop. Refer to the README file for details on how to run +// this sample. +// +// +// SQL Statements USED: +// SELECT +// +// Classes used from Util.sqlj are: +// Data +// +// OUTPUT FILE: ScrollIterDemo.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql context ScrollCtx with (dataSource="jdbc/DB2SimpleDataSource_ds1"); + + +class ScrollIterDemo +{ + // Scrollable + // allows the iterator to move both forward and backward relative to the current position, and it can + // move to an absolute position + // + // ForUpdate + // It is equivalent to the FOR UPDATE clause in SQL + // It identifies the columns that can be updated in a subsequent Positioned UPDATE statement. + // Each column name must be unqualified and must identify a column of the table in the FROM clause of the + // fullselect. + // If the ForUpdate cluase is specified without column names, all updatable columns of the table or view + // identified in the frist FROM clause of the fullselect are included + // + // Sensitivity can be one of SENSITIVE, INSENSITIVE, or ASENSITIVE + // SENSITIVE - the result set reflects changes made to the underlying data source while the result set remains open + // INSENSITIVE - the result set is insensitive to changes made to the underlying data source while it is open + + #sql public iterator sensitivePosUpdateIter implements + sqlj.runtime.Scrollable, sqlj.runtime.ForUpdate + with (sensitivity=sqlj.runtime.ResultSetIterator.SENSITIVE, + updateColumns="c1") (int, String); + + #sql public iterator sensitiveNamedUpdateIter implements + sqlj.runtime.Scrollable + with (sensitivity=sqlj.runtime.ResultSetIterator.INSENSITIVE) + (int c1, String c2); + + static ScrollCtx ctx1 = null; + + public static void main(String argv[]) + { + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO USE NAMED AND POSITIONAL SCROLLABLE \n" + + "ITERATORS IN SQLJ. \n"); + + ScrollIterDemo sid = new ScrollIterDemo(); + try + { + sid.runThis(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public void runThis() throws SQLException + { + // Obtain Connection Context from DataSource jdbc/DB2SimpleDataSource_ds1 + ctx1 = new ScrollCtx(); + Connection conn = ctx1.getConnection(); + conn.setAutoCommit(false); + + try + { + System.out.println (" Insert 4 rows into the table Scroll_Test.\n"); + #sql[ctx1] { INSERT INTO Scroll_Test VALUES(101, 'row1') }; + System.out.println(" INSERT INTO Scroll_Test VALUES(101, 'row1')"); + #sql[ctx1] { INSERT INTO Scroll_Test VALUES(102, 'row2') }; + System.out.println(" INSERT INTO Scroll_Test VALUES(102, 'row2')"); + #sql[ctx1] { INSERT INTO Scroll_Test VALUES(103, 'row3') }; + System.out.println(" INSERT INTO Scroll_Test VALUES(103, 'row3')"); + #sql[ctx1] { INSERT INTO Scroll_Test VALUES(104, 'row4') }; + System.out.println(" INSERT INTO Scroll_Test VALUES(104, 'row4')"); + + sensitivePosUpdateIter posUpdateIter = null; + sensitiveNamedUpdateIter namedUpdateIter = null; + int col1 = 0; + String col2 = null; + #sql [ctx1] posUpdateIter = { SELECT c1, c2 FROM Scroll_Test }; + + // Retrieve and display the data in the table Scroll_Test + System.out.println(""); + System.out.println( + " Display the content of the table Scroll_Test by performing\n" + + " the following SQL statement in 'SQLJ':\n\n" + + " SELECT c1, c2 FROM Scroll_Test\n"); + + System.out.println( + " Results:\n" + + " COL1 COL2 \n" + + " ----- ----- "); + + while (true) + { + #sql {FETCH FROM :posUpdateIter INTO :col1, :col2}; + if (posUpdateIter.endFetch()) + { + break; + } + System.out.println(" "+Data.format(col1, 5) + + " " + Data.format(col2, 5)); + } + + System.out.println(""); + System.out.println( + "----------------------------------------------------------\n\n" + + " PART II: Positioned Scrollable Iterator Fetch \n" + + " ------------------------------------------------ \n"); + + System.out.println(" Test scrollability-> Fetch first: \n"); + #sql {FETCH FIRST FROM :posUpdateIter INTO :col1, :col2}; + System.out.println( + " FETCH FIRST FROM :posUpdateIter INTO :col1, :col2\n\n" + + " First Row: COL1 = " + col1 + ", COL2 = " + col2 + "\n\n"); + + System.out.println(" Test scrollability-> Fetch last:\n"); + #sql {FETCH LAST FROM :posUpdateIter INTO :col1, :col2}; + System.out.println( + " FETCH LAST FROM :posUpdateIter INTO :col1, :col2\n\n" + + " Last Row: COL1 = " + col1 + ", COL2 = " + col2 + "\n\n"); + + int abs = 3; + System.out.println(" Test scrollability-> Fetch third:\n"); + #sql {FETCH ABSOLUTE(:abs) FROM :posUpdateIter INTO :col1, :col2}; + System.out.println( + " FETCH ABSOLUTE(:abs) FROM :posUpdateIter INTO :col1, :col2\n\n"+ + " Third row: COL1 = " + col1 + ", COL2 = " +col2 + "\n\n"); + + System.out.println (" Test Update of current row: \n "); + #sql [ctx1] {UPDATE Scroll_Test + SET c1 = 5000 + WHERE CURRENT OF :posUpdateIter}; + System.out.println(" UPDATE Scroll_Test SET c1 = 5000 WHERE "+ + "CURRENT OF :posUpdateIter\n"); + #sql {FETCH ABSOLUTE(:abs) FROM :posUpdateIter INTO :col1, :col2}; + System.out.println( + " FETCH ABSOLUTE(:abs) FROM :posUpdateIter INTO :col1, :col2\n\n"+ + " Updated Third row: COL1 = " + col1 + ", COL2 = " +col2+"\n\n"); + + posUpdateIter.close(); + #sql [ctx1] { commit }; + + + System.out.println(""); + System.out.println( + "----------------------------------------------------------\n\n" + + " PART I: Named Scrollable Iterator Fetch \n" + + " ------------------------------------------------ \n"); + + #sql [ctx1] namedUpdateIter = { SELECT c1,c2 FROM Scroll_Test }; + System.out.println(" SELECT c1,c2 FROM Scroll_Test\n"); + namedUpdateIter.first(); + System.out.println(" First Row: COL1 = " + namedUpdateIter.c1() + + ", COL2 = " + namedUpdateIter.c2() + "\n"); + namedUpdateIter.last(); + System.out.println(" Last Row: COL1 = " + namedUpdateIter.c1() + + ", COL2 = " + namedUpdateIter.c2() + "\n"); + + cleanup(); + } + catch(Exception ex) + { + if (ex instanceof java.sql.SQLException) + { + System.out.println("error code: " + + ((java.sql.SQLException)(ex)).getErrorCode()); + System.out.println("error message: " + ex.getMessage()); + } + ex.printStackTrace(); + } + } + + private static void cleanup() throws SQLException + { + #sql [ctx1] { DELETE FROM Scroll_Test WHERE 1=1 }; + } +} diff --git a/java/sqlj/SetIntegrity.sqlj b/java/sqlj/SetIntegrity.sqlj new file mode 100644 index 0000000..3c63b3d --- /dev/null +++ b/java/sqlj/SetIntegrity.sqlj @@ -0,0 +1,803 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: SetIntegrity.sqlj +// +// SAMPLE: How to perform online SET INTEGRITY on a table. +// +// This sample: +// 1. Availability of table during SET INTEGRITY after LOAD utility. +// 2. Availability of table during SET INTEGRITY after adding a new +// partition is added to the table via the ALTER ATTACH. +// 3. Shows how SET INTEGRITY statement will generate the proper +// values for both generated columns and identity values whenever +// a partition which violates the constraint is attached a data +// partitioned table. +// +// This sample should be run using the following steps: +// 1.Compile the program with the following command: +// sqlj SetIntegrity.sqlj Util.sqlj +// +// 2.The sample should be run using the following command +// java SetIntegrity +// The fenced user id must be able to create or overwrite files in +// the directory specified.This directory must +// be a full path on the server. The dummy file 'dummy.del' must +// exist before the sample is run. +// +// SQL Statements USED: +// ALTER TABLE +// EXPORT +// IMPORT +// INSERT +// LOAD +// SELECT +// SET INTEGRITY +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// sqljException +// +// PREQUISITES : 1. Create the pre-requisite tablespaces and tables by running the command: +// SetIntegrityScrpt +// Alternatively,you can run the command: +// db2 -tvf SetIntegrity_setup.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj SetIntegrity +// 2. Run the sample as: +// java SetIntegrity +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf SetIntegrity_cleanup.db2 +// +// OUTPUT FILE: SetIntegrity.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//************************************************************************** + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + + +class SetIntegrity +{ + public static void main(String argv[]) + { + if (argv.length < 1) + { + System.out.println("\n Usage : java SetIntegrity" + + " "); + } + else + { + try + { + String path = argv[0]; + Connection con; + DefaultContext ctx; + + // initialize DB2Driver and establish database connection. + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + ctx = new DefaultContext(con); + DefaultContext.setDefaultContext(ctx); + + System.out.println( + "\nTHIS SAMPLE SHOWS HOW TO PERFORM SET INTEGRITY ON A TABLE. \n"); + + System.out.println("The DMS tablespaces have been created using the \n" + + "setup script SetIntegrity_setup.db2 \n"); + + System.out.println( + "****************************************************"+ + "\nTHE FOLLOWING SCENARIO SHOWS THE AVAILABILITY OF\n " + + " TABLE DURING SET INTEGRITY AFTER LOAD UTILITY\n" + + "*****************************************************"); + //Shows how SET INTEGRITY can be performed on a partitioned table + partitionedTbCreate(con, path); + + System.out.println( + "*****************************************************"+ + "\nTHE FOLLOWING SCENARIO SHOWS THE AVAILABILITY OF " + + "\n TABLE DURING SET INTEGRITY ALONG WITH GENERATE" + + "\n IDENTITY CLAUSE AFTER LAOD\n" + + "*****************************************************\n"); + + createtb_Temp(con, path); + createptb_Temp(con, path); + + System.out.println( + "\n*******************************************************"+ + "\nTHE FOLLOWING SCENARIO SHOWS THE AVAILABILITY OF " + + "\n TABLE DURING SET INTEGRITY AFTER ATTACH via ALTER" + + "\n*****************************************************"); + + // alter a table + alterTable(con, path); + + // disconnect from the 'sample' database + con.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } + } // main + + + // The function shows how SET INTEGRITY can be performed on + // a partitioned table. + static void partitionedTbCreate(Connection con, String path) throws SQLException + { + try + { + System.out.println("\nThe partitioned table 'fact_table1' is created in the\n" + + "setup script SetIntegrity_setup.db2 using the command \n" + + "\n 'CREATE TABLE fact_table1 (max INTEGER NOT NULL, CONSTRAINT CC CHECK (max>0)) \n" + + " PARTITION BY RANGE (max) \n" + + " (PART part1 STARTING FROM (-1) ENDING (3) IN tbspace1, \n" + + " PART part2 STARTING FROM (4) ENDING (6) IN tbspace2, \n" + + " PART part3 STARTING FROM (7) ENDING (9) IN tbspace3)' \n"); + + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " INSERT INTO \n" + + "TO INSERT DATA IN A TABLE \n" + + "\nExecute the statement:\n" + + " INSERT INTO fact_table1 VALUES (1), (2), (3)"); + + // insert data into the table fact_table1 + + #sql {INSERT INTO fact_table1 VALUES (1), (2), (3)}; + #sql {COMMIT}; + + System.out.println("\nThe temporary table temp_table1 is created in the \n" + + "setup script SetIntegrity_setup.db2 using the command \n" + + "\n 'CREATE TABLE temp_table1 (max INT)' \n"); + + System.out.println( + "INSERT INTO temp_table1 VALUES(4), (5), (6), (7), (0), (-1)"); + + // insert data into temp_table1 + + #sql {INSERT INTO temp_table1 VALUES(4), (5), (6), (7), (0), (-1)}; + #sql {COMMIT}; + + exportData(con, path, "temp_table1"); + loadData(con, path, "fact_table1"); + + System.out.println( + "\nThe temporary table 'fact_exception' to hold exceptions thrown \n" + + "by SET INTEGRITY statement is created in the setup script \n" + + "SetIntegrity_setup.db2 using the command \n" + + "\n 'CREATE TABLE fact_exception (max INTEGER NOT NULL)' \n"); + + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " SET INTEGRITY\n" + + "TO TABLE OUT OF CHECK PENDING STATE:\n"); + + System.out.println( + "Execute the statement:" + + "SET INTEGRITY FOR fact_table1 ALLOW READ ACCESS\n" + + " IMMEDIATE CHECKED FOR EXCEPTION IN fact_table1\n" + + " USE fact_exception"); + + #sql {SET INTEGRITY FOR fact_table1 ALLOW READ ACCESS + IMMEDIATE CHECKED FOR EXCEPTION IN fact_table1 + USE fact_exception}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the contents of 'fact_table1'. + try + { + int max = 0; + + System.out.println( + "---------------------------------------------------------\n"); + System.out.println(" SELECT * FROM fact_table1"); + System.out.println( + " MAX\n" + + " ------"); + + Statement stmt = con.createStatement(); + // perform a SELECT against the "fact_table1" table. + ResultSet rs = stmt.executeQuery("SELECT * FROM fact_table1"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + max = rs.getInt(1); + + System.out.println( + " " + + Data.format(max, 3)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the contents of exception table. + try + { + int max = 0; + + System.out.println(); + System.out.println(" SELECT * FROM fact_exception"); + System.out.println( + " MAX\n" + + " ------"); + + Statement stmt = con.createStatement(); + // perform a SELECT against the "fact_exception" table. + ResultSet rs1 = stmt.executeQuery("SELECT * FROM fact_exception"); + + // retrieve and display the result from the SELECT statement + while (rs1.next()) + { + max = rs1.getInt(1); + + System.out.println( + " " + + Data.format(max, 3)); + } + rs1.close(); + stmt.close(); + System.out.println( + "-----------------------------------------------------------"); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // partitionedTbCreate + + // exports data to a temporary table. + static void exportData(Connection con, String path, String tablename) throws SQLException + { + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + int rows_exported = 0; + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " EXPORT \n" + + "TO EXPORT TABLE DATA INTO A FILE \n" + + "\nExecute the statement:\n" + + " EXPORT TO dummy.del OF DEL SELECT * FROM " + tablename); + + // export data into a dummy file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to which the data is to be exported + param = "EXPORT TO " + path + "/dummy.del OF DEL SELECT * FROM " + tablename; + + // set the input parameter + callStmt1.setString(1, param); + System.out.println(); + + // execute export by calling ADMIN_CMD + callStmt1.execute(); + + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if (rs.next()) + { + // the numbers of rows exported + rows_exported = rs.getInt(1); + + // display the output + System.out.println + ("Total number of rows exported : " + rows_exported); + } + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // exportData + + // load data from temporary table into base table. + static void loadData(Connection con, String path, String tablename) throws SQLException + { + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + int rows_read = 0; + int rows_skipped = 0; + int rows_loaded = 0; + int rows_rejected = 0; + int rows_deleted = 0; + int rows_committed = 0; + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " LOAD \n" + + "TO LOAD THE DATA INTO THE TABLE \n" + + "\nExecute the statement:\n" + + " LOAD FROM dummy.del OF DEL INSERT INTO " + tablename); + + // Load data from file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path of the file from which the data is to be loaded + param = "LOAD FROM " + path + "/dummy.del OF DEL INSERT INTO " + tablename; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if (rs.next()) + { + // retrieve the no of rows read + rows_read = rs.getInt(1); + + // retrieve the no of rows skipped + rows_skipped = rs.getInt(2); + + // retrieve the no of rows loaded + rows_loaded = rs.getInt(3); + + // retrieve the no of rows rejected + rows_rejected = rs.getInt(4); + + // retrieve the no of rows deleted + rows_deleted = rs.getInt(5); + + // retrieve the no of rows committed + rows_committed = rs.getInt(6); + + // display the resultset + System.out.print("\nTotal number of rows read : "); + System.out.println(rows_read); + System.out.print("Total number of rows skipped : "); + System.out.println( rows_skipped); + System.out.print("Total number of rows loaded : "); + System.out.println(rows_loaded); + System.out.print("Total number of rows rejected : "); + System.out.println(rows_rejected); + System.out.print("Total number of rows deleted : "); + System.out.println(rows_deleted); + System.out.print("Total number of rows committed : "); + System.out.println(rows_read); + } + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // loadData + + // displays the contents of a table. + static void showData(Connection con, String tablename) throws SQLException + { + try + { + int max = 0; + int min = 0; + + System.out.println( + "\n-----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " SELECT\n" + + "ON fact_table TABLE\n" + tablename); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + Statement stmt = con.createStatement(); + ResultSet rs; + int min = 0; + int max = 0; + + System.out.println( + "Execute the statement:\n" + + "SELECT * FROM " + tablename); + + System.out.println( + " MIN MAX \n" + + " ----- ------"); + + // perform a SELECT against the "fact_table" table in the sample database + rs = stmt.executeQuery( + "SELECT * FROM " + tablename); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + min = rs.getInt(1); + max = rs.getInt(2); + + System.out.println( + " " + + Data.format(min, 2) + " " + + Data.format(max, 7)); + } + rs.close(); + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // showData + + // creates a temporary table and inserts data into it. This also shows + // SET INTEGRITY operation on 'fact_table3' with FORCE GENERATED clause + // to it. + static void createptb_Temp(Connection con, String path) throws SQLException + { + try + { + System.out.println( + "\nA partitioned table 'fact_table3' with GENERATE IDENTITY clause \n" + + "and a temporary table 'temp_table3' are created in the setup script\n" + + "SetIntegrity_setup.db2 using the commands \n" + + "\n 'CREATE TABLE fact_table3 (min SMALLINT NOT NULL, \n" + + " max SMALLINT GENERATED ALWAYS AS IDENTITY, \n" + + " CONSTRAINT CC CHECK (min>0)) \n" + + " PARTITION BY RANGE (min) \n" + + " (PART part1 STARTING FROM (1) ENDING (3) IN tbspace1, \n" + + " PART part2 STARTING FROM (4) ENDING (6) IN tbspace2, \n" + + " PART part3 STARTING FROM (7) ENDING (9) IN tbspace3)' \n" + + "\n 'CREATE TABLE temp_table3 (max INTEGER)' \n"); + + System.out.println( + "INSERT INTO temp_table3 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9)"); + + //insert data into temp_table3 + + #sql {INSERT INTO temp_table3 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9)}; + #sql {COMMIT}; + + exportData(con, path, "temp_table3"); + loadData(con, path, "fact_table3"); + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " SET INTEGRITY \n" + + "To bring the table out of check pending state\n"); + + System.out.println( + "SET INTEGRITY FOR fact_table3 IMMEDIATE CHECKED FORCE GENERATED"); + + #sql {SET INTEGRITY FOR fact_table3 IMMEDIATE CHECKED FORCE GENERATED}; + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + showData(con, "fact_table3"); + } // createptb_Temp + + // Exports data from temporary table 'attach' into 'dummy.del'. Performs LOAD + // to load data from 'dummy.del' into temorary table 'attach_part'. Partition + // is added to 'fact_table4' and SET INTEGRITY is performed on 'fact_table4' + // to bring the table out of check pending state. + static void alterTable(Connection con, String path) throws SQLException + { + System.out.println( + "\nA partitioned table 'fact_table4' with GENERATE IDENTITY clause \n" + + "and temporary tables 'attach_part' and 'attach' are created \n" + + "in the setup script SetIntegrity_setup.db2 using the commands \n" + + "\n 'CREATE TABLE fact_table4 (min SMALLINT NOT NULL, \n" + + " max SMALLINT GENERATED ALWAYS AS IDENTITY, \n" + + " CONSTRAINT CC CHECK (min>0)) \n" + + " PARTITION BY RANGE (min) \n" + + " (PART part1 STARTING FROM (1) ENDING (3) IN tbspace1, \n" + + " PART part2 STARTING FROM (4) ENDING (6) IN tbspace2, \n" + + " PART part3 STARTING FROM (7) ENDING (9) IN tbspace3)' \n" + + "\n 'CREATE TABLE attach_part (min SMALLINT NOT NULL, \n" + + " max SMALLINT GENERATED ALWAYS AS IDENTITY, \n" + + " CONSTRAINT CC CHECK (min>0)) IN tbspace1' \n" + + "\n 'CREATE TABLE attach(min SMALLINT NOT NULL)' \n"); + + exportData(con, path, "temp_table3"); + loadData(con, path, "fact_table4"); + + // insert data into attach table + + #sql {INSERT INTO attach VALUES (10), (11), (12)}; + #sql {COMMIT}; + + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + + int rows_exported = 0; + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " EXPORT \n" + + "TO EXPORT TABLE DATA INTO A FILE \n" + + "\nExecute the statement:\n" + + " EXPORT TO dummy.del OF DEL SELECT * FROM attach"); + + // export data into a dummy file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path for the file to which the data is to be exported + param = "EXPORT TO " + path + "/dummy.del OF DEL SELECT * FROM attach" ; + + // set the input parameter + callStmt1.setString(1, param); + System.out.println(); + + // execute export by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if (rs.next()) + { + // the numbers of rows exported + rows_exported = rs.getInt(1); + + // display the output + System.out.println + ("Total number of rows exported : " + rows_exported); + } + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + String sql = ""; + String param = ""; + CallableStatement callStmt1 = null; + ResultSet rs = null; + Statement stmt = con.createStatement(); + int rows_read = 0; + int rows_skipped = 0; + int rows_loaded = 0; + int rows_rejected = 0; + int rows_deleted = 0; + int rows_committed = 0; + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " LOAD \n" + + "TO LOAD THE DATA INTO THE TABLE \n" + + "\n Execute the statement:\n" + + " LOAD FROM dummy.del OF DEL INSERT INTO attach_part"); + + // Load data from file + sql = "CALL SYSPROC.ADMIN_CMD(?)"; + callStmt1 = con.prepareCall(sql); + + // 'path' is the path of the file from which the data is to be loaded + param = "LOAD FROM " + path + "/dummy.del OF DEL INSERT INTO attach_part" ; + + // set the input parameter + callStmt1.setString(1, param); + + // execute import by calling ADMIN_CMD + callStmt1.execute(); + rs = callStmt1.getResultSet(); + + // retrieve the resultset + if (rs.next()) + { + // retrieve the no of rows read + rows_read = rs.getInt(1); + + // retrieve the no of rows skipped + rows_skipped = rs.getInt(2); + + // retrieve the no of rows loaded + rows_loaded = rs.getInt(3); + + // retrieve the no of rows rejected + rows_rejected = rs.getInt(4); + + // retrieve the no of rows deleted + rows_deleted = rs.getInt(5); + + // retrieve the no of rows committed + rows_committed = rs.getInt(6); + + // display the resultset + System.out.print("\nTotal number of rows read : "); + System.out.println(rows_read); + System.out.print("Total number of rows skipped : "); + System.out.println( rows_skipped); + System.out.print("Total number of rows loaded : "); + System.out.println(rows_loaded); + System.out.print("Total number of rows rejected : "); + System.out.println(rows_rejected); + System.out.print("Total number of rows deleted : "); + System.out.println(rows_deleted); + System.out.print("Total number of rows committed : "); + System.out.println(rows_read); + } + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " ALTER TABLE\n" + + "TO ATTACH PARTITION TO A TABLE\n" + + "\nExecute the statement:\n" + + " ALTER TABLE fact_table4 ATTACH PARTITION part4\n" + + " STARTING FROM (10) ENDING AT (12)\n" + + " FROM TABLE attach_part\n"); + + #sql {ALTER TABLE fact_table4 ATTACH PARTITION part4 + STARTING FROM (10) ENDING AT (12) FROM TABLE attach_part}; + + #sql {COMMIT}; + + // The following SET INTEGRITY statement will check the table fact_table2 + // for constraint violations and at the same time the GENERATE IDENTITY + // along with INCREMENTAL options will generate new identity values + // for attached rows only. + + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " SET INTEGRITY \n" + + "TO BRING TABLE OUT OF CHECK PENDING STATE\n\n" + + "Execute the statement:\n" + + " SET INTEGRITY FOR fact_table4 GENERATE IDENTITY\n" + + " IMMEDIATE CHECKED INCREMENTAL;"); + + #sql {SET INTEGRITY FOR fact_table4 GENERATE IDENTITY + IMMEDIATE CHECKED INCREMENTAL}; + + showData(con, "fact_table4"); + + } // alterTable + + // Inserts data into it temporary table temp_table2. Data is + // exported from 'temp_table2' to 'dummy.del' and later loaded into + // 'fact_table2'. SET INTEGRITY with GENERATE IDENTITY clause is performed + // on 'fact_table2' to generate new identity values for all rows currently + // in the table and all loaded rows. + static void createtb_Temp(Connection con, String path) throws SQLException + { + try + { + System.out.println( + "\nA partitioned table 'fact_table2' with GENERATE IDENTITY clause \n" + + "and temporary table 'temp_table2' are created in the setup script\n" + + "SetIntegrity_setup.db2 using the commands \n" + + "\n 'CREATE TABLE fact_table2 (min SMALLINT NOT NULL, \n" + + " max SMALLINT GENERATED ALWAYS AS IDENTITY, \n" + + " CONSTRAINT CC CHECK (min>0)) \n" + + " PARTITION BY RANGE (min) \n" + + " (PART part1 STARTING FROM (1) ENDING (3) IN tbspace1, \n" + + " PART part2 STARTING FROM (4) ENDING (6) IN tbspace2, \n" + + " PART part3 STARTING FROM (7) ENDING (9) IN tbspace3)' \n" + + "\n 'CREATE TABLE temp_table2 (min SMALLINT NOT NULL)' \n"); + + System.out.println( + "\nExecute the statements:\n" + + " INSERT INTO temp_table2 VALUES (1), (2), (3), (4), (5)\n" + + " INSERT INTO temp_table2 VALUES (6), (7), (8), (9)"); + + // insert data into temp_table2 + #sql {INSERT INTO temp_table2 VALUES (1), (2), (3), (4), (5), + (6), (7), (8), (9)}; + + exportData(con, path, "temp_table2"); + loadData(con, path, "fact_table2"); + + // The following SET INTEGRITY statement will check the table fact_table2 for + // constraint violations and at the same time the GENERATE IDENTITY along with + // NOT INCREMENTAL options will generate new identity values for all rows + // currently in the table and all loaded rows + + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " SET INTEGRITY\n" + + "TO TABLE OUT OF CHECK PENDING STATE:\n" + + "\nExecute the statement:" + + "\n SET INTEGRITY FOR fact_table2 GENERATE IDENTITY \n" + + " IMMEDIATE CHECKED NOT INCREMENTAL \n"); + + #sql {SET INTEGRITY FOR fact_table2 GENERATE IDENTITY + IMMEDIATE CHECKED NOT INCREMENTAL}; + #sql {COMMIT}; + + showData(con, "fact_table2"); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // createtb_Temp +} // SetIntegrity diff --git a/java/sqlj/SetIntegrityScrpt b/java/sqlj/SetIntegrityScrpt new file mode 100644 index 0000000..1b5987a --- /dev/null +++ b/java/sqlj/SetIntegrityScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: SetIntegrityScrpt +# SetIntegrity_cleanup.db2 drops tables created by SetIntegrity_setup.db2 for the +# sample SetIntegrity.sqlj +# SetIntegrity_setup.db2 creates tables necessary for execution of the sample +# SetIntegrity.sqlj +# Both CLP scripts can be run on their own +# Usage: SetIntegrityScrpt + +db2 -tvf SetIntegrity_cleanup.db2 +db2 -tvf SetIntegrity_setup.db2 diff --git a/java/sqlj/SetIntegrity_cleanup.db2 b/java/sqlj/SetIntegrity_cleanup.db2 new file mode 100644 index 0000000..e643302 --- /dev/null +++ b/java/sqlj/SetIntegrity_cleanup.db2 @@ -0,0 +1,73 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: SetIntegrity_cleanup.db2 +-- +-- SAMPLE: Cleanup script for the sample SetIntegrity.sqlj +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf SetIntegrity_cleanup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +---------------------------------------------------------------------------- + +connect to sample; + +-- drop tables created for the function partitionedTbCreate + +DROP TABLE temp_table1; +DROP TABLE fact_exception; +DROP TABLE fact_table1; + +-- drop tables created for the function createtb_Temp + +DROP TABLE temp_table2; +DROP TABLE fact_table2; + +-- drop tables created for the function createptb_Temp + +DROP TABLE fact_table3; + +-- drop tables created for the function alterTable + +DROP TABLE temp_table3; +DROP TABLE attach; +DROP TABLE fact_table4; + +-- drop the tablespaces + +DROP TABLESPACE tbspace; +DROP TABLESPACE tbspace1; +DROP TABLESPACE tbspace2; +DROP TABLESPACE tbspace3; + +connect reset; diff --git a/java/sqlj/SetIntegrity_setup.db2 b/java/sqlj/SetIntegrity_setup.db2 new file mode 100644 index 0000000..e9b73e5 --- /dev/null +++ b/java/sqlj/SetIntegrity_setup.db2 @@ -0,0 +1,156 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: SetIntegrity_setup.db2 +-- +-- SAMPLE: This sample serves as the setup script for the sample +-- SetIntegrity.sqlj +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf SetIntegrity_setup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad + +---------------------------------------------------------------------------- + +connect to sample; + +---------------------------------------------------------------------------- +-- Creating the tablespaces +---------------------------------------------------------------------------- + +-- create regular DMS table space tbspace + +CREATE REGULAR TABLESPACE tbspace + MANAGED BY DATABASE USING (FILE 'cont.dat' 10000); + +-- create regular DMS table space tbspace1 + +CREATE REGULAR TABLESPACE tbspace1 + MANAGED BY DATABASE USING (FILE 'cont1.dat' 10000); + +-- create regular DMS table space tbspace2 + +CREATE REGULAR TABLESPACE tbspace2 + MANAGED BY DATABASE USING (FILE 'cont2.dat' 10000); + +-- create regular DMS table space tbspace3 + +CREATE REGULAR TABLESPACE tbspace3 + MANAGED BY DATABASE USING (FILE 'cont3.dat' 10000); + +---------------------------------------------------------------------------- +-- Creating tables for the function partitionedTbCreate +---------------------------------------------------------------------------- + +-- creates a partitioned table with 'part1' in 'tbspace1', 'part2' in +-- 'tbspace2', and 'part3' in 'tbspace3' and inserts data into the +-- table. + +CREATE TABLE fact_table1 (max INTEGER NOT NULL, CONSTRAINT CC CHECK (max>0)) + PARTITION BY RANGE (max) + (PART part1 STARTING FROM (-1) ENDING (3) IN tbspace1, + PART part2 STARTING FROM (4) ENDING (6) IN tbspace2, + PART part3 STARTING FROM (7) ENDING (9) IN tbspace3); + +-- create a temporary table + +CREATE TABLE temp_table1 (max INT); + +-- create temporary table to hold exceptions thrown by SET INTEGRITY statement + +CREATE TABLE fact_exception (max INTEGER NOT NULL); + +---------------------------------------------------------------------------- +-- Creating temporary tables for createtb_Temp function +---------------------------------------------------------------------------- + +-- creates a partitioned table with 'part1' in 'tbspace1', 'part2' in +-- 'tbspace2' and 'part3' in 'tbspace3' with GENERATE IDENTITY clause + +CREATE TABLE fact_table2 (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)) + PARTITION BY RANGE (min) + (PART part1 STARTING FROM (1) ENDING (3) IN tbspace1, + PART part2 STARTING FROM (4) ENDING (6) IN tbspace2, + PART part3 STARTING FROM (7) ENDING (9) IN tbspace3); + +-- create temporary table + +CREATE TABLE temp_table2 (min SMALLINT NOT NULL); + +---------------------------------------------------------------------------- +-- Creating temporary tables for createptb_Temp function +---------------------------------------------------------------------------- + +-- creates a partitioned table with 'part1' in 'tbspace1', 'part2' in +-- 'tbspace2' and 'part3' in 'tbspace3' with GENERATE IDENTITY clause +-- 'tbspace2' and 'part3' in 'tbspace3' with GENERATE IDENTITY clause + +CREATE TABLE fact_table3 (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)) + PARTITION BY RANGE (min) + (PART part1 STARTING FROM (1) ENDING (3) IN tbspace1, + PART part2 STARTING FROM (4) ENDING (6) IN tbspace2, + PART part3 STARTING FROM (7) ENDING (9) IN tbspace3); + +-- create temporary table + +CREATE TABLE temp_table3 (max INTEGER); + +---------------------------------------------------------------------------- +-- Creating temporary tables for alterTable function +---------------------------------------------------------------------------- + +-- creates a partitioned table with 'part1' in 'tbspace1', 'part2' in +-- 'tbspace2' and 'part3' in 'tbspace3' with GENERATE IDENTITY clause +-- 'tbspace2' and 'part3' in 'tbspace3' with GENERATE IDENTITY clause + +CREATE TABLE fact_table4 (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)) + PARTITION BY RANGE (min) + (PART part1 STARTING FROM (1) ENDING (3) IN tbspace1, + PART part2 STARTING FROM (4) ENDING (6) IN tbspace2, + PART part3 STARTING FROM (7) ENDING (9) IN tbspace3); + +-- create temporary tables + +CREATE TABLE attach_part (min SMALLINT NOT NULL, + max SMALLINT GENERATED ALWAYS AS IDENTITY, + CONSTRAINT CC CHECK (min>0)) IN tbspace1; + +CREATE TABLE attach(min SMALLINT NOT NULL); + +connect reset; diff --git a/java/sqlj/SpClient.sqlj b/java/sqlj/SpClient.sqlj new file mode 100644 index 0000000..6c12c05 --- /dev/null +++ b/java/sqlj/SpClient.sqlj @@ -0,0 +1,582 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: SpClient.sqlj +// +// SAMPLE: Call the set of stored procedures implemented in SpServer.sqlj +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Update makefile with a valid userid, password and +// an available port number. +// 2. Compile the server source file SpServer.sqlj (this will also +// compile the Utility file, Util.sqlj, erase the existing +// library/class files and copy the newly compiled class files, +// SpServer.class, SpContext.class, SpIterat.class, +// SpServerEmployees.class, SpServerSalary.class, +// SpServer_SJProfileKeys.class and SpServer_SJProfile0.ser +// from the current directory to the $(DB2PATH)\function directory): +// nmake/make SpServer +// 2. Compile the client source file SpClient.sqlj (this will also +// call the script 'spcat' to create and catalog the stored +// procedures): +// nmake/make SpClient +// 3. Run the client SpClient: +// java SpClient +// +// II) If you don't have a compatible make/nmake program on your +// system do the following: +// 1. Compile the utility file and the server source file with: +// sqlj Util.sqlj +// sqlj SpServer.sqlj +// 2. Update bldsqljs and bldsqlj build files with a valid userid +// and password. +// 3. Erase the existing library/class files (if any): +// SpContext.class, SpIterat.class, SpServer.class, +// SpServerEmployees.class, SpServerSalary.class, +// SpServer_SJProfileKeys.class and SpServer_SJProfile0.ser +// from the following path, $(DB2PATH)\function. +// 4. Compile the Iterator class file for SpServer.sqlj with +// the following command: +// sqlj SpIterat.sqlj +// 5. Build the SQLj stored procedure server with the following +// command (It will also copy the following class files from +// the current directory to the $(DB2PATH)\function : +// SpContext.class, SpIterat.class, SpServer.class, +// SpServerEmployees.class, SpServerSalary.class, +// SpServer_SJProfileKeys.class and SpServer_SJProfile0.ser): +// bldsqljs SpServer +// 6. Catalog the stored procedures in the database with: +// spcat +// 7. Build the SQLj stored procedure client with the following +// command: +// bldsqlj SpClient +// 8. Run SpClient with: +// java SpClient +// +// SpClient calls nine methods that call stored procedures: +// (1) callOutLanguage: Calls a stored procedure that returns the +// implementation language of the stored procedure library +// Parameter types used: OUT CHAR(8) +// (2) callOutParameter: Calls a stored procedure that returns median +// salary of employee salaries +// Parameter types used: OUT DOUBLE +// (3) callInParameters: Calls a stored procedure that accepts 3 salary +// values and updates employee salaries in the EMPLOYEE table based +// on these values for a given department. +// Parameter types used: IN DOUBLE +// IN DOUBLE +// IN DOUBLE +// IN CHAR(3) +// (4) callInoutParameter: Calls a stored procedure that accepts an input +// value and returns the median salary of those employees in the +// EMPLOYEE table who earn more than the input value. Demonstrates how +// to use null indicators in a client application. The stored procedure +// has to be implemented in the following parameter styles for it to be +// compatible with this client application. +// Parameter style for a C stored procedure: SQL +// Parameter style for a Java(JDBC/SQLJ) stored procedure: JAVA +// Parameter style for an SQL stored procedure: SQL +// Parameter types used: INOUT DOUBLE +// (5) callClobExtract: Calls a stored procedure that extracts and returns a +// portion of a CLOB data type +// Parameter types used: IN CHAR(6) +// OUT VARCHAR(1000) +// (6) callDecimalType: Calls a stored procedure that passes and receives a +// DECIMAL data type from a stored procedure +// Parameter types used: INOUT DECIMAL +// (7) callAllDataTypes: Calls a stored procedure that uses a variety of +// common data types (not DECIMAL, GRAPHIC, VARGRAPHIC, BLOB, CLOB, +// DBCLOB). This sample shows only a subset of DB2 supported data types. +// For a full listing of DB2 data types, please see the SQL Reference. +// Parameter types used: INOUT SMALLINT +// INOUT INTEGER +// INOUT BIGINT +// INOUT REAL +// INOUT DOUBLE +// OUT CHAR(1) +// OUT CHAR(15) +// OUT VARCHAR(12) +// OUT DATE +// OUT TIME +// (8) callOneResultSet: Calls a stored procedure that returns a result set to +// the client application +// Parameter types used: IN DOUBLE +// (9) callTwoResultSets: Calls a stored procedure that returns two result sets +// to the client application +// Parameter types used: IN DOUBLE +// +// SQL Statements USED: +// CALL +// SELECT +// +// OUTPUT FILE: SpClient.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; // JDBC classes +import java.math.BigDecimal; // BigDecimal support for packed decimal type +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +public class SpClient +{ + static double outMedian = 0; + + public static void main(String argv[]) + { + DefaultContext ctx = null; + Connection con = null; + String language = ""; + + try + { + Db db = new Db(argv); + + System.out.println("HOW TO CALL VARIOUS STORED PROCEDURES.\n"); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + language = callOutLanguage(); + callOutParameter(); + callInParameters(); + + // call INOUT_PARAM stored procedure using the median returned + // by the call to OUT_PARAM + System.out.println("\nCall stored procedure named INOUT_PARAM"); + System.out.println("using the median returned by the call to " + + "OUT_PARAM"); + callInoutParameter(outMedian); + + // call INOUT_PARAM stored procedure again in order to depict a + // NOT FOUND error that is raised when no rows are found to satisfy + // a query in the procedure. No row is found because the query + // depends on the procedure's input parameter value which is too high. + System.out.println("\nCALL stored procedure INOUT_PARAM again"); + System.out.println("with an input value that causes a NOT FOUND error"); + callInoutParameter(99999.99); + + callClobExtract("000140"); + callDecimalType(); + callAllDataTypes(); + callOneResultSet(ctx); + callTwoResultSets(ctx); + + // roll back any changes to the database made by this sample + #sql { ROLLBACK WORK }; + db.disconnect(); + } + catch (Exception e) + { + try + { + #sql { ROLLBACK WORK }; + ctx.close(); + } + catch (Exception x) + { } + + e.printStackTrace(); + } + } // end main + + public static String callOutLanguage() + { + String outLang = ""; + try + { + // prepare the CALL statement for OUT_LANGUAGE + String procName = "OUT_LANGUAGE"; + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + #sql {CALL OUT_LANGUAGE(:out outLang)}; + + System.out.println("Stored procedures are implemented in language " + + outLang); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + + return(outLang); + + } // callOutLanguage + + public static void callOutParameter() + { + try + { + String procName = "OUT_PARAM"; + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + #sql {CALL OUT_PARAM(:out outMedian)}; + + System.out.println(procName + " completed successfully"); + System.out.println("Median salary returned from " + procName + " = " + + outMedian); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + + } // callOutParameter + + + public static void callInParameters() throws SQLException + { + double sumSalary, inParamLowSal, inParamMedSal, inParamHighSal; + String inDept; + try + { + // prepare the CALL statement for IN_PARAMS + String procName = "IN_PARAMS"; + inDept = "E11"; + + // display total salary before calling IN_PARAMS + #sql {SELECT SUM(salary) INTO :sumSalary + FROM employee + WHERE workdept = :inDept}; + + System.out.println(); + System.out.println("Sum of salaries for dept. E11 = " + + sumSalary + " before " + procName); + + // set the input parameters of the stored procedure + inParamLowSal = 15000; + inParamMedSal = 20000; + inParamHighSal = 25000; + + System.out.println("Call stored procedure named " + procName); + #sql {CALL IN_PARAMS(:in inParamLowSal, :in inParamMedSal, + :in inParamHighSal, :in inDept)}; + + System.out.println(procName + " completed successfully"); + + // display total salary after calling IN_PARAMS + #sql {SELECT SUM(salary) INTO :sumSalary + FROM employee + WHERE workdept = :inDept}; + + System.out.println("Sum of salaries for dept. E11 = " + + sumSalary + " after " + procName); + + } + catch (SQLException e) + { + // roll back any UPDATE statements issued before the SQLException + #sql { ROLLBACK WORK }; + System.out.println(e.getMessage()); + } + } // callInParameters + + public static void callInoutParameter(double median) + { + double inoutMedian; + try + { + String procName = "INOUT_PARAM"; + inoutMedian = median; + + // call the stored procedure + + if (median == 99999.99) + { + System.out.println("\n-- The following error report is " + + "expected! --"); + } + + #sql {CALL INOUT_PARAM(:inout inoutMedian)}; + + System.out.println(procName + " completed successfully"); + System.out.println("Median salary returned from " + procName + " = " + + inoutMedian); + + + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + + } // callInoutParameter + + public static void callClobExtract(String empNo) + { + String outResume; + + try + { + String procName = "CLOB_EXTRACT"; + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + #sql {CALL CLOB_EXTRACT(:in empNo, :out outResume)}; + + System.out.println(procName + " completed successfully"); + System.out.println("Resume section returned for employee " + + empNo + "=\n" + outResume); + } + catch (Exception e) + { + System.out.println(e.getMessage()); + } + } // callClobExtract + + //************************************************************************* + // PARAMETER STYLE JAVA procedures do not support the DBINFO clause. + // The following PARAMETER STYLES can be used with DBINFO or PROGRAM TYPE + // clauses: + // - DB2SQL + // - GENERAL + // - GENERAL WITH NULLS + // - SQL + // Please see the SpClient implementation for C/C++/CLI language to + // see this functionality. + //************************************************************************* + + //************************************************************************* + // PROGRAM TYPE MAIN is only valid for LANGUAGE C, COBOL or CLR, and + // following PARAMETER STYLE: + // - DB2SQL + // - GENERAL + // - GENERAL WITH NULLS + // - SQL + // Please see the SpClient implementation for C/C++/CLI language to + // see this functionality. + //************************************************************************* + + public static void callDecimalType() + { + try + { + // prepare the CALL statement for DECIMAL_TYPE + String procName = "DECIMAL_TYPE"; + + // declare and initialize input variable + BigDecimal inoutDecimal = new BigDecimal("400000.00"); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + #sql {CALL DECIMAL_TYPE(:inout inoutDecimal)}; + + System.out.println(procName + " completed successfully"); + System.out.println("Value of DECIMAL = " + inoutDecimal); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callDecimalType + + public static void callAllDataTypes() + { + try + { + // prepare the CALL statement for ALL_DATA_TYPES + String procName = "ALL_DATA_TYPES"; + + // declare and initialize input variables + short inoutSmallint = 32000; + int inoutInteger = 2147483000; + long inoutBigint = 2147483000; + float inoutReal = 100000; + double inoutDouble = 2500000; + + // declare output variables + String outChar, outChars, outVarchar; + Date outDate; + Time outTime; + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + #sql {CALL ALL_DATA_TYPES(:inout inoutSmallint, :inout inoutInteger, + :inout inoutBigint, :inout inoutReal, + :inout inoutDouble, :out outChar, + :out outChars, :out outVarchar, + :out outDate, :out outTime)}; + + System.out.println(procName + " completed successfully"); + + System.out.println("Value of SMALLINT = " + inoutSmallint); + System.out.println("Value of INTEGER = " + inoutInteger); + System.out.println("Value of BIGINT = " + inoutBigint); + System.out.println("Value of REAL = " + inoutReal); + System.out.println("Value of DOUBLE = " + inoutDouble); + System.out.println("Value of CHAR(1) = " + outChar); + System.out.println("Value of CHAR(15) = " + outChars.trim()); + System.out.println("Value of VARCHAR(12) = " + outVarchar.trim()); + System.out.println("Value of DATE = " + outDate); + System.out.println("Value of TIME = " + outTime); + + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callAllDataTypes + + public static void callOneResultSet(ConnectionContext ctx) + { + + ResultSet rs; + ExecutionContext execCtx = ctx.getExecutionContext(); + + String procName = "ONE_RESULT_SET"; + + try + { + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + #sql {CALL ONE_RESULT_SET(:in outMedian)}; + + System.out.println(procName + " completed successfully"); + if ((rs = execCtx.getNextResultSet()) != null) + { + fetchAll(rs); + + // close ResultSet + rs.close(); + } + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + + } // callOneResultSet + + public static void callTwoResultSets(ConnectionContext ctx) + { + ResultSet rs; + ExecutionContext execCtx = ctx.getExecutionContext(); + + String procName = "TWO_RESULT_SETS"; + try + { + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + #sql {CALL TWO_RESULT_SETS(:in outMedian)}; + System.out.println(procName + " completed successfully"); + + if ((rs = execCtx.getNextResultSet()) != null) + { + System.out.println( + "Result set 1: Employees with salaries greater than " + outMedian); + // get first result set + fetchAll(rs); + } + + if ((rs = execCtx.getNextResultSet()) != null) + { + System.out.println(); + System.out.println("Result set 2: Employees with salaries less than " + + outMedian); + // get second result set + fetchAll(rs); + } + + // close ResultSet + rs.close(); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callTwoResultSets + + //************************************************************************* + // PARAMETER STYLE GENERAL and GENERAL WITH NULLS can be specified when + // LANGUAGE C, COBOL, or CLR is used. + // Please see the SpClient implementation for CLI language to see this + // functionality. + //************************************************************************* + + // ====================================================== + // Method: fetchAll -- returns all rows from a result set + // ====================================================== + public static void fetchAll(ResultSet rs) + { + try + { + System.out.println( + "============================================================="); + + // retrieve the number, types and properties of the + // resultset's columns + ResultSetMetaData stmtInfo = rs.getMetaData(); + + int numOfColumns = stmtInfo.getColumnCount(); + int r = 0; + + while (rs.next()) + { + r++; + System.out.print("Row: " + r + ": "); + for (int i = 1; i <= numOfColumns; i++) + { + if (i == 3) + { + System.out.print(Data.format(rs.getDouble(i), 7, 2)); + } + else + { + System.out.print(rs.getString(i)); + } + + if (i != numOfColumns) + { + System.out.print(", "); + } + } + System.out.println(); + } + } + catch (Exception e) + { + System.out.println("Error: fetchALL: exception"); + System.out.println(e.getMessage()); + } + } // fetchAll +} // SpServer diff --git a/java/sqlj/SpCreate.db2 b/java/sqlj/SpCreate.db2 new file mode 100644 index 0000000..f908852 --- /dev/null +++ b/java/sqlj/SpCreate.db2 @@ -0,0 +1,165 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: SpCreate.db2 +-- +-- SAMPLE: How to catalog the stored procedures contained in SpServer.sqlj +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +CREATE PROCEDURE OUT_LANGUAGE (OUT LANGUAGE CHAR(8)) +SPECIFIC SQLJ_OUT_LANGUAGE +DYNAMIC RESULT SETS 0 +DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'SpServer.outLanguage'@ + +CREATE PROCEDURE OUT_PARAM (OUT medianSalary DOUBLE) +SPECIFIC SQLJ_OUT_PARAM +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'SpServer.outParameter'@ + +CREATE PROCEDURE IN_PARAMS ( + IN lowsal DOUBLE, + IN medsal DOUBLE, + IN highsal DOUBLE, + IN department CHAR(3)) +SPECIFIC SQLJ_IN_PARAMS +DYNAMIC RESULT SETS 0 +DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +MODIFIES SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'SpServer.inParams'@ + +CREATE PROCEDURE INOUT_PARAM (INOUT medianSalary DOUBLE) +SPECIFIC SQLJ_INOUT_PARAM +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +MODIFIES SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'SpServer.inoutParam'@ + +CREATE PROCEDURE CLOB_EXTRACT ( + IN number CHAR(6), + OUT buffer VARCHAR(1000)) +SPECIFIC SQLJ_CLOB_EXTRACT +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'SpServer.clobExtract'@ + +CREATE PROCEDURE DECIMAL_TYPE (INOUT decimalIn DECIMAL(10,2)) +SPECIFIC SQLJ_DEC_TYPE +DYNAMIC RESULT SETS 0 +DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'SpServer.decimalType'@ + +CREATE PROCEDURE ALL_DATA_TYPES ( + INOUT small SMALLINT, + INOUT intIn INTEGER, + INOUT bigIn BIGINT, + INOUT realIn REAL, + INOUT doubleIn DOUBLE, + OUT charOut CHAR(1), + OUT charsOut CHAR(15), + OUT varcharOut VARCHAR(12), + OUT dateOut DATE, + OUT timeOut TIME) +SPECIFIC SQLJ_ALL_DAT_TYPES +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'SpServer.allDataTypes'@ + +CREATE PROCEDURE ONE_RESULT_SET (IN salValue DOUBLE) +SPECIFIC SQLJ_ONE_RES_SET +DYNAMIC RESULT SETS 1 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'SpServer.resultSetToClient'@ + +CREATE PROCEDURE TWO_RESULT_SETS (IN salary DOUBLE) +SPECIFIC SQLJ_TWO_RES_SETS +DYNAMIC RESULT SETS 2 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE JAVA +NO DBINFO +FENCED +THREADSAFE +READS SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'SpServer.twoResultSets'@ + +connect reset@ diff --git a/java/sqlj/SpDrop.db2 b/java/sqlj/SpDrop.db2 new file mode 100644 index 0000000..57a7d01 --- /dev/null +++ b/java/sqlj/SpDrop.db2 @@ -0,0 +1,51 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: SpDrop.db2 +-- +-- SAMPLE: How to uncatalog the stored procedures contained in SpServer.sqlj +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +DROP PROCEDURE OUT_LANGUAGE (CHAR(8))@ + +DROP PROCEDURE OUT_PARAM (DOUBLE)@ + +DROP PROCEDURE IN_PARAMS (DOUBLE, DOUBLE, DOUBLE, CHAR(3))@ + +DROP PROCEDURE INOUT_PARAM (DOUBLE)@ + +DROP PROCEDURE CLOB_EXTRACT (CHAR(6), VARCHAR(1000))@ + +DROP PROCEDURE DECIMAL_TYPE (DECIMAL(10,2))@ + +DROP PROCEDURE ALL_DATA_TYPES (SMALLINT, INTEGER, BIGINT, REAL, DOUBLE, + CHAR(1), CHAR(15), VARCHAR(12), DATE, TIME)@ + +DROP PROCEDURE ONE_RESULT_SET (DOUBLE)@ + +DROP PROCEDURE TWO_RESULT_SETS (DOUBLE)@ + +connect reset@ diff --git a/java/sqlj/SpIterat.sqlj b/java/sqlj/SpIterat.sqlj new file mode 100644 index 0000000..6cc1141 --- /dev/null +++ b/java/sqlj/SpIterat.sqlj @@ -0,0 +1,40 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: SpIterat.sqlj +// +// SAMPLE: Iterator class file for SpServer.sqlj +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import sqlj.runtime.ForUpdate; +#sql public iterator SpIterat implements ForUpdate(double); + diff --git a/java/sqlj/SpServer.sqlj b/java/sqlj/SpServer.sqlj new file mode 100644 index 0000000..da1acdb --- /dev/null +++ b/java/sqlj/SpServer.sqlj @@ -0,0 +1,882 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: SpServer.sqlj +// +// SAMPLE: Code implementations of various types of stored procedures +// The stored procedures defined in this program are called by the +// client application SpClient.sqlj. Before building and running +// SpClient.sqlj, build the shared library by completing the following +// steps: +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Update makefile with a valid userid, password and +// an available port number. +// 2. Compile the server source file SpServer.sqlj (this will also +// compile the Utility file, Util.sqlj, erase the existing +// library/class files and copy the newly compiled class files, +// SpServer.class, SpContext.class, SpIterat.class, +// SpServerEmployees.class, SpServerSalary.class, +// SpServer_SJProfileKeys.class and SpServer_SJProfile0.ser +// from the current directory to the $(DB2PATH)\function directory): +// nmake/make SpServer +// 3. Compile the client source file SpClient.sqlj (this will also +// call the script 'spcat' to create and catalog the stored +// procedures): +// nmake/make SpClient +// 4. Run the client SpClient: +// java SpClient +// +// II) If you don't have a compatible make/nmake program on your +// system do the following: +// 1. Compile the utility file and the server source file with: +// sqlj Util.sqlj +// sqlj SpServer.sqlj +// 2. Update bldsqljs and bldsqlj build files with a valid userid +// and password. +// 3. Erase the existing library/class files (if exists), +// SpContext.class, SpIterat.class, SpServer.class, +// SpServerEmployees.class, SpServerSalary.class, +// SpServer_SJProfileKeys.class and SpServer_SJProfile0.ser +// from the following path, $(DB2PATH)\function. +// 4. Compile the Iterator class file for SpServer.sqlj with +// the following command: +// sqlj SpIterat.sqlj +// 5. Build the SQLj stored procedure server with the following +// command (It will also copy the following class files from +// the current directory to the $(DB2PATH)\function for you: +// SpContext.class, SpIterat.class, SpServer.class, +// SpServerEmployees.class, SpServerSalary.class, +// SpServer_SJProfileKeys.class and SpServer_SJProfile0.ser): +// bldsqljs SpServer +// 6. Register the stored procedures with the following script: +// spcat +// 7. Build the SQLj stored procedure client with the following +// command: +// bldsqlj SpClient +// 8. Run SpClient with: +// java SpClient +// +// Class SpServer contains nine methods: +// 1. outLanguage: returns the implementation language of the stored +// procedure library +// 2. outParameter: returns median salary of employee salaries +// 3. inParams: accepts 3 salary values and updates employee +// salaries in the EMPLOYEE table based on these values for a +// given department +// 4. inoutParam: accepts an input value and returns the median +// salary of those employees in the EMPLOYEE table who earn more +// than the input value +// 5. clobExtract: returns a section of a CLOB type as a string +// 6. decimalType: manipulates an INOUT DECIMAL parameter +// 7. allDataTypes: uses all of the common data types in a stored +// procedure +// 8. resultSetToClient: returns a result set to the client +// application +// 9. twoResultSets: returns two result sets to the client +// application +// +// SQL Statements USED: +// FETCH +// SELECT +// UPDATE +// +// OUTPUT FILE: SpClient.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; // JDBC classes +import java.io.*; // Input/Output classes +import java.math.BigDecimal; // Packed Decimal class +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql context SpContext; + +#sql iterator SpServerSalary(double); +#sql iterator SpServerEmployees(String, String, double); + +/////// +// SQLj stored procedure is in this class +/////// +public class SpServer +{ + //************************************************************************* + // Stored Procedure: outLanguage + // + // Purpose: Returns the code implementation language of + // routine 'OutLanguage' (as it appears in the + // database catalog) in an output parameter. + // + // Parameters: + // + // IN: (none) + // OUT: outLanguage - the code language of this routine + // + //************************************************************************* + public static void outLanguage(String[] outLanguage) // CHAR(8) + throws SQLException + { + + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + SpContext ctx = null; + + try + { + String procName; + String language; + + ctx = new SpContext("jdbc:default:connection", false); + + // initialize variables + procName = "OUT_LANGUAGE"; + + #sql [ctx] {SELECT language INTO :language + FROM syscat.procedures + WHERE procname = :procName}; + + outLanguage[0] = language; + + // clean up resources + ctx.close(); + } + + catch (SQLException sqle) + { + if(ctx != null) + { + try { ctx.close(); } catch(Exception e) {} + } + + errorCode = sqle.getErrorCode(); + throw new SQLException(errorCode + " : " + errorLabel + " FAILED"); + } + } // outLanguage + + //************************************************************************* + // Stored Procedure: outParameter + // + // Purpose: Sorts table STAFF by salary, locates and returns + // the median salary + // + // Parameters: + // + // IN: (none) + // OUT: outMedianSalary - median salary in table STAFF + // + //************************************************************************* + public static void outParameter(double[] outMedianSalary) + throws SQLException + { + + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + SpContext ctx = null; + int counter; + int numRecords; + SpServerSalary curOutParam; + double salary; + + try + { + ctx = new SpContext("jdbc:default:connection", false); + + // initialize variables + counter = 0; + salary = 0; + + errorLabel = "COUNT NUMBER OF ROWS"; + #sql [ctx] {SELECT COUNT(*) INTO :numRecords FROM staff}; + + // declare salary iterator + errorLabel = "DECLARE SALARY ITERATOR"; + #sql [ctx] curOutParam = {SELECT CAST(salary AS DOUBLE) FROM staff ORDER BY salary}; + + errorLabel = "MOVE TO NEXT ROW"; + while (counter < (numRecords / 2 + 1)) + { + #sql {FETCH :curOutParam INTO :salary}; + if (curOutParam.endFetch()) break; + counter++; + } + + errorLabel = "GET MEDIAN SALARY"; + outMedianSalary[0] = salary; + + // clean up resources + curOutParam.close(); + ctx.close(); + + } + catch (SQLException sqle) + { + if(ctx != null) + { + try { ctx.close(); } catch(Exception e) {} + } + + errorCode = sqle.getErrorCode(); + throw new SQLException(errorCode + " : " + errorLabel + " FAILED"); + } + } // outParameter + + //************************************************************************* + // Stored Procedure: inParams + // + // Purpose: Updates salaries of employees in department 'inDepartment' + // using inputs inLowSal, inMedSal, inHighSal as + // salary raise/adjustment values. + // + // Parameters: + // + // IN: inLowSal - new salary for low salary employees + // inMedSal - new salary for mid salary employees + // inHighSal - new salary for high salary employees + // inDepartment - department to use in SELECT predicate + // OUT: (none) + // + //************************************************************************* + public static void inParams(double inLowSal, + double inMedSal, + double inHighSal, + String inDepartment) // CHAR(3) + throws SQLException + { + String errorLabel = null; + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + + SpContext ctx = null; + double salary; + String cursorName; + SpIterat updateIterator; + + // initialize variables + salary = 0; + cursorName = ""; + + try + { + ctx = new SpContext("jdbc:default:connection", false); + + errorLabel = "DECLARE ITERATOR"; + #sql [ctx] updateIterator = {SELECT CAST(salary AS DOUBLE) + FROM employee + WHERE workdept = :inDepartment}; + + errorLabel = "FETCH FIRST ROW"; + #sql {FETCH :updateIterator INTO :salary}; + + if (updateIterator.endFetch()) + { + // iterator contains no data, so return SQLCODE 100 to client + errorLabel = "100 : NO DATA FOUND"; + } + else + { + while (!updateIterator.endFetch()) + { + if (inLowSal > salary) + { + errorLabel = "UPDATE -- LOW CASE"; + #sql [ctx] {UPDATE employee SET salary = :inLowSal + WHERE CURRENT OF :updateIterator}; + } + else if (inMedSal > salary) + { + errorLabel = "UPDATE -- MEDIUM CASE"; + #sql [ctx] {UPDATE employee SET salary = :inMedSal + WHERE CURRENT OF :updateIterator}; + } + else if (inHighSal > salary) + { + errorLabel = "UPDATE -- HIGH CASE"; + #sql [ctx] {UPDATE employee SET salary = :inHighSal + WHERE CURRENT OF :updateIterator}; + } + else + { + errorLabel = "UPDATE -- FINAL CASE"; + #sql [ctx] {UPDATE employee SET salary = (salary * 1.10) + WHERE CURRENT OF :updateIterator}; + } + #sql {FETCH :updateIterator INTO :salary}; + } + } + updateIterator.close(); + ctx.close(); + } + catch (SQLException sqle) + { + if( ctx != null ) + { + try { ctx.close(); } catch( Exception e ) {} + } + + errorCode = sqle.getErrorCode(); + if (errorLabel.equalsIgnoreCase("100 : NO DATA FOUND")) + throw new SQLException(sqle.getMessage()); + else + throw new SQLException(errorCode + " : " + errorLabel + " FAILED"); + } + } // inParams + + //************************************************************************* + // Stored Procedure: inOutParam + // + // Purpose: Calculates the median salary of all salaries in the STAFF + // table greater than the input median salary. + // + // Parameters: + // + // IN/OUT: inOutMedianSalary - median salary + // The input value is used in a SELECT + // predicate. Its output value is set to the + // median salary. + // + //************************************************************************* + public static void inoutParam(double[] inoutMedianSalary) + throws SQLException + { + SpContext ctx = null; + int counter; + int numRecords = 0; + double salary; + double inSalary; + String cursorName; + SpServerSalary curInOutParam; + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + // initialize variables + counter = 0; + salary = 0; + cursorName = ""; + inSalary = inoutMedianSalary[0]; + + try + { + ctx = new SpContext( "jdbc:default:connection", false ); + errorLabel = "GET NUMBER OF RECORDS"; + #sql [ctx] {SELECT COUNT(*) INTO :numRecords + FROM staff + WHERE CAST(salary AS DOUBLE) > :inSalary}; + + if (numRecords == 0) + { + // set errorCode to SQL0100 to indicate data not found + errorLabel = "100 : NO DATA FOUND"; + throw new SQLException(errorLabel); + } + else + { + errorLabel = "GET SALARY RESULT SET"; + #sql [ctx] curInOutParam = {SELECT CAST(salary AS DOUBLE) + FROM staff + WHERE CAST(salary AS DOUBLE) > :inSalary + ORDER BY salary}; + + while (counter < (numRecords / 2 + 1)) + { + errorLabel = "MOVE TO NEXT ROW"; + #sql {FETCH :curInOutParam INTO :salary}; + counter++; + } + + inoutMedianSalary[0] = salary; + + curInOutParam.close(); + } + ctx.close(); + } + catch (SQLException sqle) + { + if( ctx != null ) + { + try { ctx.close(); } catch( Exception e ) {} + } + + errorCode = sqle.getErrorCode(); + if (errorLabel.equalsIgnoreCase("100 : NO DATA FOUND")) + throw new SQLException(sqle.getMessage()); + else + throw new SQLException(errorCode + " : " + errorLabel + "FAILED"); + } + } // inoutParam + + //************************************************************************* + // Stored Procedure: clobExtract + // + // Purpose: Extracts department information from a large object (LOB) + // resume of employee data returns this information + // to the caller in output parameter outDeptInfo. + // + // Parameters: + // + // IN: inEmpNumber - employee number + // OUT: outDeptInfo - department information section of the + // employee's resume + // + //************************************************************************* + public static void clobExtract(String inEmpNumber, // CHAR(6) + String[] outDeptInfo) // VARCHAR(1000) + throws Exception + { + int counter; + int index; + int maximumLength; + byte[] clobBytes; + char[] clobData; + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + try + { + errorLabel = "GET CONNECTION"; + + // get caller's connection to the database + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + // choose the employee resume that matches the employee number + errorLabel = "SELECT STATEMENT"; + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT resume FROM emp_resume " + + " WHERE empno = '" + inEmpNumber + "'" + + " AND resume_format = 'ascii'"); + + if (rs.next()) + { + // copy the CLOB into an array of characters by converting all + // bytes into characters as they are read in + InputStream inStream = rs.getAsciiStream(1); + + // InputStream.available() may not work on larger files + maximumLength = inStream.available(); + clobBytes = new byte[maximumLength]; + clobData = new char[maximumLength]; + + inStream.read(clobBytes); + for (counter = 0; counter < maximumLength; counter++) + { + clobData[counter] = (char)clobBytes[counter]; + } + + String clob = String.valueOf(clobData); + + // copy substring from "Department Info" to "Education" + // into OUT parameter + index = clob.indexOf("Department Info"); + if (index == -1) + { + outDeptInfo[0] = "Resume does not contain a " + + "Department Info section."; + } + else + { + outDeptInfo[0] = clob.substring(clob.indexOf("Department Info"), + clob.indexOf("Education")); + } + } + else + { + outDeptInfo[0] = ("\nEmployee " + inEmpNumber + + " does not have a resume."); + } + rs.close(); + stmt.close(); + } + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + throw new SQLException(errorCode + " : " + errorLabel + "FAILED"); + } + } // clobExtract + + //************************************************************************* + // PARAMETER STYLE JAVA procedures do not support the DBINFO clause. + // The following PARAMETER STYLES can be used with DBINFO or PROGRAM TYPE + // clauses: + // - DB2SQL + // - GENERAL + // - GENERAL WITH NULLS + // - SQL + // Please see the spserver implementation for C/C++/CLI language to + // see this functionality. + //************************************************************************* + + //************************************************************************* + // PROGRAM TYPE MAIN is only valid for LANGUAGE C, COBOL or CLR, and + // following PARAMETER STYLE: + // - DB2SQL + // - GENERAL + // - GENERAL WITH NULLS + // - SQL + // Please see the spserver implementation for C/C++/CLI language to + // see this functionality. + //************************************************************************* + + //************************************************************************* + // Stored Procedure: decimalType + // + // Purpose: Takes in a decimal number as input, divides it by 2 + // and returns the resulting decimal rounded off to 2 + // decimal places. + // + // Parameters: + // + // INOUT: inOutDecimal - DECIMAL(10,2) + // + //************************************************************************* + public static void decimalType(BigDecimal[] inoutDecimal) // DECIMAL(10,2) + throws SQLException + { + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + try + { + // get caller's connection to the database + errorLabel = "GET CONNECTION"; + Connection con = DriverManager.getConnection("jdbc:default:connection"); + + if (inoutDecimal[0].equals(BigDecimal.valueOf(0))) + { + inoutDecimal[0].add(BigDecimal.valueOf(1)); + } + else + { + inoutDecimal[0] = inoutDecimal[0].divide(BigDecimal.valueOf(2), + BigDecimal.ROUND_HALF_UP); + } + + // close our connection + con.close(); + } + + catch (SQLException sqle) + { + errorCode = sqle.getErrorCode(); + throw new SQLException(errorCode + " : DECIMAL_TYPE FAILED"); + } + } // decimalType + + //************************************************************************* + // Stored Procedure: allDataTypes + // + // Purpose: Take each parameter and set it to a new output value. + // This sample shows only a subset of DB2 supported data types. + // For a full listing of DB2 data types, please see the SQL + // Reference. + // + // Parameters: + // + // INOUT: inOutSmallint, inOutInteger, inOutBigint, inOutReal, + // outDouble + // OUT: outChar, outChars, outVarchar, outDate, outTime + // + //************************************************************************* + public static void allDataTypes(short[] inoutSmallint, + int[] inoutInteger, + long[] inoutBigint, + float[] inoutReal, + double[] inoutDouble, + String[] outChar, // CHAR(1) + String[] outChars, // CHAR(15) + String[] outVarchar, // VARCHAR(13) + Date[] outDate, // DATE + Time[] outTime) // TIME + throws SQLException + { + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + SpContext ctx = null; + String query; + String hvOutChar; + String hvOutChars; + String hvOutVarchar; + Date hvOutDate; + Time hvOutTime; + Connection con = null; + ResultSet rs; + Statement stmt; + + try + { + // get caller's connection to the database + ctx = new SpContext("jdbc:default:connection", false); + con = ctx.getConnection(); + + if (inoutSmallint[0] == 0) + { + inoutSmallint[0] = 1; + } + else + { + inoutSmallint[0] = (short)(inoutSmallint[0] / 2); + } + + if (inoutInteger[0] == 0) + { + inoutInteger[0] = 1; + } + else + { + inoutInteger[0] = (inoutInteger[0] / 2); + } + + if (inoutBigint[0] == 0) + { + inoutBigint[0] = 1; + } + else + { + inoutBigint[0] = (inoutBigint[0] / 2); + } + + if (inoutReal[0] == 0) + { + inoutReal[0] = 1; + } + else + { + inoutReal[0] = (inoutReal[0] / 2); + } + + if (inoutDouble[0] == 0) + { + inoutDouble[0] = 1; + } + else + { + inoutDouble[0] = (inoutDouble[0] / 2); + } + + errorLabel = "SELECT MIDINIT, LASTNAME ..."; + #sql [ctx] {SELECT midinit, lastname, firstnme + INTO :hvOutChar, :hvOutChars, :hvOutVarchar + FROM employee + WHERE empno = '000180'}; + + // get the value of the midinit column + outChar[0] = hvOutChar; + // get the value of the lastname column + outChars[0] = hvOutChars; + // get the value of the firstnme column + outVarchar[0] = hvOutVarchar; + + // get current date using JDBC + query = "VALUES(CURRENT DATE)"; + + errorLabel = "create VALUES(CURRENT DATE)"; + // create the SQL statement + stmt = con.createStatement(); + + // get the result set + rs = stmt.executeQuery(query); + + // move to first row of result set + rs.next(); + + // get the date value + outDate[0] = rs.getDate(1); + + // clean up resources + rs.close(); + stmt.close(); + + // get current time using JDBC + query = "VALUES(CURRENT TIME)"; + + errorLabel = "create VALUES(CURRENT TIME)"; + // create the SQL statement + stmt = con.createStatement(); + + // get the result set + rs = stmt.executeQuery(query); + + // move to first row of result set + rs.next(); + + // get the time value + outTime[0] = rs.getTime(1); + + // clean up resources + rs.close(); + stmt.close(); + + // close our connection + ctx.close(); + } + + catch (SQLException sqle) + { + if(ctx != null) + { + try { ctx.close(); } catch( Exception e ) {} + } + + errorCode = sqle.getErrorCode(); + throw new SQLException(errorCode + " : " + errorLabel + " FAILED"); + } + } // allDataTypes + + //************************************************************************* + // Stored Procedure: resultSetToClient + // + // Purpose: Returns a result set to the caller that identifies employees + // with salaries greater than the value of input parameter + // inSalaryThreshold. + // + // Parameters: + // + // IN: inSalaryThreshold - salary + // OUT: outRs - ResultSet + // + //************************************************************************* + public static void resultSetToClient(double inSalaryThreshold, + ResultSet[] outRs) + throws SQLException + { + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + SpContext ctx = null; + SpServerEmployees curResSetToClient; + double inSalary; + inSalary = inSalaryThreshold; + + try + { + ctx = new SpContext( "jdbc:default:connection", false ); + + errorLabel = "SELECT STATEMENT"; + + // declare iterator for result set + #sql [ctx] curResSetToClient = {SELECT name, job, CAST(salary AS DOUBLE) + FROM staff + WHERE salary > :inSalary + ORDER BY salary}; + + // get the result set that is returned to the client + outRs[0] = curResSetToClient.getResultSet(); + + } + + catch (SQLException sqle) + { + if(ctx != null) + { + try { ctx.close(); } catch( Exception e ) {} + } + + errorCode = sqle.getErrorCode(); + throw new SQLException(errorCode + " : " + errorLabel + " FAILED"); + } + } // resultSetToClient + + //************************************************************************* + // Stored Procedure: twoResultSets + // + // Purpose: Returns two result sets to the caller. One result set + // consists of employee data of all employees with + // salaries greater than inSalaryThreshold. The other + // result set contains employee data for employees with salaries + // less than inSalaryThreshold. + // + // Parameters: + // + // IN: inSalaryThreshold - salary + // OUT: outRs1 - first ResultSet + // outRs2 - second ResultSet + // + //************************************************************************* + public static void twoResultSets(double inSalaryThreshold, + ResultSet[] outRs1, + ResultSet[] outRs2) + throws SQLException + { + SpContext ctx = null; + int errorCode = 0; // SQLCODE = 0 unless SQLException occurs + String errorLabel = null; + + SpServerEmployees curTwoResultSets1; + SpServerEmployees curTwoResultSets2; + double inSalary; + inSalary = inSalaryThreshold; + + try + { + ctx = new SpContext("jdbc:default:connection", false); + + errorLabel = "SELECT STATEMENT 1"; + // declare iterator for the first result set + #sql [ctx] curTwoResultSets1 = {SELECT name, job, CAST(salary AS DOUBLE) + FROM staff + WHERE salary > :inSalary + ORDER BY salary}; + + // get the first result set that is returned to the client + outRs1[0] = curTwoResultSets1.getResultSet(); + + errorLabel = "SELECT STATEMENT 2"; + // declare iterator for the second result set + #sql [ctx] curTwoResultSets2 = {SELECT name, job, CAST(salary AS DOUBLE) + FROM staff + WHERE salary < :inSalary + ORDER BY salary DESC}; + + // get the second result set that is returned to the client + outRs2[0] = curTwoResultSets2.getResultSet(); + ctx.close(); + + } + catch (SQLException sqle) + { + if(ctx != null) + { + try { ctx.close(); } catch( Exception e ) {} + } + + errorCode = sqle.getErrorCode(); + throw new SQLException(errorCode + " : " + errorLabel + " FAILED"); + } + } // twoResultSets + + //************************************************************************* + // PARAMETER STYLE GENERAL and GENERAL WITH NULLS can be specified when + // LANGUAGE C, COBOL, or CLR is used. + // Please see the spserver implementation for C/C++/CLI language to see + // this functionality. + //************************************************************************* + +} // SpServer diff --git a/java/sqlj/TbAST.sqlj b/java/sqlj/TbAST.sqlj new file mode 100644 index 0000000..e2f2e12 --- /dev/null +++ b/java/sqlj/TbAST.sqlj @@ -0,0 +1,287 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbAST.sqlj +// +// SAMPLE: How to use staging table for updating deferred AST +// +// This sample: +// 1. Creates a refresh-deferred summary table +// 2. Creates a staging table for this summary table +// 3. Applies contents of staging table to AST +// 4. Restores the data in a summary table +// +// SQL STATEMENTS USED: +// INSERT +// REFRESH +// SET INTEGRITY +// FETCH +// COMMIT +// +// Classes used from Util.java are: +// Db +// SqljException +// +// PREQUISITES : 1. Create the pre-requisite tables by running the command: +// TbAstScrpt +// Alternatively,you can run the command: +// db2 -tvf TbAst_setup.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj TbAst +// 2. Run the sample as: +// java TbAst +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf TbAst_cleanup.db2 +// +// OUTPUT FILE: TbAST.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator TbAST_Cursor0(int, int, int); + +class TbAST +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS THE USAGE OF STAGING TABLE TO UPDATE \n" + + "REFRESH DEFERRED AST AND RESTORE DATA IN A SUMMARY TABLE \n" + + "\n-----------------------------------------------------------\n"); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + // create a base table, summary table, staging table + System.out.println( + "\nBase table 't', summary table 'd_ast' and staging table 'g' \n" + + "are created in the setup script TbAst_setup.db2 using the commands\n" + + "'CREATE TABLE t(c1 SMALLINT NOT NULL,c2 SMALLINT NOT NULL,c3 SMALLINT,c4 SMALLINT)' \n" + + "'CREATE SUMMARY TABLE d_ast AS(SELECT c1, c2, COUNT(*) AS count FROM t GROUP BY c1, c2) \n" + + " DATA INITIALLY DEFERRED REFRESH DEFERRED' \n" + + "'CREATE TABLE g FOR d_ast PROPAGATE IMMEDIATE' \n"); + + // to show the propagation of changes of base table to + // summary tables through the staging table + System.out.println( + "\n-----------------------------------------------------------\n" + + "To show the propagation of changes from base table to \n" + + "summary tables through the staging table: \n" ); + propagateStagingToAst( ctx.getConnection() ); + + // to show restoring of data in a summary table + System.out.println( + "\n------------------------------------------------------------ \n" + + "To show restoring of data in a summary table"); + restoreSummaryTable( ctx.getConnection() ); + + // disconnect from 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // Show how to propagate the changes from base table to + // summary tables through the staging table + static void propagateStagingToAst(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "Bring staging table out of pending state \n"+ + " SET INTEGRITY FOR g IMMEDIATE CHECKED"); + stmt.executeUpdate("SET INTEGRITY FOR G IMMEDIATE CHECKED"); + #sql {COMMIT}; + + System.out.println( + "\nRefresh summary table, get it out of pending state. \n" + + " REFRESH TABLE d_ast NOT INCREMENTAL\n"); + #sql {REFRESH TABLE d_ast NOT INCREMENTAL}; + #sql {COMMIT}; + + System.out.println( + "\nInsert data into base table T\n" + + " INSERT INTO t VALUES(1,1,1,1), \n" + + " (2,2,2,2), \n" + + " (1,1,1,1), \n" + + " (3,3,3,3)"); + #sql {INSERT INTO t VALUES (1,1,1,1), + (2,2,2,2), + (1,1,1,1), + (3,3,3,3) }; + #sql {COMMIT}; + + System.out.println( + "\nDisplay the contents of staging table g.\n" + + "The Staging table contains incremental changes to base table."); + displayTable("g"); + + System.out.println( + "\n\nRefresh the summary table \n" + + " REFRESH TABLE d_ast INCREMENTAL\n"); + #sql {REFRESH TABLE d_ast INCREMENTAL}; + #sql {COMMIT}; + + System.out.println( + "Display the contents of staging table g \n" + + " NOTE: The staging table is pruned after AST is \n" + + " refreshed. The contents are propagated to AST \n" + + " from the staging table"); + displayTable("g"); + + System.out.println( + "\nDisplay the contents of AST\n" + + "Summary table has the changes propagated from staging table"); + displayTable("d_ast"); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // propagateStagingToAst + + // Shows how to restore the data in a summary table + static void restoreSummaryTable(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + System.out.println( + "\nBlock all modifications to the summary table \n" + + "by setting the integrity to off \n" + + " (g is placed in pending and g.CC=N) \n" + + "\n SET INTEGRITY FOR g OFF"); + stmt.executeUpdate("SET INTEGRITY FOR g OFF"); + #sql {COMMIT}; + + System.out.println( + "\nExport the query definition in summary table and load \n" + + "directly back to the summary table.\n" + + " (d_ast and g both in pending \n" + + "\n SET INTEGRITY FOR d_ast OFF CASCADE IMMEDIATE\n"); + stmt.executeUpdate("SET INTEGRITY FOR d_ast OFF CASCADE IMMEDIATE"); + #sql {COMMIT}; + + System.out.println( + "Prune staging table and place it in normal state\n" + + " (g.CC=F)\n" + + "\n SET INTEGRITY FOR g IMMEDIATE CHECKED PRUNE\n"); + stmt.executeUpdate("SET INTEGRITY FOR g IMMEDIATE CHECKED PRUNE"); + #sql {COMMIT}; + + System.out.println( + "Changing staging table state to U \n" + + " (g.CC to U)\n" + + "\n SET INTEGRITY FOR g STAGING IMMEDIATE UNCHECKED\n"); + stmt.executeUpdate("SET INTEGRITY FOR g STAGING IMMEDIATE UNCHECKED"); + #sql {COMMIT}; + + System.out.println( + "\nPlace d_ast in normal and d_ast.CC to U \n" + + "\n SET INTEGRITY FOR d_ast MATERIALIZED QUERY" + + " IMMEDIATE UNCHECKED\n" ); + stmt.executeUpdate( + "SET INTEGRITY FOR d_ast MATERIALIZED QUERY IMMEDIATE UNCHECKED"); + #sql {COMMIT}; + + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // restoreSummaryTable + + // Displays the contents of the table being passed as the argument + static void displayTable(String tableName) + { + TbAST_Cursor0 cur0; + int c1 = 0; + int c2 = 0; + int count = 0; + + try + { + if (tableName.equals("g")) + { + #sql cur0 = {SELECT c1, c2, count FROM g}; + System.out.println( + "\n SELECT c1, c2, count FROM g\n" + + "\n C1 C2 COUNT " + + "\n ------------------"); + } + else + { + #sql cur0 = {SELECT c1, c2, count FROM d_ast}; + System.out.println( + "\n SELECT c1, c2, count FROM d_ast\n" + + "\n C1 C2 COUNT " + + "\n ------------------"); + } + + // retrieve and display the result from the SELECT statement + #sql {FETCH :cur0 INTO :c1, :c2, :count}; + + while (!cur0.endFetch()) + { + System.out.println(" " + c1 + " " + c2 + " " + count ); + #sql {FETCH :cur0 INTO :c1, :c2, :count}; + } + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // displayTable +} // TbAST diff --git a/java/sqlj/TbASTScrpt b/java/sqlj/TbASTScrpt new file mode 100644 index 0000000..2b71740 --- /dev/null +++ b/java/sqlj/TbASTScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: TbASTScrpt +# TbAST_cleanup.db2 drops tables created by LargeRid_setup.db2 for the +# sample TbAST.sqlj +# TbAST_setup.db2 creates tables necessary for execution of the sample +# TbAST.sqlj +# Both CLP scripts can be run on their own +# Usage: TbASTScrpt + +db2 -tvf TbAST_cleanup.db2 +db2 -tvf TbAST_setup.db2 diff --git a/java/sqlj/TbAST_cleanup.db2 b/java/sqlj/TbAST_cleanup.db2 new file mode 100644 index 0000000..e297bbe --- /dev/null +++ b/java/sqlj/TbAST_cleanup.db2 @@ -0,0 +1,50 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: TbAst_cleanup.db2 +-- +-- SAMPLE: Cleanup script for the sample TbAst.sqlj +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf TbAst_cleanup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +---------------------------------------------------------------------------- + +connect to sample; + +-- Dropping a base table implicitly drops summary table defined +-- on it which in turn cascades to dropping its staging table + +DROP TABLE t; + +connect reset; diff --git a/java/sqlj/TbAST_setup.db2 b/java/sqlj/TbAST_setup.db2 new file mode 100644 index 0000000..ec2f68e --- /dev/null +++ b/java/sqlj/TbAST_setup.db2 @@ -0,0 +1,70 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: TbAst_setup.db2 +-- +-- SAMPLE: This sample serves as the setup script for the sample +-- TbAst.sqlj +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf TbAst_setup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad + +---------------------------------------------------------------------------- + +connect to sample; + +-- create base table, summary table, staging table + +-- create base table + +CREATE TABLE t + (c1 SMALLINT NOT NULL, + c2 SMALLINT NOT NULL, + c3 SMALLINT, + c4 SMALLINT); + +-- create summary table + +CREATE SUMMARY TABLE d_ast AS + (SELECT c1, c2, COUNT(*) AS count + FROM t + GROUP BY c1, c2) + DATA INITIALLY DEFERRED + REFRESH DEFERRED; + +-- create staging table + +CREATE TABLE g FOR d_ast PROPAGATE IMMEDIATE; + +connect reset; diff --git a/java/sqlj/TbCompress.sqlj b/java/sqlj/TbCompress.sqlj new file mode 100644 index 0000000..31b268a --- /dev/null +++ b/java/sqlj/TbCompress.sqlj @@ -0,0 +1,199 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbCompress.sqlj +// +// SAMPLE: How to create tables with null and default value compression +// option. +// +// SQL STATEMENTS USED: +// CREATE TABLE +// ALTER TABLE +// DROP TABLE +// COMMIT +// +// Classes used from Util.java are: +// Db +// SqljException +// +// OUTPUT FILE: TbCompress.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class TbCompress +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO USE NULL AND DEFAULT VALUE\n" + + "COMPRESSION OPTION AT TABLE LEVEL AND COLUMN LEVEL \n"); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + // create a new table + tbCreate(); + + // activate null and default value compression + tbCompress(); + + // drop the table created + tbDrop(); + + // disconnect from 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // Create a new table + static void tbCreate() + { + try + { + // create base table + System.out.println( + "\n-----------------------------------------------------------\n" + + "USE THE SQL STATEMENT\n" + + " CREATE TABLE\n" + + "TO CREATE A TABLE\n\n" + + " CREATE TABLE comp_tab(col1 INT NOT NULL WITH DEFAULT,\n" + + " col2 CHAR(7),\n" + + " col3 VARCHAR(7) NOT NULL,\n" + + " col4 DOUBLE) \n"); + + #sql {CREATE TABLE comp_tab(col1 INT NOT NULL WITH DEFAULT, + col2 CHAR(7), + col3 VARCHAR(7) NOT NULL, + col4 DOUBLE)}; + + System.out.println(" COMMIT"); + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // tbCreate + + // Activate null and default value compression + static void tbCompress() + { + try + { + System.out.println( + "\n-----------------------------------------------------------\n" + + "USE THE SQL STATEMENT \n" + + " ALTER TABLE\n" + + "TO ALTER COMPRESSION OPTIONS OF THE TABLE\n\n" + + "To activate VALUE COMPRESSION at table level and COMPRESS \n" + + "SYSTEM DEFAULT at column level \n\n" + + " ALTER TABLE comp_tab ACTIVATE VALUE COMPRESSION \n\n" + + "Rows will be formatted using the new row format on subsequent\n" + + "insert, load and update operation, and NULL values will not be\n" + + "taking up space if applicable.\n"); + + #sql {ALTER TABLE comp_tab ACTIVATE VALUE COMPRESSION}; + #sql {COMMIT}; + + // if the table comp_tab does not have many NULL values, enabling + // compression will result in using more disk space than using + // the old row format + + System.out.println( + "\nTo save more disk space on system default value for column\n" + + "col1, enter\n" + + "\n ALTER TABLE comp_tab ALTER col1 COMPRESS SYSTEM DEFAULT\n" + + "\nOn subsequent insert, load, and update operations, numerical\n" + + "0 value (occupying 4 bytes of storage) for column col1 will\n" + + "not be saved on disk.\n"); + + #sql {ALTER TABLE comp_tab ALTER col1 COMPRESS SYSTEM DEFAULT}; + #sql {COMMIT}; + + System.out.println( + "\nTo switch the table to use the old format, enter\n\n" + + " ALTER TABLE comp_tab DEACTIVATE VALUE COMPRESSION\n\n" + + "Rows inserted, loaded or updated after the ALTER statement\n" + + "will have old row format.\n"); + + #sql {ALTER TABLE comp_tab DEACTIVATE VALUE COMPRESSION}; + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // tbCompress + + // Drop the table created + static void tbDrop() + { + try + { + // drop the table + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT\n" + + " DROP TABLE\n" + + "TO DROP THE TABLE\n\n" + + " DROP TABLE comp_tab\n" + + "\n COMMIT"); + + #sql {DROP TABLE comp_tab}; + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // tbDrop +} // TbCompress diff --git a/java/sqlj/TbConstr.sqlj b/java/sqlj/TbConstr.sqlj new file mode 100644 index 0000000..4c392b7 --- /dev/null +++ b/java/sqlj/TbConstr.sqlj @@ -0,0 +1,1426 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbConstr.sqlj +// +// SAMPLE: How to create, use and drop constraints +// +// SQL Statements USED: +// CREATE TABLE +// DROP TABLE +// DELETE +// COMMIT +// ROLLBACK +// +// JAVA 2 CLASSES USED: +// Statement +// +// Classes used from Util.sqlj are: +// Db +// SqljException +// +// OUTPUT FILE: TbConstr.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class TbConstr +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CREATE, USE AND DROP CONSTRAINTS."); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + demo_NOT_NULL( ctx.getConnection() ); + demo_UNIQUE( ctx.getConnection() ); + demo_PRIMARY_KEY( ctx.getConnection() ); + demo_CHECK( ctx.getConnection() ); + demo_CHECK_INFO(); + demo_WITH_DEFAULT( ctx.getConnection() ); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "#####################################################\n" + + "# Create tables for FOREIGN KEY sample functions #\n" + + "#####################################################"); + + FK_TwoTablesCreate( ctx.getConnection() ); + + demo_FK_OnInsertShow( ctx.getConnection() ); + demo_FK_ON_UPDATE_NO_ACTION( ctx.getConnection() ); + demo_FK_ON_UPDATE_RESTRICT( ctx.getConnection() ); + demo_FK_ON_DELETE_CASCADE( ctx.getConnection() ); + demo_FK_ON_DELETE_SET_NULL( ctx.getConnection() ); + demo_FK_ON_DELETE_NO_ACTION( ctx.getConnection() ); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "########################################################\n" + + "# Drop tables created for FOREIGN KEY sample functions #\n" + + "########################################################"); + FK_TwoTablesDrop(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // helping function: This function creates two foreign keys + static void FK_TwoTablesCreate(Connection con) + { + try + { + System.out.println(); + System.out.println( + " CREATE TABLE dept_details(deptno CHAR(3) NOT NULL,\n" + + " deptname VARCHAR(20),\n" + + " CONSTRAINT pk_dept\n" + + " PRIMARY KEY(deptno))"); + + #sql {CREATE TABLE dept_details(deptno CHAR(3) NOT NULL, + deptname VARCHAR(20), + CONSTRAINT pk_dept + PRIMARY KEY(deptno))}; + + System.out.println(); + System.out.println( + " INSERT INTO dept_details VALUES('A00', 'ADMINISTRATION'),\n" + + " ('B00', 'DEVELOPMENT'),\n" + + " ('C00', 'SUPPORT')"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO dept_details VALUES('A00', 'ADMINISTRATION')," + + " ('B00', 'DEVELOPMENT')," + + " ('C00', 'SUPPORT')"); + stmt.close(); + + System.out.println(); + System.out.println( + " CREATE TABLE emp_details(empno CHAR(4),\n" + + " empname VARCHAR(10),\n" + + " dept_no CHAR(3))"); + + #sql {CREATE TABLE emp_details(empno CHAR(4), + empname VARCHAR(10), + dept_no CHAR(3))}; + + System.out.println(); + System.out.println( + " INSERT INTO emp_details VALUES('0010', 'Smith', 'A00'),\n" + + " ('0020', 'Ngan', 'B00'),\n" + + " ('0030', 'Lu', 'B00'),\n" + + " ('0040', 'Wheeler', 'B00'),\n" + + " ('0050', 'Burke', 'C00'),\n" + + " ('0060', 'Edwards', 'C00'),\n" + + " ('0070', 'Lea', 'C00')"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO emp_details VALUES('0010', 'Smith', 'A00')," + + " ('0020', 'Ngan', 'B00')," + + " ('0030', 'Lu', 'B00')," + + " ('0040', 'Wheeler', 'B00')," + + " ('0050', 'Burke', 'C00')," + + " ('0060', 'Edwards', 'C00')," + + " ('0070', 'Lea', 'C00')"); + stmt1.close(); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // FK_TwoTablesCreate + + // helping function + static void FK_TwoTablesDisplay(Connection con) + { + try + { + System.out.println(); + System.out.println(" SELECT * FROM dept_details"); + + System.out.println(" DEPTNO DEPTNAME\n" + + " ------- --------------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM dept_details"); + + while (rs.next()) + { + System.out.println( + " " + Data.format(rs.getString("deptno"),7) + + " " + Data.format(rs.getString("deptname"),20)); + } + rs.close(); + stmt.close(); + + System.out.println(); + System.out.println(" SELECT * FROM emp_details"); + + System.out.println(" EMPNO EMPNAME DEPT_NO\n" + + " ----- ---------- -------"); + + Statement stmt1 = con.createStatement(); + ResultSet rs1 = stmt1.executeQuery("SELECT * FROM emp_details"); + while(rs1.next()) + { + System.out.print( + " " + Data.format(rs1.getString("empno"),5) + + " " + Data.format(rs1.getString("empname"),10)); + + String deptNo = rs1.getString("dept_no"); + if(deptNo !=null) + { + System.out.print(" " + Data.format(deptNo,3)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + rs1.close(); + stmt1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // FK_TwoTablesDisplay + + // helping function + static void FK_TwoTablesDrop() + { + try + { + System.out.println(); + System.out.println(" DROP TABLE dept_details"); + + #sql {DROP TABLE dept_details}; + + System.out.println(); + System.out.println(" DROP TABLE emp_details"); + + #sql {DROP TABLE emp_details}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // FK_TwoTablesDrop + + // helping function + static void FK_Create(String ruleClause, Connection con) + { + try + { + System.out.println(); + System.out.println(" ALTER TABLE emp_details\n" + + " ADD CONSTRAINT fk_dept\n" + + " FOREIGN KEY(dept_no)\n" + + " REFERENCES dept_details(deptno)\n" + + " " + ruleClause); + + Statement stmt = con.createStatement(); + stmt.execute("ALTER TABLE emp_details" + + " ADD CONSTRAINT fk_dept" + + " FOREIGN KEY(dept_no)" + + " REFERENCES dept_details(deptno) " + + " " + ruleClause); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // FK_Create + + // helping function + static void FK_Drop(Connection con) + { + try + { + System.out.println(); + System.out.println(" ALTER TABLE emp_details DROP CONSTRAINT fk_dept"); + + Statement stmt = con.createStatement(); + stmt.execute("ALTER TABLE emp_details DROP CONSTRAINT fk_dept"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // FK_Drop + + // This function demonstrates how to use a 'NOT NULL' constraint. + static void demo_NOT_NULL(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " DROP TABLE\n" + + "TO SHOW A 'NOT NULL' CONSTRAINT."); + + // Create a table called emp_sal with a 'NOT NULL' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE emp_sal(lastname VARCHAR(10) NOT NULL,\n" + + " firstname VARCHAR(10),\n" + + " salary DECIMAL(7, 2))"); + + #sql {CREATE TABLE emp_sal(lastname VARCHAR(10) NOT NULL, + firstname VARCHAR(10), + salary DECIMAL(7, 2))}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // Insert a row in the table emp_sal with NULL as the lastname. + // This insert will fail with an expected error. + try + { + System.out.println(); + System.out.println( + " INSERT INTO emp_sal VALUES(NULL, 'PHILIP', 17000.00)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO emp_sal VALUES(NULL, 'PHILIP', 17000.00)"); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // drop the table emp_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE emp_sal"); + + #sql {DROP TABLE emp_sal}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demo_NOT_NULL + + // This function demonstrates how to use a 'UNIQUE' constraint. + static void demo_UNIQUE(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ALTER TABLE\n" + + " DROP TABLE\n" + + "TO SHOW A 'UNIQUE' CONSTRAINT."); + + // Create a table called emp_sal with a 'UNIQUE' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE emp_sal(lastname VARCHAR(10) NOT NULL,\n" + + " firstname VARCHAR(10) NOT NULL,\n" + + " salary DECIMAL(7, 2),\n" + + " CONSTRAINT unique_cn\n" + + " UNIQUE(lastname, firstname))"); + + #sql {CREATE TABLE emp_sal(lastname VARCHAR(10) NOT NULL, + firstname VARCHAR(10) NOT NULL, + salary DECIMAL(7, 2), + CONSTRAINT unique_cn + UNIQUE(lastname, firstname))}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // Insert two rows into the table emp_sal that have the same lastname + // and firstname values. The insert will fail with an expected error + // because the rows violate the PRIMARY KEY constraint. + try + { + System.out.println(); + System.out.println( + " INSERT INTO emp_sal VALUES('SMITH', 'PHILIP', 17000.00),\n" + + " ('SMITH', 'PHILIP', 21000.00)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO emp_sal VALUES('SMITH', 'PHILIP', 17000.00), " + + " ('SMITH', 'PHILIP', 21000.00)"); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // drop the 'UNIQUE' constraint on the table emp_sal + try + { + System.out.println(); + System.out.println(" ALTER TABLE emp_sal DROP CONSTRAINT unique_cn"); + + #sql {ALTER TABLE emp_sal DROP CONSTRAINT unique_cn}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the table emp_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE emp_sal"); + + #sql {DROP TABLE emp_sal}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demo_UNIQUE + + // This function demonstrates how to use a 'PRIMARY KEY' constraint. + static void demo_PRIMARY_KEY(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ALTER TABLE\n" + + " DROP TABLE\n" + + "TO SHOW A 'PRIMARY KEY' CONSTRAINT."); + + // Create a table called emp_sal with a 'PRIMARY KEY' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE emp_sal(lastname VARCHAR(10) NOT NULL,\n" + + " firstname VARCHAR(10) NOT NULL,\n" + + " salary DECIMAL(7, 2),\n" + + " CONSTRAINT pk_cn\n" + + " PRIMARY KEY(lastname, firstname))"); + + #sql {CREATE TABLE emp_sal(lastname VARCHAR(10) NOT NULL, + firstname VARCHAR(10) NOT NULL, + salary DECIMAL(7, 2), + CONSTRAINT pk_cn + PRIMARY KEY(lastname, firstname))}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // Insert two rows into the table emp_sal that have the same lastname + // and firstname values. The insert will fail with an expected error + // because the rows violate the PRIMARY KEY constraint. + try + { + System.out.println(); + System.out.println( + " INSERT INTO emp_sal VALUES('SMITH', 'PHILIP', 17000.00),\n" + + " ('SMITH', 'PHILIP', 21000.00)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO emp_sal VALUES('SMITH', 'PHILIP', 17000.00)," + + " ('SMITH', 'PHILIP', 21000.00)"); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // drop the 'PRIMARY KEY' constraint on the table emp_sal + try + { + System.out.println(); + System.out.println(" ALTER TABLE emp_sal DROP CONSTRAINT pk_cn"); + + #sql {ALTER TABLE emp_sal DROP CONSTRAINT pk_cn}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the table emp_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE emp_sal"); + + #sql {DROP TABLE emp_sal}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demo_PRIMARY_KEY + + // This function demonstrates how to use a 'CHECK' constraint. + static void demo_CHECK(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ALTER TABLE\n" + + " DROP TABLE\n" + + "TO SHOW A 'CHECK' CONSTRAINT."); + + // Create a table called emp_sal with a 'CHECK' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE emp_sal(lastname VARCHAR(10),\n" + + " firstname VARCHAR(10),\n" + + " salary DECIMAL(7, 2),\n" + + " CONSTRAINT check_cn\n" + + " CHECK(salary < 25000.00))"); + + #sql {CREATE TABLE emp_sal(lastname VARCHAR(10), + firstname VARCHAR(10), + salary DECIMAL(7, 2), + CONSTRAINT check_cn + CHECK(salary < 25000.00))}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // Insert a row in the table emp_sal that violates the rule defined + // in the 'CHECK' constraint. This insert will fail with an expected + // error. + try + { + System.out.println(); + System.out.println( + " INSERT INTO emp_sal VALUES('SMITH', 'PHILIP', 27000.00)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO emp_sal VALUES('SMITH', 'PHILIP', 27000.00)"); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // drop the 'CHECK' constraint on the table emp_sal + try + { + System.out.println(); + System.out.println(" ALTER TABLE emp_sal DROP CONSTRAINT check_cn"); + + #sql {ALTER TABLE emp_sal DROP CONSTRAINT check_cn}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the table emp_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE emp_sal"); + + #sql {DROP TABLE emp_sal}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demo_CHECK + + // This function demonstrates how to use an 'INFORMATIONAL' constraint. + static void demo_CHECK_INFO() + { + try + { + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ALTER TABLE\n" + + " DROP TABLE\n" + + "TO SHOW AN 'INFORMATIONAL' CONSTRAINT."); + + // create a table called emp_details with a 'CHECK' constraint + System.out.println( + "\n CREATE TABLE emp_details(empno INTEGER NOT NULL PRIMARY KEY,\n" + + " name VARCHAR(10),\n" + + " firstname VARCHAR(20),\n" + + " salary INTEGER CONSTRAINT minsalary\n" + + " CHECK (salary >= 25000)\n" + + " NOT ENFORCED\n" + + " ENABLE QUERY OPTIMIZATION)\n"); + #sql {CREATE TABLE emp_details(empno INTEGER NOT NULL PRIMARY KEY, + name VARCHAR(10), + firstname VARCHAR(20), + salary INTEGER CONSTRAINT minsalary + CHECK (salary >= 25000) + NOT ENFORCED + ENABLE QUERY OPTIMIZATION)}; + #sql {COMMIT}; + System.out.println(" COMMIT"); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + // insert data that doesn't satisfy the constraint 'minsalary'. + // database manager does not enforce the constraint for IUD operations + System.out.println( + "\n\nTO SHOW NOT ENFORCED OPTION\n" + + "\n INSERT INTO emp_details VALUES(1, 'SMITH', 'PHILIP', 1000)\n"); + #sql {INSERT INTO emp_details VALUES(1, 'SMITH', 'PHILIP', 1000)}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + // alter the constraint to make it ENFORCED by database manager + System.out.println( + "Alter the constraint to make it ENFORCED by database manager\n" + + "\n ALTER TABLE emp_details ALTER CHECK minsalary ENFORCED"); + #sql {ALTER TABLE emp_details ALTER CHECK minsalary ENFORCED}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + try + { + // delete entries from EMP_DETAILS Table + System.out.println("\n DELETE FROM emp_details"); + #sql {DELETE FROM emp_details}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + // alter the constraint to make it ENFORCED by database manager + System.out.println( + "\n\nTO SHOW ENFORCED OPTION\n" + + "\n ALTER TABLE emp_details ALTER CHECK minsalary ENFORCED\n "); + #sql {ALTER TABLE emp_details ALTER CHECK minsalary ENFORCED}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + // insert table with data not conforming to the constraint 'minsalary' + // database manager enforces the constraint for IUD operations + System.out.println( + " INSERT INTO emp_details VALUES(1, 'SMITH', 'PHILIP', 1000)"); + #sql {INSERT INTO emp_details VALUES(1, 'SMITH', 'PHILIP', 1000)}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + try + { + // drop table + System.out.println("\n DROP TABLE emp_details"); + #sql {DROP TABLE emp_details}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demo_CHECK_INFO + + // This function demonstrates how to use a 'WITH DEFAULT' constraint. + static void demo_WITH_DEFAULT(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " DROP TABLE\n" + + "TO SHOW A 'WITH DEFAULT' CONSTRAINT."); + + // Create a table called emp_sal with a 'WITH DEFAULT' constraint + try + { + System.out.println(); + System.out.println( + " CREATE TABLE emp_sal(lastname VARCHAR(10),\n" + + " firstname VARCHAR(10),\n" + + " salary DECIMAL(7, 2) " + + "WITH DEFAULT 17000.00)"); + + #sql { + CREATE TABLE emp_sal(lastname VARCHAR(10), + firstname VARCHAR(10), + salary DECIMAL(7, 2) WITH DEFAULT 17000.00)}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // Insert three rows into the table emp_sal, without any value for the + // the third column. Since the third column is defined with a default + // value of 17000.00, the third column for each of these three rows + // will be set to 17000.00. + try + { + System.out.println(); + System.out.println( + " INSERT INTO emp_sal(lastname, firstname)\n" + + " VALUES('SMITH', 'PHILIP'),\n" + + " ('PARKER', 'JOHN'),\n" + + " ('PEREZ', 'MARIA')"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO emp_sal(lastname, firstname)"+ + " VALUES('SMITH', 'PHILIP')," + + " ('PARKER', 'JOHN')," + + " ('PEREZ', 'MARIA')"); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // retrieve and display the data in the table emp_sal + try + { + System.out.println(); + System.out.println(" SELECT * FROM emp_sal"); + System.out.println(" FIRSTNAME LASTNAME SALARY\n" + + " ---------- ---------- --------"); + + Statement stmt = con.createStatement(); + ResultSet rs3 = stmt.executeQuery("SELECT * FROM emp_sal"); + + while (rs3.next()) + { + System.out.println(" " + + Data.format(rs3.getString("firstname"),10) + " " + + Data.format(rs3.getString("lastname"),10) + " " + + Data.format(rs3.getDouble("salary"),7,2)); + } + rs3.close(); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the table emp_sal + try + { + System.out.println(); + System.out.println(" DROP TABLE emp_sal"); + + #sql {DROP TABLE emp_sal}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demo_WITH_DEFAULT + + // This function demonstrates how to insert into a foreign key + static void demo_FK_OnInsertShow(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " INSERT\n" + + " ROLLBACK\n" + + "TO SHOW HOW A FOREIGN KEY WORKS ON INSERT."); + + + // display the initial content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // create a foreign key on the 'emp_details' table that reference the + // 'dept_details' table + FK_Create("", con); + + // insert an entry into the parent table, 'dept_details' + try + { + System.out.println(); + System.out.println(" INSERT INTO dept_details VALUES('D00', 'SALES')"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO dept_details VALUES('D00', 'SALES')"); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // insert an entry into the child table, 'emp_details' + try + { + System.out.println(); + System.out.println( + " INSERT INTO emp_details VALUES('0080', 'Pearce', 'E03')"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO emp_details VALUES('0080', 'Pearce', 'E03')"); + stmt1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // display the final content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + + #sql {ROLLBACK}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + + } // demo_FK_OnInsertShow + + // This function demonstrates how to use an 'ON UPDATE NO ACTION' + // foreign key + static void demo_FK_ON_UPDATE_NO_ACTION(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " UPDATE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON UPDATE NO ACTION' FOREIGN KEY."); + + // display the initial content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // create an 'ON UPDATE NO ACTION' foreign key + FK_Create("ON UPDATE NO ACTION", con); + + // update the parent table, 'dept_details' + try + { + System.out.println(); + System.out.println( + " UPDATE dept_details SET deptno = 'E01' WHERE deptno = 'A00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE dept_details SET deptno = 'E01' WHERE deptno = 'A00' "); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // update the parent table, 'dept_details' + try + { + System.out.println(); + System.out.println( + " UPDATE dept_details\n" + + " SET deptno = CASE\n" + + " WHEN deptno = 'A00' THEN 'B00'\n" + + " WHEN deptno = 'B00' THEN 'A00'\n" + + " END\n" + + " WHERE deptno = 'A00' OR deptno = 'B00'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "UPDATE dept_details" + + " SET deptno = CASE" + + " WHEN deptno = 'A00' THEN 'B00'" + + " WHEN deptno = 'B00' THEN 'A00'" + + " END" + + " WHERE deptno = 'A00' OR deptno = 'B00'"); + stmt1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // update the child table, 'emp_details' + try + { + System.out.println(); + System.out.println( + " UPDATE emp_details SET dept_no = 'G11' WHERE empname = 'Wheeler'"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "UPDATE emp_details SET dept_no = 'G11' WHERE empname = 'Wheeler' "); + stmt2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // display the final content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + + #sql {ROLLBACK}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + } // demo_FK_ON_UPDATE_NO_ACTION + + // This function demonstrates how to use an 'ON UPDATE RESTRICT' + // foreign key + static void demo_FK_ON_UPDATE_RESTRICT(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " UPDATE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON UPDATE RESTRICT' FOREIGN KEY."); + + // display the initial content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // create an 'ON UPDATE RESTRICT' foreign key + FK_Create("ON UPDATE RESTRICT", con); + + // update the parent table, 'dept_details', with data that violates the 'ON + // UPDATE RESTRICT' foreign key. An error is expected to be returned. + try + { + System.out.println(); + System.out.println( + " UPDATE dept_details SET deptno = 'E01' WHERE deptno = 'A00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE dept_details SET deptno = 'E01' WHERE deptno = 'A00' "); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // update the parent table, 'dept_details', with data that violates the 'ON + // UPDATE RESTRICT' foreign key. An error is expected to be returned. + try + { + System.out.println(); + System.out.println( + " UPDATE dept_details\n" + + " SET deptno = CASE\n" + + " WHEN deptno = 'A00' THEN 'B00'\n" + + " WHEN deptno = 'B00' THEN 'A00'\n" + + " END\n" + + " WHERE deptno = 'A00' OR deptno = 'B00'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "UPDATE dept_details" + + " SET deptno = CASE " + + " WHEN deptno = 'A00' THEN 'B00' " + + " WHEN deptno = 'B00' THEN 'A00' " + + " END " + + " WHERE deptno = 'A00' OR deptno = 'B00' "); + stmt1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // update the child table, 'emp_details', with data that violates the 'ON + // UPDATE RESTRICT' foreign key. An error is expected to be returned. + try + { + System.out.println(); + System.out.println( + " UPDATE emp_details SET dept_no = 'G11' WHERE empname = 'Wheeler'"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "UPDATE emp_details SET dept_no = 'G11' WHERE empname = 'Wheeler'"); + stmt2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // display the final content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + + #sql {ROLLBACK}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + + } // demo_FK_ON_UPDATE_RESTRICT + + // This function demonstrates how to use an 'ON DELETE CASCADE' foreign key + static void demo_FK_ON_DELETE_CASCADE(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " DELETE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON DELETE CASCADE' FOREIGN KEY."); + + // display the initial content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // create an 'ON DELETE CASCADE' foreign key + FK_Create("ON DELETE CASCADE", con); + + // delete from the parent table, 'dept_details' + try + { + System.out.println(); + System.out.println(" DELETE FROM dept_details WHERE deptno = 'C00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DELETE FROM dept_details WHERE deptno = 'C00'"); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // delete from the child table, 'emp_details' + try + { + System.out.println(); + System.out.println(" DELETE FROM emp_details WHERE empname = 'Wheeler'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "DELETE FROM emp_details WHERE empname = 'Wheeler' "); + stmt1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the final content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + + #sql {ROLLBACK}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + + } // demo_FK_ON_DELETE_CASCADE + + // This function demonstrates how to use an 'ON DELETE SET NULL' + // foreign key + static void demo_FK_ON_DELETE_SET_NULL(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " DELETE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON DELETE SET NULL' FOREIGN KEY."); + + // display the initial content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // create an 'ON DELETE SET NULL' foreign key + FK_Create("ON DELETE SET NULL",con); + + // delete from the parent table, 'dept_details' + try + { + System.out.println(); + System.out.println(" DELETE FROM dept_details WHERE deptno = 'C00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DELETE FROM dept_details WHERE deptno = 'C00' "); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // delete from the child table, 'emp_details' + try + { + System.out.println(); + System.out.println(" DELETE FROM emp_details WHERE empname = 'Wheeler'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("DELETE FROM emp_details WHERE empname = 'Wheeler'"); + stmt1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the final content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + + #sql {ROLLBACK}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + + } // demo_FK_ON_DELETE_SET_NULL + + // This function demonstrates how to use an 'ON DELETE NO ACTION' + // foreign key + static void demo_FK_ON_DELETE_NO_ACTION(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " ALTER TABLE\n" + + " COMMIT\n" + + " DELETE\n" + + " ROLLBACK\n" + + "TO SHOW AN 'ON DELETE NO ACTION' FOREIGN KEY."); + + // display the initial content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // create an 'ON DELETE NO ACTION' foreign key + FK_Create("ON DELETE NO ACTION",con); + + // delete from the parent table, 'dept_details' + try + { + System.out.println(); + System.out.println(" DELETE FROM dept_details WHERE deptno = 'C00'"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DELETE FROM dept_details WHERE deptno = 'C00' "); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + + // delete from the child table, 'emp_details' + try + { + System.out.println(); + System.out.println(" DELETE FROM emp_details WHERE empname = 'Wheeler'"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("DELETE FROM emp_details WHERE empname = 'Wheeler'"); + stmt1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the final content of the 'dept_details' and 'emp_details' table + FK_TwoTablesDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" ROLLBACK"); + + #sql {ROLLBACK}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the foreign key + FK_Drop(con); + + } // demo_FK_ON_DELETE_NO_ACTION +} // TbConstr + diff --git a/java/sqlj/TbCreate.sqlj b/java/sqlj/TbCreate.sqlj new file mode 100644 index 0000000..9b6f9b3 --- /dev/null +++ b/java/sqlj/TbCreate.sqlj @@ -0,0 +1,161 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbCreate.sqlj +// +// SAMPLE: How to create and drop tables +// +// SQL Statements USED: +// CREATE TABLE +// DROP TABLE +// COMMIT +// +// Classes used from Util.sqlj are: +// Db +// SqljException +// +// OUTPUT FILE: TbCreate.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class TbCreate +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + String tableName; + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO CREATE AND DROP TABLES."); + + // connect to the 'sample' database + db.getDefaultContext(); + + create(); + drop(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // This function demonstrates how to create a table with different + // data types for each column. + static void create() + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT\n" + + " CREATE TABLE\n" + + "TO CREATE A TABLE:"); + + // create a table called 'tbname' under the schema 'schname' + try + { + System.out.println(); + System.out.println( + " Execute the statement:\n" + + " CREATE TABLE schname.tbname(Col1 SMALLINT,\n" + + " Col2 CHAR(7),\n" + + " Col3 VARCHAR(7),\n" + + " Col4 DEC(9,2),\n" + + " Col5 DATE,\n" + + " Col6 BLOB(5000),\n" + + " Col7 CLOB(5000))"); + + #sql {CREATE TABLE schname.tbname(col1 SMALLINT, + col2 CHAR(7), + col3 VARCHAR(7), + col4 DEC(9,2), + col5 DATE, + col6 BLOB(5000), + col7 CLOB(5000))}; + + // commit the transaction + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + System.exit(1); + } + } //create + + // This function demonstrates how to drop a table in a specific schema + static void drop() + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT\n" + + " DROP\n" + + "TO DROP A TABLE:"); + + // drop the table 'tbname' that is under the schema 'schname' + try + { + System.out.println(); + System.out.println(" Execute the statement:\n" + + " DROP TABLE schname.tbname"); + + #sql {DROP TABLE schname.tbname}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + System.exit(1); + } + } // drop +} // TbCreate + diff --git a/java/sqlj/TbIdent.sqlj b/java/sqlj/TbIdent.sqlj new file mode 100644 index 0000000..e1c05cd --- /dev/null +++ b/java/sqlj/TbIdent.sqlj @@ -0,0 +1,266 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbIdent.sqlj +// +// SAMPLE: How to use Identity Columns +// +// SQL Statements USED: +// CREATE TABLE +// INSERT +// SELECT +// DROP +// +// Classes used from Util.sqlj are: +// Db +// Data +// SqljException +// +// OUTPUT FILE: TbIdent.out (available in the online documentation). +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + + +import java.sql.*; +import java.lang.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +public class TbIdent +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO USE IDENTITY COLUMNS"); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + generateAlways( ctx.getConnection() ); + generateByDefault( ctx.getConnection() ); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + static void generateAlways(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " CREATE TABLE\n" + + " INSERT\n" + + "TO CREATE AN IDENTITY COLUMN WITH VALUE 'GENERATED ALWAYS'\n" + + "AND TO INSERT DATA IN THE TABLE\n"); + + try + { + // Create the table 'building' + System.out.println( + " CREATE TABLE building (bldnum INT\n" + + " GENERATED ALWAYS ASIDENTITY\n" + + " (START WITH 1, INCREMENT BY 1),\n" + + " addr VARCHAR(20),\n" + + " city VARCHAR(10),\n" + + " floor SMALLINT,\n" + + " employees SMALLINT)\n"); + + #sql {CREATE TABLE building( + bldnum INT GENERATED ALWAYS AS IDENTITY + (START WITH 1, INCREMENT BY 1), + addr VARCHAR(20), + city VARCHAR(10), + floors SMALLINT, + employees SMALLINT)}; + + // Insert data into the table 'building' + System.out.println( + " INSERT INTO building(bldnum, addr, city, floors, employees)\n" + + " VALUES(DEFAULT, '110 Woodpart St', 'Smithville', 3, 10),\n" + + " (DEFAULT, '123 Sesame Ave', 'Jonestown', 16, 13),\n" + + " (DEFAULT, '738 Eglinton Rd', 'Whosburg', 2, 10),\n" + + " (DEFAULT, '832 Lesley Blvd', 'Centertown', 2, 18)\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO building(bldnum, addr, city, floors, employees)" + + " VALUES(DEFAULT, '110 Woodpart St', 'Smithville', 3, 10), " + + "(DEFAULT, '123 Sesame Ave', 'Jonestown', 16, 13), " + + "(DEFAULT, '738 Eglinton Rd', 'Whosburg', 2, 10), " + + "(DEFAULT, '832 Lesley Blvd', 'Centertown', 2, 18)"); + + stmt.close(); + + // Retrieve and display the content of the 'building' table + System.out.println( + " SELECT * FROM building\n" + + " ID ADDRESS CITY FLOORS EMP\n" + + " --- -------------------- ------------ ------ ---\n"); + Statement stmt1 = con.createStatement(); + ResultSet rs = stmt1.executeQuery("SELECT * FROM building"); + + while (rs.next()) + { + System.out.println(" " + + Data.format(rs.getString("bldnum"),3) + " " + + Data.format(rs.getString("addr"),20) + " " + + Data.format(rs.getString("city"),12) + " " + + Data.format(rs.getString("floors"),6) + " " + + Data.format(rs.getString("employees"),4)); + } + + rs.close(); + stmt1.close(); + + // Drop the table 'building' + System.out.println(); + System.out.println(" Dropping the table 'building'"); + + #sql {DROP TABLE building}; + + #sql {COMMIT}; + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + System.exit(1); + } + } // generatedAlways + + static void generateByDefault(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " CREATE TABLE\n" + + " INSERT\n" + + "TO CREATE AN IDENTITY COLUMN WITH VALUE 'GENERATED BY DEFAULT'\n" + + "AND TO INSERT DATA IN THE TABLE\n"); + + try + { + // Create the table 'warehouse' + System.out.println( + " CREATE TABLE warehouse(\n" + + " whnum INT GENERATED BY DEFAULT AS IDENTITY\n" + + " (START WITH 1, INCREMENT BY 1),\n" + + " addr VARCHAR(20),\n" + + " city VARCHAR(10),\n" + + " capacity SMALLINT,\n" + + " employees SMALLINT)\n"); + + #sql {CREATE TABLE warehouse( + whnum INT GENERATED BY DEFAULT AS IDENTITY + (START WITH 1, INCREMENT BY 1), + addr VARCHAR(20), + city VARCHAR(10), + capacity SMALLINT, + employees SMALLINT)}; + + // Insert data into the table 'warehouse' + System.out.println( + " INSERT INTO warehouse(whnum, addr, city, capacity, employees)\n" + + " VALUES(DEFAULT, '92 Bothfield Dr', 'Yorkvile', 23, 100),\n" + + " (DEFAULT, '33 Giant Road', 'Centertown', 100, 22),\n" + + " (3, '8200 Warden Blvd', 'Smithville', 254, 10),\n" + + " (DEFAULT, '53 4th Ave', 'Whosburg', 97, 28)\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO warehouse(whnum, addr, city, capacity, employees)" + + " VALUES(DEFAULT, '92 Bothfield Dr', 'Yorkvile', 23, 100), " + + "(DEFAULT, '33 Giant Road', 'Centertown', 100, 22), " + + "(3, '8200 Warden Blvd', 'Smithville', 254, 10), " + + "(DEFAULT, '53 4th Ave', 'Whosburg', 97, 28) "); + + stmt.close(); + + // Retrieve and display warehouse Table + System.out.println( + " SELECT * FROM warehouse\n" + + " ID ADDRESS CITY CAPACITY EMP\n" + + " --- -------------------- ------------ -------- ---\n"); + + Statement stmt1 = con.createStatement(); + ResultSet rs = stmt1.executeQuery("SELECT * FROM warehouse"); + + while (rs.next()) + { + System.out.println(" " + + Data.format(rs.getString("whnum"),3) + " " + + Data.format(rs.getString("addr"),20) + " " + + Data.format(rs.getString("city"),12) + " " + + Data.format(rs.getString("capacity"),8) + " " + + Data.format(rs.getString("employees"),4)); + } + + rs.close(); + stmt1.close(); + + System.out.println( + "\n NOTE:\n" + + " An Identity Column with value 'GENERATED BY DEFAULT' may\n" + + " not contain a unique value for each row! To ensure a unique\n" + + " value for each row, define an index on the Identity Column.\n"); + + // Drop the table 'warehouse' + System.out.println(" Dropping the table 'warehouse'"); + + #sql {DROP TABLE warehouse}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + System.exit(1); + } + } // generateByDefault +} // TbIdent + diff --git a/java/sqlj/TbInfo.sqlj b/java/sqlj/TbInfo.sqlj new file mode 100644 index 0000000..285871f --- /dev/null +++ b/java/sqlj/TbInfo.sqlj @@ -0,0 +1,185 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbInfo.sqlj +// +// SAMPLE: How to get information about a table +// +// SQL Statements USED: +// SELECT +// +// Classes used from Util.sqlj are: +// Db +// SqljException +// +// OUTPUT FILE: TbInfo.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator TbInfo_Cursor(String, String, int, int); + +class TbInfo +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + String tableName; + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO GET INFORMATION ABOUT A TABLE."); + + + // connect to the 'sample' database + db.getDefaultContext(); + + // call the sample methods + tableName = "STAFF"; + getSchemaName(tableName); + getColumnInfo(tableName); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // This function demonstrates how to get the schema name for a table + static void getSchemaName(String tableName) + { + try + { + String schemaName; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " SELECT INTO\n" + + "TO GET A TABLE SCHEMA NAME."); + + // get the table schema name for a table + System.out.println(); + System.out.println( + " Execute the statement:\n" + + " SELECT tabschema INTO :schemaName\n" + + " FROM syscat.tables\n" + + " WHERE tabname = :tableName\n" + + " for tableName = '" + tableName + "'."); + + #sql {SELECT tabschema INTO :schemaName + FROM syscat.tables + WHERE tabname = :tableName}; + + System.out.println(); + System.out.println(" Table schema name is: " + schemaName); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // getSchemaName + + // This function demonstrates how to get the column information for a table + static void getColumnInfo(String tableName) + { + try + { + TbInfo_Cursor cur; + String colName = "", dataType = ""; + int dataLength = 0, dataScale = 0; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + " FETCH\n" + + "TO GET TABLE COLUMN INFORMATION."); + + // get the column information for a table + System.out.println(); + System.out.println( + " Get info for '" + tableName + "' table columns: "); + System.out.println( + " column name data type data size\n" + + " -------------------- -------------- ----------"); + + #sql cur = {SELECT colname, typename, length, scale + FROM syscat.columns + WHERE tabname = :tableName}; + + #sql {FETCH :cur INTO :colName, :dataType, :dataLength, :dataScale}; + + if (cur.endFetch()) + { + System.out.println(); + System.out.println(" Data not found.\n"); + } + + while (!cur.endFetch()) + { + System.out.print(" " + Data.format(colName,20) + + " " + Data.format(dataType,14) + + " " + dataLength); + if (dataScale != 0) + { + System.out.println("," + dataScale); + } + else + { + System.out.println(); + } + + #sql {FETCH :cur INTO :colName, :dataType, :dataLength, :dataScale}; + } + cur.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // getColumnInfo +} // TbInfo + diff --git a/java/sqlj/TbMod.sqlj b/java/sqlj/TbMod.sqlj new file mode 100644 index 0000000..5421b3e --- /dev/null +++ b/java/sqlj/TbMod.sqlj @@ -0,0 +1,1058 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbMod.sqlj +// +// SAMPLE: How to modify table data +// +// SQL Statements USED: +// SELECT +// UPDATE +// DELETE +// ROLLBACK +// +// Classes used from Util.sqlj are: +// Db +// Data +// SqljException +// +// OUTPUT FILE: TbMod.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; +import sqlj.runtime.ForUpdate; + +#sql iterator TbMod_Cursor1(Integer, String, Integer, String, + Integer, Double, Double); +#sql iterator TbMod_Cursor2(String, Double, String); +#sql iterator TbMod_PosCursor implements ForUpdate(String, int); + +class TbMod +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO MODIFY TABLE DATA."); + + // connect to the 'sample' database + db.getDefaultContext(); + + // different ways to INSERT table data + insertUsingValues(); + insertUsingFullselect(); + + // different ways to UPDATE table data + updateWithoutSubqueries(); + updateUsingSubqueryInSetClause(); + updateUsingSubqueryInWhereClause(); + updateUsingCorrelatedSubqueryInSetClause(); + updateUsingCorrelatedSubqueryInWhereClause(); + positionedUpdateWithoutSubqueries(); + positionedUpdateUsingSubqueryInSetClause(); + positionedUpdateUsingCorrelatedSubqueryInSetClause(); + + // different ways to DELETE table data + deleteWithoutSubqueries(); + deleteUsingSubqueryInWhereClause(); + deleteUsingCorrelatedSubqueryInWhereClause(); + positionedDelete(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // helping function: Display the content of the 'staff' table + static void staffTbContentDisplay() + { + try + { + TbMod_Cursor1 cur1; + Integer id = new Integer(0); + Integer years = new Integer(0); + Integer dept = new Integer(0); + String name = null; + String job = null; + Double salary = new Double(0.0); + Double comm = new Double(0.0); + + System.out.println(); + System.out.println( + " SELECT * FROM staff WHERE id >= 310\n" + + " ID NAME DEPT JOB YEARS SALARY COMM\n" + + " --- -------- ---- ----- ----- -------- --------"); + + #sql cur1 = {SELECT * FROM staff WHERE id >= 310}; + + while (true) + { + #sql {FETCH :cur1 + INTO :id, :name, :dept, :job, :years, :salary, :comm}; + + if (cur1.endFetch()) + { + break; + } + + System.out.print(" "+Data.format(id, 3) + + " " + Data.format(name, 8) + + " " + Data.format(dept, 4)); + + if (job != null) + { + System.out.print(" " + Data.format(job, 5)); + } + else + { + System.out.print(" -"); + } + if (years != null) + { + System.out.print(" " + Data.format(years, 5)); + } + else + { + System.out.print(" -"); + } + + System.out.print(" " + Data.format(salary, 7, 2)); + if (comm != null) + { + System.out.print(" " + Data.format(comm, 7, 2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + + // close the cursor + cur1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // staffTbContentDisplay + + // helping function: Display part of the content of the 'employee' table + static void employeeTbPartialContentDisplay() + { + try + { + TbMod_Cursor2 cur2; + String empno = null; + Double salary = new Double(0.0); + String workdept = null; + + System.out.println(); + System.out.println(" SELECT empno, salary, workdept\n" + + " FROM employee\n" + + " WHERE workdept = 'E11'\n" + + " EMPNO SALARY WORKDEPT\n" + + " ------ ---------- --------"); + + #sql cur2 = {SELECT empno, salary, workdept + FROM employee + WHERE workdept = 'E11'}; + + while (true) + { + #sql {FETCH :cur2 INTO :empno, :salary, :workdept}; + + if (cur2.endFetch()) + { + break; + } + + System.out.println(" "+Data.format(empno, 6) + + " " + Data.format(salary, 9, 2) + + " " + Data.format(workdept, 8)); + } + System.out.println(); + cur2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // employeeTbPartialContentDisplay + + // This function demonstrates how to insert table data using VALUES + static void insertUsingValues() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO INSERT TABLE DATA USING VALUES."); + + // display the initial content of the 'staff' table + staffTbContentDisplay(); + + // INSERT data INTO a table using VALUES + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " INSERT INTO staff(id, name, dept, job, salary)\n" + + " VALUES(380, 'Pearce', 38, 'Clerk', 13217.50),\n" + + " (390, 'Hachey', 38, 'Mgr', 21270.00),\n" + + " (400, 'Wagland', 38, 'Clerk', 14575.00)"); + + #sql {INSERT INTO staff(id, name, dept, job, salary) + VALUES(380, 'Pearce', 38, 'Clerk', 13217.50), + (390, 'Hachey', 38, 'Mgr', 21270.00), + (400, 'Wagland', 38, 'Clerk', 14575.00)}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // insertUsingValues + + // This function demonstrates how to insert table data using + // FULLSELECT + static void insertUsingFullselect() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO INSERT TABLE DATA USING FULLSELECT."); + + // display the initial content of the 'staff' table + staffTbContentDisplay(); + + // INSERT data INTO a table using FULLSELECT + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " INSERT INTO staff(id, name, dept, salary)\n" + + " SELECT INTEGER(empno)+100, lastname, 77, salary\n" + + " FROM employee\n" + + " WHERE INTEGER(empno) >= 310"); + + #sql {INSERT INTO staff(id, name, dept, salary) + SELECT INTEGER(empno) + 100, lastname, 77, salary + FROM employee + WHERE INTEGER(empno) >= 310}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // insertUsingFullselect + + // This function demonstrates how to update table data + static void updateWithoutSubqueries() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // update table data + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff\n" + + " SET salary = salary + 1000\n" + + " WHERE id >= 310 AND dept = 84"); + + #sql {UPDATE staff + SET salary = salary + 1000 + WHERE id >= 310 AND dept = 84}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // updateWithoutSubqueries + + // This function demonstrates how to update table data using a + // subquery in the SET clause + static void updateUsingSubqueryInSetClause() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA USING A SUBQUERY IN THE 'SET' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // update data of the table 'staff' by using a subquery in the SET + // clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff\n" + + " SET salary = (SELECT MIN(salary)\n" + + " FROM staff\n" + + " WHERE id >= 310)\n" + + " WHERE id = 350"); + + #sql {UPDATE staff + SET salary = (SELECT MIN(salary) + FROM staff + WHERE id >= 310) + WHERE id = 350}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // updateUsingSubqueryInSetClause + + // This function demonstrates how to update table data using a subquery + // in the WHERE clause. + static void updateUsingSubqueryInWhereClause() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA\n" + + "USING A SUBQUERY IN THE 'WHERE' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // update table using subquery in WHERE clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff\n" + + " SET comm = 250.00\n" + + " WHERE dept = 84 AND\n" + + " salary < (SELECT AVG(salary)\n" + + " FROM staff\n" + + " WHERE id >= 310 AND dept = 84)"); + + #sql {UPDATE staff + SET comm = 250.00 + WHERE dept = 84 AND + salary < (SELECT AVG(salary) + FROM staff + WHERE id >= 310 AND dept = 84)}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // updateUsingSubqueryInWhereClause + + // This function demonstrates how to update table data using a + // correlated subquery in the 'SET' clause. + static void updateUsingCorrelatedSubqueryInSetClause() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA\n" + + "USING A CORRELATED SUBQUERY IN THE 'SET' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // update data of the 'staff' table using a correlated subquery in + // the 'SET' clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff s1\n" + + " SET comm = 0.01 * (SELECT MIN(salary)\n" + + " FROM staff s2\n" + + " WHERE id >= 310 AND\n" + + " s2.dept = s1.dept)\n" + + " WHERE id >= 340"); + + #sql {UPDATE staff s1 + SET comm = 0.01 * (SELECT MIN(salary) + FROM staff s2 + WHERE id >= 310 AND + s2.dept = s1.dept) + WHERE id >= 340}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // updateUsingCorrelatedSubqueryInSetClause + + // This function demonstrates how to update table data using a + // correlated subquery in the 'WHERE' clause. + static void updateUsingCorrelatedSubqueryInWhereClause() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO UPDATE TABLE DATA\n" + + "USING A CORRELATED SUBQUERY IN THE 'WHERE' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // update data of the 'staff' table using a correlated subquery in the + // 'WHERE' clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff s1\n" + + " SET comm = 700\n" + + " WHERE id >= 340 AND\n" + + " salary < (SELECT AVG(salary)\n" + + " FROM staff s2\n" + + " WHERE id >= 310 AND\n" + + " s2.dept = s1.dept)"); + + #sql {UPDATE staff s1 + SET comm = 700 + WHERE id >= 340 AND + salary < (SELECT AVG(salary) + FROM staff s2 + WHERE id >= 310 AND + s2.dept = s1.dept)}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // updateUsingCorrelatedSubqueryInWhereClause + + // This function demonstrates how to perform a positioned update on a table + static void positionedUpdateWithoutSubqueries() + { + try + { + TbMod_PosCursor posCur; + int dept = 0; + String name = null; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " UPDATE\n" + + "TO PERFORM A POSITIONED UPDATE ON A TABLE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + System.out.println(); + System.out.println( + " Invoke the statements:\n" + + " DECLARE posCur CURSOR FOR\n" + + " SELECT name, dept FROM staff WHERE id >= 310\n" + + "\n" + + " FETCH :posCur INTO :name, :dept\n" + + " while (successful fetch)\n" + + " {\n" + + " if (dept != 84)\n" + + " {\n" + + " UPDATE staff SET comm = NULL WHERE CURRENT OF :posCur\n" + + " }\n" + + " FETCH :posCur INTO :name, :dept\n" + + " }"); + + // declare a cursor + #sql posCur = {SELECT name, dept FROM staff WHERE id >= 310}; + + while (true) + { + // fetch the cursor + #sql {FETCH :posCur INTO :name, :dept}; + + if (posCur.endFetch()) + { + break; + } + + if (dept != 84) + { + #sql {UPDATE staff SET comm = NULL WHERE CURRENT OF :posCur}; + } + } + + // close the cursor + posCur.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // positionedUpdateWithoutSubqueries + + // This function demonstrates how to perform a positioned update on a table + // using subquery in the 'SET' clause. + static void positionedUpdateUsingSubqueryInSetClause() + { + try + { + TbMod_PosCursor posCur; + int dept = 0; + String name = null; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " UPDATE\n" + + "TO PERFORM A POSITIONED UPDATE ON A TABLE\n" + + "USING A SUBQUERY IN THE 'SET' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + System.out.println(); + System.out.println( + " Invoke the statements:\n" + + " DECLARE posCur CURSOR FOR\n" + + " SELECT name, dept FROM staff WHERE id >= 310\n" + + "\n" + + " FETCH :posCur INTO :name, :dept\n" + + " while (successful fetch)\n" + + " {\n" + + " if (dept != 84)\n" + + " {\n" + + " UPDATE staff\n" + + " SET comm = 0.01 * (SELECT AVG(salary)\n"+ + " FROM staff\n" + + " WHERE id >= 310)\n" + + " WHERE CURRENT OF :posCur\n" + + " }\n" + + " FETCH :posCur INTO :name, :dept\n" + + " }"); + + // declare a cursor + #sql posCur = {SELECT name, dept FROM staff WHERE id >= 310}; + + while (true) + { + // fetch the cursor + #sql {FETCH :posCur INTO :name, :dept}; + + if (posCur.endFetch()) + { + break; + } + + if (dept != 84) + { + #sql {UPDATE staff + SET comm = 0.01 * (SELECT AVG(salary) + FROM staff + WHERE id >= 310) + WHERE CURRENT OF :posCur}; + } + } + + // close the cursor + posCur.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // positionedUpdateUsingSubqueryInSetClause + + // This function demonstrates how to perform a positioned update on a table + // using a correlated subquery in the 'SET' clause + static void positionedUpdateUsingCorrelatedSubqueryInSetClause() + { + try + { + TbMod_PosCursor posCur; + int dept = 0; + String name = null; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " UPDATE\n" + + "TO PERFORM A POSITIONED UPDATE ON A TABLE\n" + + "USING A CORRELATED SUBQUERY IN THE 'SET' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + System.out.println(); + System.out.println( + " Invoke the statements:\n" + + " DECLARE posCur CURSOR FOR\n" + + " SELECT name, dept FROM staff WHERE id >= 310\n" + + "\n" + + " FETCH :posCur INTO :name, :dept\n" + + " while (successful fetch)\n" + + " {\n" + + " if (dept != 84)\n" + + " {\n" + + " UPDATE staff s1\n" + + " SET comm = 0.01 * (SELECT AVG(salary)\n" + + " FROM staff s2\n" + + " WHERE id >= 310 AND\n"+ + " s2.dept = s1.dept)\n" + + " WHERE CURRENT OF :posCur\n" + + " }\n" + + " FETCH :posCur INTO :name, :dept\n" + + " }"); + + // declare a cursor + #sql posCur = {SELECT name, dept FROM staff WHERE id >= 310}; + + while (true) + { + // fetch the cursor + #sql {FETCH :posCur INTO :name, :dept}; + + if (posCur.endFetch()) + { + break; + } + + if (dept != 84) + { + #sql {UPDATE staff s1 + SET comm = 0.01 * (SELECT AVG(salary) + FROM staff s2 + WHERE id >= 310 AND + s2.dept = s1.dept) + WHERE CURRENT OF :posCur}; + } + } + + // close the cursor + posCur.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // updateUsingCorrelatedSubqueryInSetClause + + // This function demonstrates how to delete table data + static void deleteWithoutSubqueries() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO DELETE TABLE DATA."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // delete data from the 'staff' table without subqueries + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " DELETE FROM staff WHERE id >= 310 AND salary > 20000"); + + #sql {DELETE FROM staff WHERE id >= 310 AND salary > 20000}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // deleteWithoutSubqueries + + // This function demonstrates how to delete table data using a + // subquery in the 'WHERE' clause. + static void deleteUsingSubqueryInWhereClause() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO DELETE TABLE DATA\n" + + "USING A SUBQUERY IN THE 'WHERE' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // display a partial content of the 'employee' table + employeeTbPartialContentDisplay(); + + // delete data from the 'staff' table using a subquery in the 'WHERE' + // clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " DELETE FROM staff\n" + + " WHERE id >= 310 AND\n" + + " salary > (SELECT AVG(salary)\n" + + " FROM employee\n" + + " WHERE workdept = 'E11')"); + + #sql {DELETE FROM staff + WHERE id >= 310 AND + salary > (SELECT AVG(salary) + FROM employee + WHERE workdept = 'E11')}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // deleteUsingSubqueryInWhereClause + + // This function demonstrates how to delete table data using a + // correlated subquery in the 'WHERE' clause. + static void deleteUsingCorrelatedSubqueryInWhereClause() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO DELETE TABLE DATA\n" + + "USING A CORRELATED SUBQUERY IN THE 'WHERE' CLAUSE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // delete data from the 'staff' table using a correlated subquery in the + // 'WHERE' clause + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " DELETE FROM staff s1\n" + + " WHERE id >= 310 AND\n" + + " salary < (SELECT AVG(salary)\n" + + " FROM staff s2\n" + + " WHERE s2.dept = s1.dept)"); + + #sql {DELETE FROM staff s1 + WHERE id >= 310 AND + salary < (SELECT AVG(salary) + FROM staff s2 + WHERE s2.dept = s1.dept)}; + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // TbDeleteUsingCorrelatedSubqueryInWhereClause + + // This function demonstrates how to perform a positioned delete on a table + static void positionedDelete() + { + try + { + TbMod_PosCursor posCur; + int dept = 0; + String name = null; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " DELETE\n" + + "TO PERFORM A POSITIONED DELETE ON A TABLE."); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + System.out.println(); + System.out.println( + " Invoke the statements:\n" + + " DECLARE posCur CURSOR FOR\n" + + " SELECT name, dept FROM staff WHERE id >= 310\n" + + "\n" + + " FETCH :posCur INTO :name, :dept\n" + + " while (successful fetch)\n" + + " {\n" + + " if (dept != 84)\n" + + " {\n" + + " DELETE FROM staff WHERE CURRENT OF :posCur\n" + + " }\n" + + " FETCH :posCur INTO :name, :dept\n" + + " }"); + + // declare a cursor + #sql posCur = {SELECT name, dept FROM staff WHERE id >= 310}; + + while (true) + { + // fetch the cursor + #sql {FETCH :posCur INTO :name, :dept}; + + if (posCur.endFetch()) + { + break; + } + + if (dept != 84) + { + #sql {DELETE FROM staff WHERE CURRENT OF :posCur}; + } + } + + // close the cursor + posCur.close(); + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction"); + + #sql {ROLLBACK}; + + System.out.println(" Rollback Done."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // positionedDelete +} // TbMod + diff --git a/java/sqlj/TbOnlineInx.sqlj b/java/sqlj/TbOnlineInx.sqlj new file mode 100644 index 0000000..2ca7123 --- /dev/null +++ b/java/sqlj/TbOnlineInx.sqlj @@ -0,0 +1,310 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbOnlineInx.sqlj +// +// SAMPLE: How to create and reorg indexes on a table +// +// SQL STATEMENTS USED: +// INCLUDE +// CREATE INDEX +// DROP INDEX +// REORG +// LOCK +// +// JAVA 2 CLASSES USED: +// File +// FileWriter +// Process +// BufferedReader +// InputStreamReader +// +// Classes used from Util.java are: +// Db +// SqljException +// +// OUTPUT FILE: TbOnlineInx.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** + +import java.lang.*; +import java.sql.*; +import java.io.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +// declare an iterator for result of the select command +#sql iterator TbOnlineInx_Cursor0(String); + +public class TbOnlineInx +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CREATE AND REORG ONLINE INDEXES\n" + + "ON TABLES."); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + // create online index on a table + createIndex(); + + // reorg online index on a table + reorgIndex(); + + // drop online index created + dropIndex(); + + // disconnect from 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // How to create an index on a table with different levels + // of access to the table like read-write, read-only, no access + static void createIndex() throws Exception + { + System.out.print( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT\n" + + " CREATE INDEX\n" + + "TO CREATE AN INDEX\n"); + + // create an online index with read-write access to the table + System.out.print( + "\nTo create an index on a table allowing read-write access\n" + + "to the table, use the following SQL command:\n\n" + + " CREATE INDEX index1 ON employee (lastname ASC)\n"); + + #sql {CREATE INDEX index1 ON employee (lastname ASC)}; + #sql {COMMIT}; + + // drop index1 created on 'employee' table + dropIndex(); + + // create an index on a table while allowing only read access to it + System.out.println( + "\nTo create an index on a table allowing only read access\n" + + "to the table, use the following two SQL commands:\n\n" + + " LOCK TABLE employee IN SHARE MODE\n" + + " CREATE INDEX index1 ON employee (lastname ASC)"); + + #sql {LOCK TABLE employee IN SHARE MODE}; + #sql {COMMIT}; + + #sql {CREATE INDEX index1 ON employee (lastname ASC)}; + #sql {COMMIT}; + + // drop index1 created on 'employee' table + dropIndex(); + + // create an online index allowing no access to the table + System.out.println( + "\nTo create an index on a table allowing no access to the \n" + + "table (only uncommitted readers allowed), use the \n" + + "following two SQL statements:\n\n" + + " LOCK TABLE employee IN EXCLUSIVE MODE\n" + + " CREATE INDEX index1 ON employee (lastname ASC)"); + + #sql {LOCK TABLE employee IN EXCLUSIVE MODE}; + #sql {COMMIT}; + + #sql {CREATE INDEX index1 ON employee (lastname ASC)}; + #sql {COMMIT}; + } // createIndex + + // Create 3 CLP files for REORG command with write, read and no access, + // respectively. + static void createFiles() throws Exception + { + // get fully qualified name of the table + String tableName = "EMPLOYEE"; + String schemaName = getSchemaName(tableName); + String fullTableName = schemaName + "." + tableName; + + // reorg command has to be executed with three different options, namely, + // 'with write access', 'with read access' and 'with no access' + String[] fileNames = { "ReorgCmdAllowWrite.db2", + "ReorgCmdAllowRead.db2", + "ReorgCmdAllowNone.db2" }; + + String[] options = { " WRITE ACCESS", + " READ ACCESS", + " NO ACCESS" }; + + for (int i = 0; i < 3; i++) + { + // create a CLP file with the REORG command + File outputFile = new File(fileNames[i]); + FileWriter out = new FileWriter(outputFile); + + out.write("CONNECT TO SAMPLE;\n"); + out.write("REORG INDEXES ALL FOR TABLE " + fullTableName + + " ALLOW" + options[i] + ";\n"); + out.write("CONNECT RESET;"); + out.close(); + + // on exit, delete the temporary files created + outputFile.deleteOnExit(); + } + } //createFiles + + // How to reorg an index on a table with different levels of + // access to the table like read-write, read-only, no access + static void reorgIndex() + { + System.out.print( + "\n-----------------------------------------------------------\n" + + "\nUSE THE SQL STATEMENT:\n"+ + " REORG\n" + + "TO REORGANIZE A TABLE OR INDEX\n"); + + try + { + String[] fileNames = { "ReorgCmdAllowWrite.db2", + "ReorgCmdAllowRead.db2", + "ReorgCmdAllowNone.db2" }; + + String[] options = { " write access", + " read access", + " no access" }; + + // create 3 files with REORG commands + createFiles(); + + for (int i = 0; i < 3; i++) + { + System.out.println( + "\nReorganize the indexes on a table allowing" + options[i] + + "\n-----------------------------------------------------------"); + + String s = null; + String execCmd = "db2 -tvf " + fileNames[i]; + + // execute the command to run the CLP file + Process p = Runtime.getRuntime().exec(execCmd); + + BufferedReader stdInput = new BufferedReader(new + InputStreamReader(p.getInputStream())); + BufferedReader stdError = new BufferedReader(new + InputStreamReader(p.getErrorStream())); + + // read the output from the command and set the output variable with + // the value + while ((s = stdInput.readLine()) != null) + { + System.out.println(s); + } + + // read any errors from the attempted command and set the error + // variable with the value + while ((s = stdError.readLine()) != null) + { + System.out.println(s); + } + + p.destroy(); + + } // for + } // try + + catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + } // reorgIndex + + // How to drop the index on a table + static void dropIndex() + { + System.out.println( + "\nUSE THE SQL STATEMENT\n" + + " DROP\n" + + "TO DROP AN INDEX:\n"); + + try + { + // drop the indexes + System.out.println( + " Execute the statement\n" + + " DROP INDEX index1\n" + + "\n-----------------------------------------------------------"); + #sql {DROP INDEX index1}; + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + } // dropIndex + + // function to get the schema name for a particular table + static String getSchemaName(String tableName) throws Exception + { + // declare a cursor to run through the result of the query + TbOnlineInx_Cursor0 cur0; + + #sql cur0 = {SELECT tabschema FROM syscat.tables WHERE tabname = :tableName}; + + String schemaName = null; + #sql {FETCH :cur0 INTO :schemaName}; + + // remove the trailing white space characters from schemaName before + // returning it to the calling function + return schemaName.trim(); + + } // getSchemaName +} // TbOnlineInx + diff --git a/java/sqlj/TbPriv.sqlj b/java/sqlj/TbPriv.sqlj new file mode 100644 index 0000000..18a0b9c --- /dev/null +++ b/java/sqlj/TbPriv.sqlj @@ -0,0 +1,219 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbPriv.sqlj +// +// SAMPLE: How to grant, display and revoke privileges on a table +// +// SQL Statements USED: +// GRANT +// SELECT +// REVOKE +// COMMIT +// +// Classes used from Util.sqlj are: +// Db +// SqljException +// +// OUTPUT FILE: TbPriv.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator TbPriv_Cursor(String, String, String, String, String, + String, String, String, String); + +class TbPriv +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO GRANT, DISPLAY AND REVOKE \n" + + "PRIVILEGES ON A TABLE."); + + // connect to the 'sample' database + db.getDefaultContext(); + + grant(); + display(); + revoke(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + static void grant() + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " GRANT\n" + + " COMMIT\n" + + "TO GRANT PRIVILEGES ON A TABLE."); + + System.out.println(); + System.out.println( + " GRANT SELECT, INSERT, UPDATE(salary, comm)\n" + + " ON TABLE staff\n" + + " TO USER user1"); + + try + { + #sql {GRANT SELECT, INSERT, UPDATE(salary, comm) + ON TABLE staff + TO USER user1}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // grant + + static void display() + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " SELECT\n" + + "TO DISPLAY PRIVILEGES ON A TABLE."); + + System.out.println(); + System.out.println( + " SELECT granteetype, controlauth, alterauth,\n" + + " deleteauth, indexauth, insertauth,\n" + + " selectauth, refauth, updateauth\n" + + " FROM syscat.tabauth\n" + + " WHERE grantee = 'USER1' AND\n" + + " tabname = 'STAFF'"); + + try + { + TbPriv_Cursor cur; + String granteetype = null; + String controlauth = null; + String alterauth = null; + String deleteauth = null; + String indexauth = null; + String insertauth = null; + String selectauth = null; + String refauth = null; + String updateauth = null; + + #sql cur = {SELECT granteetype, controlauth, alterauth, + deleteauth, indexauth, insertauth, + selectauth, refauth, updateauth + FROM syscat.tabauth + WHERE grantee = 'USER1' AND + tabname = 'STAFF'}; + + #sql {FETCH :cur INTO :granteetype, :controlauth, :alterauth, + :deleteauth, :indexauth, :insertauth, + :selectauth, :refauth, :updateauth}; + + System.out.println(); + System.out.println( + " Grantee Type = " + granteetype + "\n" + + " CONTROL priv. = " + controlauth + "\n" + + " ALTER priv. = " + alterauth + "\n" + + " DELETE priv. = " + deleteauth + "\n" + + " INDEX priv. = " + indexauth + "\n" + + " INSERT priv. = " + insertauth + "\n" + + " SELECT priv. = " + selectauth + "\n" + + " REFERENCES priv. = " + refauth + "\n" + + " UPDATE priv. = " + updateauth); + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // display + + static void revoke() + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " REVOKE\n" + + " COMMIT\n" + + "TO REVOKE PRIVILEGES ON A TABLE."); + + System.out.println(); + System.out.println( + " REVOKE SELECT, INSERT, UPDATE\n" + + " ON TABLE staff\n" + + " FROM USER user1"); + + try + { + #sql {REVOKE SELECT, INSERT, UPDATE + ON TABLE staff + FROM USER user1}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // revoke +} // TbPriv + diff --git a/java/sqlj/TbRead.sqlj b/java/sqlj/TbRead.sqlj new file mode 100644 index 0000000..f1f4a10 --- /dev/null +++ b/java/sqlj/TbRead.sqlj @@ -0,0 +1,1403 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbRead.sqlj +// +// SAMPLE: How to read table data +// +// SQL Statements USED: +// SELECT +// FETCH +// +// Classes used from Util.sqlj are: +// Db +// Data +// SqljException +// +// OUTPUT FILE: TbRead.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator Named_Iterator(String deptnumb, String deptname); +#sql iterator Positioned_Iterator(String, String); +#sql iterator TbRead_Cursor0(int, String, int, String, String); +#sql iterator TbRead_Cursor1(String, String, String, String, String); +#sql iterator TbRead_Cursor2(int, String); +#sql iterator TbRead_Cursor3(String, int); +#sql iterator TbRead_Cursor4(int, String, String, String); +#sql iterator TbRead_Cursor5(int, int, String, String); +#sql iterator TbRead_Cursor6(String, int, double); +#sql iterator TbRead_Cursor7(String, Integer, Double); +#sql iterator TbRead_Cursor8(float); + +class TbRead +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO READ TABLE DATA."); + + // connect to the 'sample' database + db.getDefaultContext(); + + // different ways to read table data + selectUsingNamedBindingToColumns(); + selectUsingPositionalBindingToColumns(); + + mostSimpleSubselect(); + basicSubselect(); + groupBySubselect(); + subselect(); + rowSubselect(); + fullselect(); + selectStatement(); + + basicSubselectFromMultipleTables(); + basicSubselectFromJoinedTable(); + basicSubselectUsingSubquery(); + basicSubselectUsingCorrelatedSubquery(); + + subselectUsingGroupingSets(); + subselectUsingRollup(); + subselectUsingCube(); + selectUsingQuerySampling(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // helping function + static void orgTbContentDisplay() + { + try + { + int deptnumb = 0; + String deptname = ""; + int manager = 0; + String division = ""; + String location = ""; + + TbRead_Cursor0 cur0; + System.out.println(); + System.out.println(" SELECT * FROM org"); + + System.out.println( + " DEPTNUMB DEPTNAME MANAGER DIVISION LOCATION\n" + + " -------- -------------- ------- ---------- --------------"); + + // perform a SELECT against the "org" table in the sample database. + #sql cur0 = {SELECT * FROM org}; + + + while (true) + { + // retrieve and display the result from the SELECT statement + #sql {FETCH :cur0 + INTO :deptnumb, :deptname, :manager, :division, :location}; + + if (cur0.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14) + + " " + Data.format(manager, 7) + + " " + Data.format(division, 10) + + " " + Data.format(location, 14)); + } + + // close the cursor + cur0.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // orgTbContentDisplay + + // helping function + static void departmentTbContentDisplay() + { + try + { + int mgrnoInd = 0; + int departmentLocationInd = 0; + String deptno = ""; + String departmentDeptname = ""; + String mgrno = ""; + String admrdept = ""; + String departmentLocation = ""; + TbRead_Cursor1 cur1; + + System.out.println(); + System.out.println(" SELECT * FROM department"); + + System.out.println( + " DEPTNO DEPTNAME MGRNO ADMRDEPT LOCATION\n" + + " ------ ---------------------------- ------ -------- --------"); + + #sql cur1 = {SELECT * FROM department}; + + while (true) + { + #sql {FETCH :cur1 INTO :deptno, :departmentDeptname, :mgrno, + :admrdept, :departmentLocation}; + if (cur1.endFetch()) + { + break; + } + + System.out.print(" " + Data.format(deptno, 6) + + " " + Data.format(departmentDeptname, 28)); + if (mgrno != null) + { + System.out.print(" " + Data.format(mgrno, 6)); + } + else + { + System.out.print(" - "); + } + System.out.print(" " + Data.format(admrdept, 8)); + if (departmentLocation != null) + { + System.out.print(" " + Data.format(departmentLocation, 16)); + } + else + { + System.out.print(" - "); + } + System.out.println(); + } + + // close the cursor + cur1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // departmentTbContentDisplay + + // helping function + static void employeeTbPartialContentDisplay() + { + try + { + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT job, edlevel, comm\n" + + " FROM employee\n" + + " WHERE job IN('DESIGNER', 'FIELDREP')\n" + + "\n" + + " Results:\n" + + " JOB EDLEVEL COMM\n" + + " -------- ------- -----------"); + + int edlevel = 0; + double comm = 0.0; + String job = ""; + TbRead_Cursor6 cur6; + + // declare a cursor + #sql cur6 = {SELECT job, edlevel, comm + FROM employee + WHERE job IN('DESIGNER', 'FIELDREP')}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur6 INTO :job, :edlevel, :comm}; + + if (cur6.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(job, 8) + + " " + Data.format(edlevel, 7) + + " " + Data.format(comm, 10, 2)); + } + + // close the cursor + cur6.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // employeeTbPartialContentDisplay + + static void selectUsingNamedBindingToColumns() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT\n" + + " SELECT\n" + + "AND THE 'NAMED' ITERATOR\n" + + "TO RETRIEVAL MULTI-ROW QUERY RESULTS."); + + // display the content of the 'org' table + departmentTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptno as deptnumb, deptname\n" + + " FROM department\n" + + " WHERE admrdept = 'A00'\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + Named_Iterator namedIter = null; + + // declare a cursor + #sql namedIter = {SELECT deptno as deptnumb, deptname + FROM department + WHERE admrdept = 'A00'}; + + while (namedIter.next()) + { + System.out.println(" " + Data.format(namedIter.deptnumb(), 8) + + " " + Data.format(namedIter.deptname(), 14)); + } + + // close the cursor + namedIter.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // selectUsingNamedBindingToColumns + + static void selectUsingPositionalBindingToColumns() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT\n" + + " SELECT\n" + + "AND THE 'POSITIONED' ITERATOR\n" + + "TO RETRIEVAL MULTI-ROW QUERY RESULTS."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptno as deptnumb, deptname\n" + + " FROM department\n" + + " WHERE admrdept = 'A00'\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + Positioned_Iterator posIter; + String deptnumb = ""; + String deptname = ""; + + // delcare cursor + #sql posIter = {SELECT deptno as deptnumb, deptname + FROM department + WHERE admrdept = 'A00'}; + + while (true) + { + // fetch the cursor + #sql {FETCH :posIter INTO :deptnumb, :deptname}; + + if (posIter.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + } + + // close the cursor + posIter.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // selectUsingPositionalBindingToColumns + + static void mostSimpleSubselect() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname FROM org\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + int deptnumb = 0; + String deptname = ""; + TbRead_Cursor2 cur2; + + // declare a cursor + #sql cur2 = {SELECT deptnumb, deptname FROM org}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur2 INTO :deptnumb, :deptname}; + + if (cur2.endFetch()) + { + break; + } + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + } + + // close the cursor + cur2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // mostSimpleSubselect + + static void basicSubselect() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT USING A WHERE CLAUSE."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname FROM org WHERE deptnumb < 30\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + int deptnumb = 0; + String deptname = ""; + TbRead_Cursor2 cur2; + + // declare a cursor + #sql cur2 = {SELECT deptnumb, deptname FROM org WHERE deptnumb < 30}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur2 INTO :deptnumb, :deptname}; + + if (cur2.endFetch()) + { + break; + } + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + } + + // close the cursor + cur2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // basicSubselect + + static void groupBySubselect() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A 'GROUP BY' SUBSELECT."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT division, MAX(deptnumb) FROM org GROUP BY division\n" + + "\n" + + " Results:\n" + + " DIVISION MAX(DEPTNUMB)\n" + + " ---------- --------------"); + + int maxDeptnumb = 0; + String division = ""; + TbRead_Cursor3 cur3; + + // declare a cursor + #sql cur3 = { + SELECT division, MAX(deptnumb) FROM org GROUP BY division}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur3 INTO :division, :maxDeptnumb}; + + if (cur3.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(division, 10) + + " " + Data.format(maxDeptnumb, 14)); + } + + // close the cursor + cur3.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // groupBySubselect + + static void subselect() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT division, MAX(deptnumb)\n" + + " FROM org\n" + + " WHERE location NOT IN 'New York'\n" + + " GROUP BY division\n" + + " HAVING division LIKE '%%ern'\n" + + "\n" + + " Results:\n" + + " DIVISION MAX(DEPTNUMB)\n" + + " ---------- --------------"); + + int maxDeptnumb = 0; + String division = ""; + TbRead_Cursor3 cur3; + + // declare a cursor + #sql cur3 = {SELECT division, MAX(deptnumb) + FROM org + WHERE location NOT IN 'New York' + GROUP BY division + HAVING division LIKE '%ern'}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur3 INTO :division, :maxDeptnumb}; + + if (cur3.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(division, 10) + + " " + Data.format(maxDeptnumb, 14)); + } + + // close the cursor + cur3.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // subselect + + static void rowSubselect() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A 'ROW' SUBSELECT."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname\n" + + " INTO :deptnumb, :deptname\n" + + " FROM org\n" + + " WHERE location = 'New York'\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + int deptnumb = 0; + String deptname = ""; + TbRead_Cursor2 cur2; + + // declare a cursor + #sql cur2 = {SELECT deptnumb, deptname + FROM org + WHERE location = 'New York'}; + + // fetch the cursor + #sql {FETCH :cur2 INTO :deptnumb, :deptname}; + + System.out.println(" " + Data.format(deptnumb,8) + + " " + Data.format(deptname,14)); + cur2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // rowSubselect + + static void fullselect() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A FULLSELECT."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname\n" + + " FROM org\n" + + " WHERE deptnumb < 20\n" + + " UNION\n" + + " VALUES(7, 'New Deptname')\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + int deptnumb = 0; + String deptname = ""; + TbRead_Cursor2 cur2; + + // declare a cursor + #sql cur2 = {SELECT deptnumb, deptname + FROM org + WHERE deptnumb < 20 + UNION + VALUES(7, 'New Deptname')}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur2 INTO :deptnumb, :deptname}; + + if (cur2.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + } + + // close the cursor + cur2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // fullselect + + static void selectStatement() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SELECT USING ORDER BY."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname\n" + + " FROM org\n" + + " WHERE deptnumb > 30\n" + + " ORDER BY deptname\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- ------------"); + + int deptnumb = 0; + String deptname = ""; + TbRead_Cursor2 cur2; + + // declare a cursor + #sql cur2 = {SELECT deptnumb, deptname + FROM org + WHERE deptnumb > 30 + ORDER BY deptname}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur2 INTO :deptnumb, :deptname}; + + if (cur2.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 18)); + } + + // close the cursor + cur2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // selectStatement + + static void basicSubselectFromMultipleTables() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT FROM MULTIPLE TABLES."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + // display the content of the 'department' table + departmentTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, o.deptname, deptno, d.deptname\n" + + " FROM org o, department d\n" + + " WHERE deptnumb <= 15 AND deptno LIKE '%%11'\n" + + "\n" + + " Results:\n" + + " DEPTNUMB ORG.DEPTNAME DEPTNO DEPARTMENT.DEPTNAME\n"+ + " -------- -------------- ------ -------------------"); + + int deptnumb = 0; + String deptno = ""; + String orgDeptname = ""; + String departmentDeptname = ""; + TbRead_Cursor4 cur4; + + // declare a cursor + #sql cur4 = {SELECT deptnumb, o.deptname, deptno, d.deptname + FROM org o, department d + WHERE deptnumb <= 15 AND deptno LIKE '%11'}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur4 INTO :deptnumb, :orgDeptname, :deptno, + :departmentDeptname}; + + if (cur4.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(orgDeptname, 14) + + " " + Data.format(deptno, 6) + + " " + Data.format(departmentDeptname, 14)); + } + + // close the cursor + cur4.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // basicSelectFromMultipleTables + + static void basicSubselectFromJoinedTable() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT FROM JOINED TABLES."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + // display the content of the 'department' table + departmentTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, manager, deptno, mgrno\n" + + " FROM org\n" + + " INNER JOIN department\n" + + " ON manager = INTEGER(mgrno)\n" + + " WHERE deptnumb BETWEEN 20 AND 100\n" + + "\n" + + " Results:\n" + + " DEPTNUMB MANAGER DEPTNO MGRNO\n" + + " -------- ------- ------ ------"); + + int deptnumb = 0; + int manager = 0; + String deptno = ""; + String mgrno = ""; + TbRead_Cursor5 cur5; + + // declare a cursor + #sql cur5 = {SELECT deptnumb, manager, deptno, mgrno + FROM org + INNER JOIN department + ON manager = INTEGER(mgrno) + WHERE deptnumb BETWEEN 20 AND 100}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur5 INTO :deptnumb, :manager, :deptno, :mgrno}; + + if (cur5.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(manager, 7) + + " " + Data.format(deptno, 5) + + " " + Data.format(mgrno, 6)); + } + + // close the cursor + cur5.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // basicSubselectFromJoinedTable + + static void basicSubselectUsingSubquery() + { + try + { + int deptnumb = 0; + String deptname = ""; + TbRead_Cursor2 cur2; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT USING A SUBQUERY."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname\n" + + " FROM org\n" + + " WHERE deptnumb < (SELECT AVG(deptnumb) FROM org)\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + // declare a cursor + #sql cur2 = {SELECT deptnumb, deptname + FROM org + WHERE deptnumb < (SELECT AVG(deptnumb) FROM org)}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur2 INTO :deptnumb, :deptname}; + + if (cur2.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + } + + // close the cursor + cur2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // basicSubselectUsingSubquery + + static void basicSubselectUsingCorrelatedSubquery() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT USING A CORRELATED SUBQUERY."); + + // display the content of the 'org' table + orgTbContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT deptnumb, deptname\n" + + " FROM org o1\n" + + " WHERE deptnumb > (SELECT AVG(deptnumb)\n" + + " FROM org o2\n" + + " WHERE o2.division = o1.division)\n" + + "\n" + + " Results:\n" + + " DEPTNUMB DEPTNAME\n" + + " -------- --------------"); + + int deptnumb = 0; + String deptname = ""; + TbRead_Cursor2 cur2; + + // declare a cursor + #sql cur2 = {SELECT deptnumb, deptname + FROM org o1 + WHERE deptnumb > (SELECT AVG(deptnumb) + FROM org o2 + WHERE o2.division = o1.division)}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur2 INTO :deptnumb, :deptname}; + + if (cur2.endFetch()) + { + break; + } + + System.out.println(" " + Data.format(deptnumb, 8) + + " " + Data.format(deptname, 14)); + } + + // close the cursor + cur2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // basicSubselectUsingCorrelatedSubquery + + static void subselectUsingGroupingSets() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT USING GROUPING SETS."); + + employeeTbPartialContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT job, edlevel, SUM(comm)\n" + + " FROM employee\n" + + " WHERE job IN('DESIGNER', 'FIELDREP')\n" + + " GROUP BY GROUPING SETS((job, edlevel), (job))\n" + + "\n" + + " Results:\n" + + " JOB EDLEVEL SUM(COMM)\n" + + " -------- ------- -----------"); + + Integer edlevel = new Integer(0); + Double commSum = new Double(0.0); + String job = null; + TbRead_Cursor7 cur7; + + // declare a cursor + #sql cur7 = {SELECT job, edlevel, SUM(comm) + FROM employee + WHERE job IN('DESIGNER', 'FIELDREP') + GROUP BY GROUPING SETS((job, edlevel), (job))}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur7 INTO :job, :edlevel, :commSum}; + + if (cur7.endFetch()) + { + break; + } + + if (job != null) + { + System.out.print(" " + Data.format(job, 8)); + } + else + { + System.out.print(" -"); + } + if (edlevel != null) + { + System.out.print(" " + Data.format(edlevel, 7)); + } + else + { + System.out.print(" -"); + } + if (commSum != null) + { + System.out.print(" " + Data.format(commSum, 10, 2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + + // close the cursor + cur7.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // subselectUsingGroupingSets + + static void subselectUsingRollup() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT USING ROLLUP."); + + employeeTbPartialContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT job, edlevel, SUM(comm)\n" + + " FROM employee\n" + + " WHERE job IN('DESIGNER', 'FIELDREP')\n" + + " GROUP BY ROLLUP(job, edlevel)\n" + + "\n" + + " Results:\n" + + " JOB EDLEVEL SUM(COMM)\n" + + " -------- ------- -----------"); + + Integer edlevel = new Integer(0); + Double commSum = new Double(0.0); + String job = null; + TbRead_Cursor7 cur7; + + // declare a cursor + #sql cur7 = {SELECT job, edlevel, SUM(comm) + FROM employee + WHERE job IN('DESIGNER', 'FIELDREP') + GROUP BY ROLLUP(job, edlevel)}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur7 INTO :job, :edlevel, :commSum}; + + if (cur7.endFetch()) + { + break; + } + + if (job != null) + { + System.out.print(" " + Data.format(job, 8)); + } + else + { + System.out.print(" -"); + } + if (edlevel != null) + { + System.out.print(" " + Data.format(edlevel, 7)); + } + else + { + System.out.print(" -"); + } + if (commSum != null) + { + System.out.print(" " + Data.format(commSum, 10, 2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + + // close the cursor + cur7.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // subselectUsingRollup + + static void subselectUsingCube() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " DECLARE CURSOR\n" + + " FETCH\n" + + " CLOSE\n" + + "TO PERFORM A SUBSELECT USING CUBE."); + + employeeTbPartialContentDisplay(); + + System.out.println(); + System.out.println( + " Perform:\n" + + " SELECT job, edlevel, SUM(comm)\n" + + " FROM employee\n" + + " WHERE job IN('DESIGNER', 'FIELDREP')\n" + + " GROUP BY CUBE(job, edlevel)\n" + + "\n" + + " Results:\n" + + " JOB EDLEVEL SUM(COMM)\n" + + " -------- ------- -----------"); + + Integer edlevel = new Integer(0); + Double commSum = new Double(0.0); + String job = null; + TbRead_Cursor7 cur7; + + // declare a cursor + #sql cur7 = {SELECT job, edlevel, SUM(comm) + FROM employee + WHERE job IN('DESIGNER', 'FIELDREP') + GROUP BY CUBE(job, edlevel)}; + + while (true) + { + // fetch the cursor + #sql {FETCH :cur7 INTO :job, :edlevel, :commSum}; + + if (cur7.endFetch()) + { + break; + } + + if (job != null) + { + System.out.print(" " + Data.format(job, 8)); + } + else + { + System.out.print(" -"); + } + if (edlevel != null) + { + System.out.print(" " + Data.format(edlevel, 7)); + } + else + { + System.out.print(" -"); + } + if (commSum != null) + { + System.out.print(" " + Data.format(commSum, 10, 2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + } + + // close the cursor + cur7.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // subselectUsingCube + + static void selectUsingQuerySampling() + { + float avg = 0.0f; + + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO PERFORM A SELECT USING QUERY SAMPLING "); + + System.out.println( + "\nCOMPUTING AVG(SALARY) WITHOUT SAMPLING \n" + + "\n Perform:\n" + + " SELECT AVG(salary) FROM employee \n" + + "\n Results:\n" + + " AVG SALARY\n" + + " ----------"); + + TbRead_Cursor8 cur8; + + // declare a cursor + #sql cur8 = {SELECT AVG(salary) FROM employee}; + + // retrieve and display the result from the SELECT statement + #sql {FETCH :cur8 INTO :avg}; + System.out.println(" " + avg); + cur8.close(); + + System.out.println( + "\nCOMPUTING AVG(SALARY) WITH QUERY SAMPLING" + + "\n - ROW LEVEL SAMPLING " + + "\n - BLOCK LEVEL SAMPLING \n" + + "\n ROW LEVEL SAMPLING : USE THE KEYWORD 'BERNOULLI'\n" + + "\nFOR A SAMPLING PERCENTAGE OF P, EACH ROW OF THE TABLE IS\n" + + "SELECTED FOR THE INCLUSION IN THE RESULT WITH A PROBABILITY\n" + + "OF P/100, INDEPENDENTLY OF THE OTHER ROWS IN T\n" + + "\n Perform:\n" + + " SELECT AVG(salary) FROM employee TABLESAMPLE BERNOULLI(25)" + + " REPEATABLE(5)\n" + + "\n Results:\n" + + " AVG SALARY\n" + + " ----------"); + + #sql cur8 = {SELECT AVG(salary) + FROM employee + TABLESAMPLE BERNOULLI(25) REPEATABLE(5)}; + + // retrieve and display the result from the SELECT statement + #sql {FETCH :cur8 INTO :avg}; + System.out.println(" " +avg); + cur8.close(); + + System.out.println( + "\n\n BLOCK LEVEL SAMPLING : USE THE KEYWORD 'SYSTEM'\n" + + "\nFOR A SAMPLING PERCENTAGE OF P, EACH ROW OF THE TABLE IS\n" + + "SELECTED FOR INCLUSION IN THE RESULT WITH A PROBABILITY\n" + + "OF P/100, NOT NECESSARILY INDEPENDENTLY OF THE OTHER ROWS\n" + + "IN T, BASED UPON AN IMPLEMENTATION-DEPENDENT ALGORITHM\n" + + "\n Perform:\n" + + " SELECT AVG(salary) FROM employee TABLESAMPLE SYSTEM(50)" + + " REPEATABLE(1234)\n" + + "\n Results:\n" + + " AVG SALARY\n" + + " ----------" ); + + #sql cur8 = {SELECT AVG(salary) + FROM employee + TABLESAMPLE SYSTEM(50) REPEATABLE(1234)}; + + // retrieve and display the result from the SELECT statement + #sql {FETCH :cur8 INTO :avg}; + System.out.println(" " + avg); + + // close the cursor + cur8.close(); + + System.out.println( + "\nREPEATABLE CLAUSE ENSURES THAT REPEATED EXECUTIONS OF THAT\n" + + "TABLE REFERENCE WILL RETURN IDENTICAL RESULTS FOR THE SAME \n" + + "VALUE OF THE REPEAT ARGUMENT (IN PARENTHESIS)."); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // selectUsingQuerySampling +} // TbRead diff --git a/java/sqlj/TbRowcompress.sqlj b/java/sqlj/TbRowcompress.sqlj new file mode 100644 index 0000000..452f31b --- /dev/null +++ b/java/sqlj/TbRowcompress.sqlj @@ -0,0 +1,648 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbRowcompress.sqlj +// +// SAMPLE: How to perform row compression on a table +// +// This sample shows: +// 1. How to enable the row compression after a table is created. +// 2. How to enable the row compression during table creation. +// 3. Usage of the options to REORG to use the exiting dictionary +// or creating a new dictionary. +// 4. How to estimate the effectiveness of the compression. +// +// This sample should be run using the following steps: +// 1.Compile the program with the following command: +// javac TbRowcompress.java +// +// 2.The sample should be run using the following command +// java TbRowcompress +// The fenced user id must be able to create or overwrite files in +// the directory specified.This directory must be a full path on +// the server. The dummy file 'dummy.del' must +// exist before the sample is run. +// +// SQL STATEMENTS USED: +// ALTER TABLE +// COMMIT +// DELETE +// EXPORT +// FETCH +// IMPORT +// INSERT +// INSPECT +// REORG +// RUNSTATS +// SELECT +// UPDATE +// +// JAVA 2 CLASSES USED: +// Statement +// CallableStatement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// PREQUISITES : 1. Create the pre-requisite tables by running the command: +// TbRowcompressScrpt +// Alternatively,you can run the command: +// db2 -tvf TbRowcompress_setup.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj TbRowcompress +// 2. Run the sample as: +// java TbRowcompress +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf TbRowcompress_cleanup.db2 +// +// OUTPUT FILE: TbRowcompress.java (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator TbRowcompress_Cursor0(String); +#sql iterator TbRowcompress_Cursor1(int, int); +#sql iterator TbRowcompress_Cursor2(int, int, int, int, int); + +class TbRowcompress +{ + public static void main(String argv[]) + { + try + { + Connection con; + DefaultContext ctx; + + // initialize DB2Driver and establish database connection. + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection("jdbc:db2:SAMPLE"); + + ctx = new DefaultContext( con ); + DefaultContext.setDefaultContext(ctx); + + String path = argv[0]; + + System.out.println( + "THIS SAMPLE SHOWS HOW TO PERFROM ROW COMPRESSION ON A TABLE.\n" + + "\n-------------------------------------------------------------\n"); + + // to Load table data into a file. + getLoadData(con, path); + + // to enable row compression on table. + enableRowCompressionForTables(con, path); + + // to disable row compression on tables. + disableRowCompressionForTables(con, path); + + // to inspect the compression. + inspectCompression(con, path); + + // disconnect from the 'sample' database + con.close(); + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + } // main + + // this function shows how to prepare data for load + static void getLoadData(Connection con, String path) throws SQLException + { + try + { + System.out.println( + "\nThe temp table is created in the setup script \n" + + "TbRowcompress_setup.db2 using the command \n" + + "'CREATE TABLE temp(empno INT, sal INT)' \n"); + + // insert data into the table and export the data in order to obtain + // dummy.del file in the required format for load. + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO temp VALUES(100, 20000)\n" + + " INSERT INTO temp VALUES(200, 30000)\n" + + " INSERT INTO temp VALUES(100, 30500)\n" + + " INSERT INTO temp VALUES(300, 20000)\n" + + " INSERT INTO temp VALUES(400, 30000)"); + + // insert data into the table + #sql {INSERT INTO temp VALUES(100, 20000)}; + #sql {INSERT INTO temp VALUES(200, 30000)}; + #sql {INSERT INTO temp VALUES(100, 30500)}; + #sql {INSERT INTO temp VALUES(300, 20000)}; + #sql {INSERT INTO temp VALUES(400, 30000)}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " EXPORT \n" + + "TO EXPORT TABLE DATA INTO A FILE \n" + + "\n Perform:\n" + + " EXPORT TO dummy.del OF DEL SELECT * FROM temp"); + + // export data into a dummy file + // call the stored procedure ADMIN_CMD for EXPORT + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + + String str ="CALL SYSPROC.ADMIN_CMD" + + "('EXPORT TO " + + path + + "dummy.del OF DEL SELECT * FROM temp')"; + + Statement stmt = con.createStatement(); + stmt.execute(str); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // getLoadData + + // this function shows how to enable row compression for tables + static void enableRowCompressionForTables + (Connection con, String path) throws SQLException + { + try + { + System.out.println( + "\nTable empl1 is created in the setup script \n" + + "TbRowcompress_setup.db2 with compression not enabled\n" + + "at the time of table creation using the command\n" + + "'CREATE TABLE empl1(emp_no INT, salary INT)' \n"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " IMPORT \n" + + "TO IMPORT THE DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " IMPORT FROM dummy.del OF DEL INSERT INTO empl1"); + + // import data from file + // call the stored procedure ADMIN_CMD for IMPORT + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + + String str ="CALL SYSPROC.ADMIN_CMD" + + "('IMPORT FROM " + + path + + "dummy.del OF DEL INSERT INTO empl1')"; + + Statement stmt = con.createStatement(); + stmt.execute(str); + stmt.close(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO ENABLE ROW COMPRESSION \n" + + "\n Perform:\n" + + " ALTER TABLE empl1 COMPRESS YES"); + + // enable row compression + #sql {ALTER TABLE empl1 COMPRESS YES}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " REORG \n" + + "TO COMPRESS ROWS \n" + + "\n Perform:\n" + + " REORG TABLE empl1"); + + // perform non-inplace reorg to compress rows and to retain + // existing dictionary + // call the stored procedure ADMIN_CMD for REORG + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + #sql {CALL SYSPROC.ADMIN_CMD('REORG TABLE empl1')}; + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // enableRowCompressionForTables + + // this function shows how to disable rowcompression on table + static void disableRowCompressionForTables + (Connection con, String path) throws SQLException + { + try + { + System.out.println( + "\nTable empl2 is created in the setup script TbRowcompress_setup.db2\n" + + "with compression enabled initially using the command \n" + + "'CREATE TABLE empl2(emp_no INT, salary INT) COMPRESS YES' \n"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " IMPORT \n" + + "TO IMPORT THE DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " IMPORT FROM dummy.del OF DEL INSERT INTO empl2"); + + // import data into the table + // call the stored procedure ADMIN_CMD for IMPORT + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + String str ="CALL SYSPROC.ADMIN_CMD" + + "('IMPORT FROM " + + path + + "dummy.del OF DEL INSERT INTO empl2')"; + + Statement stmt = con.createStatement(); + stmt.execute(str); + stmt.close(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " REORG \n" + + "TO COMPRESS ROWS \n" + + "\n Perform:\n" + + " REORG TABLE empl2"); + + // perform reorg to compress rows + // call the stored procedure ADMIN_CMD for REORG + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + #sql {CALL SYSPROC.ADMIN_CMD('REORG TABLE empl2')}; + #sql {COMMIT}; + + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + " UPDATE \n" + + " DELETE \n" + + "TO INSERT, UPDATE OR DELETE DATA IN TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl2 VALUES(400, 30000)\n" + + " UPDATE empl2 SET salary = salary + 1000\n" + + " DELETE FROM empl2 WHERE emp_no = 200"); + + // perform modifications on table + #sql {INSERT INTO empl2 VALUES(400, 30000)}; + #sql {UPDATE empl2 SET salary = salary + 1000}; + #sql {DELETE FROM empl2 WHERE emp_no = 200}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO DISABLE ROW COMPRESSION FOR THE TABLE \n" + + "\n Perform:\n" + + " ALTER TABLE empl2 COMPRESS NO"); + + // disable row compression for the table + #sql {ALTER TABLE empl2 COMPRESS NO}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " REORG TABLE \n" + + "TO REORG THE TABLE AND REMOVE EXISTING DICTIONARY \n" + + "\n Perform:\n" + + " REORG TABLE empl2 RESETDICTIONARY"); + + // Perform reorg to remove existing dictionary. + // New dictionary will be created and all the rows processed + // by the reorg are decompressed. + // call the stored procedure ADMIN_CMD for REORG + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + #sql {CALL SYSPROC.ADMIN_CMD('REORG TABLE empl2 RESETDICTIONARY')}; + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // disableRowCompressionForTables + + // this function demonstrates the extent of row compression for table + static void inspectCompression(Connection con, String path) throws SQLException + { + try + { + System.out.println( + "\nTable empl3 is created in the setup script \n" + + "TbRowcompress_setup.db2 using the command \n" + + "'CREATE TABLE empl3(emp_no INT, salary INT)' \n"); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " IMPORT \n" + + "TO IMPORT DATA INTO TABLE \n" + + "\n Perform:\n" + + " IMPORT FROM dummy.del OF DEL INSERT INTO empl3"); + + // import data into the table + // call the stored procedure ADMIN_CMD for IMPORT + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + String str ="CALL SYSPROC.ADMIN_CMD" + + "('IMPORT FROM " + + path + + "dummy.del OF DEL INSERT INTO empl3')"; + + Statement stmt = con.createStatement(); + stmt.execute(str); + stmt.close(); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO ENABLE COMPRESSION \n" + + "\n Perform:\n" + + " ALTER TABLE empl3 COMPRESS YES"); + + // enable row compression for the table + #sql {ALTER TABLE empl3 COMPRESS YES}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl3 VALUES(400, 30000)"); + + // insert some data into the table + #sql {INSERT INTO empl3 VALUES(400, 30000)}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSPECT \n" + + "TO ESTIMATE THE EFFECTIVENESS OF COMPRESSION \n" + + "\n Perform:\n" + + " INSPECT ROWCOMPESTIMATE TABLE NAME empl3 RESULTS KEEP result"); + + // Perform inspect to estimate the effectiveness of compression. + // Inspect has to be run before the REORG utility. + // Inspect allows you to look over tablespaces and tables for their + // architectural integrity. + // 'result' file contains percentage of bytes saved from compression, + // Percentage of rows ineligible for compression due to small row size, + // Compression dictionary size, Expansion dictionary size etc. + // To view the contents of 'result' file perform + // db2inspf result result.out; This formats the 'result' file to + // readable form. + + String execCmd = "db2 INSPECT ROWCOMPESTIMATE TABLE NAME empl3" + + " RESULTS KEEP result"; + + // execute the command + Process p1 = Runtime.getRuntime().exec(execCmd); + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " REORG \n" + + "TO REORG THE TABLE \n" + + "\n Perform:\n" + + " REORG TABLE empl3"); + + // perform reorg on the table + // call the stored procedure ADMIN_CMD for REORG + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + #sql {CALL SYSPROC.ADMIN_CMD('REORG TABLE empl3')}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl3 VALUES(500, 40000)"); + + // all the rows will be compressed including the one inserted + // after reorg + #sql {INSERT INTO empl3 VALUES(500, 40000)}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO DISABLE THE COMPRESSION \n" + + "\n Perform:\n" + + " ALTER TABLE empl3 COMPRESS NO"); + + // disable row compression for the table. + // rows inserted after this will be non-compressed. + #sql {ALTER TABLE empl3 COMPRESS NO}; + #sql {COMMIT}; + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl3 VALUES(600, 40500)"); + + // add one row of data to the table + #sql {INSERT INTO empl3 VALUES(600, 40500)}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " ALTER TABLE \n" + + "TO ENABLE THE COMPRESSION \n" + + "\n Perform:\n" + + " ALTER TABLE empl3 COMPRESS YES"); + + // enable the row compression for the table + #sql {ALTER TABLE empl3 COMPRESS YES}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT \n" + + "TO INSERT DATA INTO THE TABLE \n" + + "\n Perform:\n" + + " INSERT INTO empl3 VALUES(700, 40600)"); + + // add one row of data to the table + #sql {INSERT INTO empl3 VALUES(700, 40600)}; + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " RUNSTATS \n" + + "TO MEASURE THE EFFECTIVENESS OF COMPRESSION \n" + + "\n Perform:\n" + + " RUNSTATS ON TABLE EMPL"); + + // Perform runstats to measure the effectiveness of compression using + // compression related catalog fields. New columns will be updated to + // catalog table after runstats if performed on a compressed table. + + // get fully qualified name of the table + String tableName = "EMPL3"; + String schemaName = getSchemaName(tableName); + String fullTableName = schemaName + "." + tableName; + + // call the stored procedure ADMIN_CMD for RUNSTATS + System.out.println(); + System.out.println("Call stored procedure named SYSPROC.ADMIN_CMD"); + str = "CALL SYSPROC.ADMIN_CMD('" + + "RUNSTATS ON TABLE " + + fullTableName + + "')"; + + Statement stmt1 = con.createStatement(); + stmt1.execute(str); + + stmt1.close(); + + System.out.println(); + System.out.println(" SELECT * FROM empl3"); + System.out.println( + " EMP_NO SALARY\n" + + " ------ ------"); + + int emp_no = 0; + int sal = 0; + + TbRowcompress_Cursor1 cur1; + + // declare a cursor + #sql cur1 = {SELECT * FROM empl3}; + + // fetch the cursor + #sql {FETCH :cur1 INTO :emp_no, :sal}; + + while (!cur1.endFetch()) + { + System.out.println( + " " + Data.format(emp_no, 3) + + " " + Data.format(sal, 5)); + + #sql {FETCH :cur1 INTO :emp_no, :sal}; + } + + // close the cursor + cur1.close(); + + System.out.println(); + System.out.println( + "SELECT avgrowsize, avgcompressedrowsize, pctpagessaved,\n" + + " avgrowcompressionratio, pctrowscompressed\n" + + " FROM SYSCAT.TABLES WHERE tabname = 'EMPL3'"); + System.out.println( + "\n AvRowSize AvCmprsdRowSize PerPgSaved AvgRowCmprRatio" + + " PerRowsCmprsd\n" + + " --------- --------------- ---------- ---------------" + + " -------------"); + + int avgrowsize = 0; + int avgcompressedrowsize = 0; + int pctpagessaved = 0; + int avgrowcompressionratio = 0; + int pctrowscompressed = 0; + + TbRowcompress_Cursor2 cur2; + + // declare a cursor + #sql cur2 = {SELECT avgrowsize, avgcompressedrowsize, + pctpagessaved, avgrowcompressionratio, + pctrowscompressed + FROM SYSCAT.TABLES + WHERE tabname = 'EMPL3'}; + + // fetch the cursor + #sql {FETCH :cur2 INTO :avgrowsize, :avgcompressedrowsize, + :pctpagessaved, :avgrowcompressionratio, + :pctrowscompressed}; + + while (!cur2.endFetch()) + { + System.out.println( + " " + Data.format(avgrowsize, 4) + + " " + Data.format(avgcompressedrowsize, 11) + + " " + Data.format(pctpagessaved, 9) + + " " + Data.format(avgrowcompressionratio, 9) + + " " + Data.format(pctrowscompressed, 13)); + + #sql {FETCH :cur2 INTO :avgrowsize, :avgcompressedrowsize, + :pctpagessaved, :avgrowcompressionratio, + :pctrowscompressed}; + } + + // close the cursor + cur2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // inspectCompression + + // function to get the schema name for a particular table + static String getSchemaName(String tableName) throws Exception + { + // declare a cursor to run through the result of the query + TbRowcompress_Cursor0 cur0; + + #sql cur0 = {SELECT tabschema FROM syscat.tables WHERE tabname = :tableName}; + + String schemaName = null; + #sql {FETCH :cur0 INTO :schemaName}; + + // remove the trailing white space characters from schemaName before + // returning it to the calling function + return schemaName.trim(); + + } // getSchemaName +} + diff --git a/java/sqlj/TbRowcompressScrpt b/java/sqlj/TbRowcompressScrpt new file mode 100644 index 0000000..c7a366a --- /dev/null +++ b/java/sqlj/TbRowcompressScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: TbRowcompressScrpt +# TbRowcompress_cleanup.db2 drops tables created by LargeRid_setup.db2 for the +# sample TbRowcompress.sqlj +# TbRowcompress_setup.db2 creates tables necessary for execution of the sample +# TbRowcompress.sqlj +# Both CLP scripts can be run on their own +# Usage: TbRowcompressScrpt + +db2 -tvf TbRowcompress_cleanup.db2 +db2 -tvf TbRowcompress_setup.db2 diff --git a/java/sqlj/TbRowcompress_cleanup.db2 b/java/sqlj/TbRowcompress_cleanup.db2 new file mode 100644 index 0000000..eac233e --- /dev/null +++ b/java/sqlj/TbRowcompress_cleanup.db2 @@ -0,0 +1,62 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: TbRowcompress_cleanup.db2 +-- +-- SAMPLE: Cleanup script for the sample TbRowcompress.sqlj +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf TbRowcompress_cleanup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad + +---------------------------------------------------------------------------- + +connect to sample; + +-- drop the temporary table + +DROP TABLE temp; + +-- drop table empl1 + +DROP TABLE empl1; + +-- drop table empl2 + +DROP TABLE empl2; + +-- drop table empl3 + +DROP TABLE empl3; + +connect reset; diff --git a/java/sqlj/TbRowcompress_setup.db2 b/java/sqlj/TbRowcompress_setup.db2 new file mode 100644 index 0000000..3ad2035 --- /dev/null +++ b/java/sqlj/TbRowcompress_setup.db2 @@ -0,0 +1,64 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: TbRowcompress_setup.db2 +-- +-- SAMPLE: This sample serves as the setup script for the sample +-- TbRowcompress.sqlj +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf TbRowcompress_setup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad + +---------------------------------------------------------------------------- + +connect to sample; + +-- create a temporary table + +CREATE TABLE temp(empno INT, sal INT); + +-- create a table without enabling row compression at the time of +-- table creation + +CREATE TABLE empl1(emp_no INT, salary INT); + +-- create a table enabling compression initially + +CREATE TABLE empl2(emp_no INT, salary INT) COMPRESS YES; + +-- create a table to demonstrate the extent of row compression for table + +CREATE TABLE empl3(emp_no INT, salary INT); + +connect reset; diff --git a/java/sqlj/TbRunstats.sqlj b/java/sqlj/TbRunstats.sqlj new file mode 100644 index 0000000..2659c1a --- /dev/null +++ b/java/sqlj/TbRunstats.sqlj @@ -0,0 +1,176 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbRunstats.sqlj +// +// SAMPLE: How to perform runstats on a table +// +// SQL STATEMENTS USED: +// SELECT +// CONNECT +// RUNSTATS +// +// JAVA 2 CLASSES USED: +// Statement +// File +// FileWriter +// Process +// BufferedReader +// InputStreamReader +// +// Classes used from Util.java are: +// Db +// SqljException +// +// OUTPUT FILE: TbRunstats.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** + +import java.sql.*; +import java.lang.*; +import java.io.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator TbRunstats_Cursor0(String); + +public class TbRunstats +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + // call tbRunstats that updates the statistics of employee table + tbRunstats(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // call runstats on 'employee' table to update its statistics + static void tbRunstats() throws Exception + { + System.out.print( + "\n-----------------------------------------------------------\n" + + "\nUSE THE SQL STATEMENT:\n"+ + " RUNSTATS\n" + + "TO UPDATE TABLE STATISTICS.\n"); + + // get fully qualified name of the table + String tableName = "EMPLOYEE"; + String schemaName = schemaNameGet(tableName); + String fullTableName = schemaName + "." + tableName; + + try + { + // store the CLP commands in a file and execute the file + File outputFile = new File("RunstatsCmd.db2"); + FileWriter out = new FileWriter(outputFile); + + String cmd = "RUNSTATS ON TABLE "+ fullTableName + + " WITH DISTRIBUTION ON KEY COLUMNS" + + " DEFAULT NUM_FREQVALUES 30 NUM_QUANTILES -1" + + " ALLOW READ ACCESS"; + + out.write("CONNECT TO SAMPLE;\n"); + out.write(cmd + ";\n"); + out.write("CONNECT RESET;\n"); + + out.close(); + + Process p = Runtime.getRuntime().exec("db2 -vtf RunstatsCmd.db2"); + + BufferedReader stdInput = new BufferedReader(new + InputStreamReader(p.getInputStream())); + BufferedReader stdError = new BufferedReader(new + InputStreamReader(p.getErrorStream())); + String s; + + // read the output from the command and set the output variable with + // the value + while ((s = stdInput.readLine()) != null) + { + System.out.println(s); + } + + // read any errors from the attempted command and set the error + // variable with the value + while ((s = stdError.readLine()) != null) + { + System.out.println(s); + } + + // destroy the process created + p.destroy(); + + // delete the temporary file created + outputFile.deleteOnExit(); + } + catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + } // tbRunstats + + // function to get the schema name for a particular table + static String schemaNameGet(String tableName) throws Exception + { + // declare a cursor to run through the result of the query + TbRunstats_Cursor0 cur0; + + #sql cur0 = {SELECT tabschema + FROM syscat.tables + WHERE tabname = :tableName}; + + String schemaName = null; + #sql {FETCH :cur0 INTO :schemaName}; + + // remove the trailing white space characters from schemaName before + // returning it to the calling function + return schemaName.trim(); + + } // schemaNameGet +} // TbRunstats diff --git a/java/sqlj/TbSel.sqlj b/java/sqlj/TbSel.sqlj new file mode 100644 index 0000000..f998b49 --- /dev/null +++ b/java/sqlj/TbSel.sqlj @@ -0,0 +1,517 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbSel.sqlj +// +// SAMPLE: How to select from each of: insert, update, delete. +// +// SQL Statements USED: +// INCLUDE +// CREATE TABLE +// INSERT +// SELECT FROM INSERT +// SELECT FROM UPDATE +// SELECT FROM DELETE +// PREPARE +// DROP TABLE +// +// OUTPUT FILE: TbSel.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class TbSel +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS EXAMPLE SHOWS HOW TO SELECT FROM EACH OF: " + + "INSERT, UPDATE, DELETE.\n"); + + // Connect to database. + ctx = db.getDefaultContext(); + + Create( ctx.getConnection() ); + Print( ctx.getConnection() ); + Buy_Company( ctx.getConnection() ); + Print( ctx.getConnection() ); + Drop(); + + // Disconnect from database. + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // Main + + /* The Create function creates and populates the tables used by the + sample. + */ + static void Create(Connection con) + { + try + { + + /* The context for this sample is that of a Company B taking over + a Company A. This sample illustrates how company B incorporates + data from table company_b into table company_a. + */ + + System.out.println( + "\nCREATE TABLE company_a \n" + + " (ID SMALLINT NOT NULL UNIQUE, \n" + + " NAME VARCHAR(9), \n" + + " DEPARTMENT SMALLINT, \n" + + " JOB CHAR(5), \n" + + " YEARS SMALLINT, \n" + + " SALARY DECIMAL(7,2))\n"); + + // Company A is being bought out. + #sql {CREATE TABLE company_a + (ID SMALLINT NOT NULL UNIQUE, + NAME VARCHAR(9), + DEPARTMENT SMALLINT, + JOB CHAR(5), + YEARS SMALLINT, + SALARY DECIMAL(7,2))}; + + System.out.println( + "CREATE TABLE company_b \n" + + " (ID SMALLINT GENERATED BY DEFAULT AS IDENTITY (START WITH 2000, " + + "INCREMENT BY 1) NOT NULL, \n" + + " NAME VARCHAR(9), \n" + + " DEPARTMENT SMALLINT, \n" + + " JOB CHAR(5), \n" + + " YEARS SMALLINT, \n" + + " SALARY DECIMAL(7,2), \n" + + " BENEFITS VARCHAR(50), \n" + + " OLD_ID SMALLINT)\n"); + + // Company B is buying out Company A. This table has a few additional + // columns and differences from the previous table. Specifically, the + // ID column is generated. + #sql {CREATE TABLE company_b + (ID SMALLINT GENERATED BY DEFAULT AS IDENTITY (START WITH 2000, INCREMENT BY 1) NOT NULL, + NAME VARCHAR(9), + DEPARTMENT SMALLINT, + JOB CHAR(5), + YEARS SMALLINT, + SALARY DECIMAL(7,2), + BENEFITS VARCHAR(50), + OLD_ID SMALLINT)}; + + System.out.println( + "CREATE TABLE salary_change \n" + + " (ID SMALLINT NOT NULL UNIQUE, \n" + + " OLD_SALARY DECIMAL(7,2), \n" + + " SALARY DECIMAL(7,2))\n"); + + // This table can be used by the management of Company B to see how + // much of a raise they gave to employees from Company A for joining + // Company B (in a dollar amount, as opposed to a 5% increase). + #sql {CREATE TABLE salary_change + (ID SMALLINT NOT NULL UNIQUE, + OLD_SALARY DECIMAL(7,2), + SALARY DECIMAL(7,2))}; + + System.out.println( + "INSERT INTO company_a VALUES(5275, 'Sanders', 20, " + + "'Mgr', 15, 18357.50), \n" + + " (5265, 'Pernal', 20, 'Sales', NULL, 18171.25), \n" + + " (5791, 'O''Brien', 38, 'Sales', 9, 18006.00)\n"); + + // Populate table company_a with data. + PreparedStatement stmt1 = con.prepareStatement( + "INSERT INTO company_a VALUES(5275, 'Sanders', 20, " + + "'Mgr', 15, 18357.50), " + + "(5265, 'Pernal', 20, 'Sales', NULL, 18171.25), " + + "(5791, 'O''Brien', 38, 'Sales', 9, 18006.00)"); + stmt1.execute(); + stmt1.close(); + + System.out.println( + "INSERT INTO company_b VALUES" + + "(default, 'Naughton', 38, 'Clerk', NULL, 12954.75, " + + "'No Benefits', NULL), \n" + + " (default, 'Yamaguchi', 42, 'Clerk', 5, 10505.00, " + + "'Basic Health Coverage', NULL), \n" + + " (default, 'Fraye', 51, 'Mgr', 8, 21150.00, " + + "'Basic Health Coverage', NULL), \n" + + " (default, 'Williams', 51, 'Sales', 10, 19456.50, " + + "'Advanced Health Coverage', NULL), \n" + + " (default, 'Molinare', 10, 'Mgr', 15, 22959.20, " + + "'Advanced Health Coverage and Pension Plan', NULL)\n"); + + // Populate table company_b with data. + PreparedStatement stmt2 = con.prepareStatement( + "INSERT INTO company_b VALUES " + + "(default, 'Naughton', 38, 'Clerk', NULL, 12954.75, " + + "'No Benefits', NULL), " + + "(default, 'Yamaguchi', 42, 'Clerk', 5, 10505.00, " + + "'Basic Health Coverage', NULL), " + + "(default, 'Fraye', 51, 'Mgr', 8, 21150.00, " + + "'Basic Health Coverage', NULL), " + + "(default, 'Williams', 51, 'Sales', 10, 19456.50, " + + "'Advanced Health Coverage', NULL), " + + "(default, 'Molinare', 10, 'Mgr', 15, 22959.20, " + + "'Advanced Health Coverage and Pension Plan', NULL)\n"); + stmt2.execute(); + stmt2.close(); + + // Commit + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // Create + + /* The Buy_Company function encapsulates the table updates after Company + B takes over Company A. Each employees from table company_a is + allocated a benefits package. The employee data is moved into table + company_b. Each employee's salary is increased by 5%. The old and + new salaries are recorded in a table salary_change. + */ + static void Buy_Company(Connection con) + { + try + { + + int id; // Employee's ID + int department; // Employee's department + int years; // Number of years employee has + // worked with the company + int new_id = 0; // Employee's new ID when they + // switch companies + + String name; // Employee's name + String job; // Employee's job title + String benefits = new String(); // Employee's benefits + + double salary; // Employee's current salary + double old_salary; // Employee's old salary + + /* The following SELECT statement references a DELETE statement + in its FROM clause. It deletes all rows from company_a, + selecting all deleted rows into the ResultSet rs. + */ + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT ID, NAME, DEPARTMENT, JOB, YEARS, SALARY " + + "FROM OLD TABLE (DELETE FROM company_a)"); + while(rs.next()) + { + id = rs.getInt(1); + name = rs.getString(2); + department = rs.getInt(3); + job = rs.getString(4); + years = rs.getInt(5); + salary = rs.getDouble(6); + + /* The following if statement sets the new employee's benefits based + on their years of experience. + */ + if(years > 14) + benefits = "Advanced Health Coverage and Pension Plan"; + else if(years > 9) + benefits = "Advanced Health Coverage"; + else if(years > 4) + benefits = "Basic Health Coverage"; + else + benefits = "No Benefits"; + + /* The following SELECT statement references an INSERT statement in + its FROM clause. It inserts an employee record from host + variables into table company_b. The current employee ID from the + ResultSet is selected into the host variable new_id. The + keywords FROM FINAL TABLE determine that the value in new_id is + the value of ID after the INSERT statement is complete. + + Note that the ID column in table company_b is generated and + without the SELECT statement an additional query would have to be + made in order to retrieve the employee's ID number. + */ + PreparedStatement stmt1 = con.prepareStatement( + "SELECT ID " + + "FROM FINAL TABLE (INSERT INTO company_b " + + "VALUES(default, ?, ?, ?, ?, ?, ?, ?))"); + + stmt1.setString(1, name); + stmt1.setInt(2, department); + stmt1.setString(3, job); + stmt1.setInt(4, years); + stmt1.setDouble(5, salary); + stmt1.setString(6, benefits); + stmt1.setInt(7, id); + + ResultSet rs1 = stmt1.executeQuery(); + rs1.next(); + + new_id = rs1.getInt(1); + + stmt1.close(); + rs1.close(); + + /* The following SELECT statement references an UPDATE statement + in its FROM clause. It updates an employee's salary by giving + them a 5% raise. The employee's id, old salary and current + salary are all read into host varibles for later use in this + function. + + The INCLUDE statement works by creating a temporary column to + keep track of the old salary. This temporary column is only + available for this statement and is gone once the statement + completes. The only way to keep this data after the statement + completes is to read it into a host variable. + */ + PreparedStatement stmt2 = con.prepareStatement( + "SELECT ID, OLD_SALARY, SALARY " + + "FROM FINAL TABLE (UPDATE company_b INCLUDE " + + "(OLD_SALARY DECIMAL(7,2)) " + + "SET OLD_SALARY = SALARY, " + + " SALARY = SALARY * 1.05 " + + "WHERE ID = ?)"); + stmt2.setInt(1, new_id); + + ResultSet rs2 = stmt2.executeQuery(); + rs2.next(); + + id = rs2.getInt(1); + old_salary = rs2.getDouble(2); + salary = rs2.getDouble(3); + + stmt2.close(); + rs2.close(); + + /* This INSERT statement inserts an employee's id, old salary and + current salary into the salary_change table. + */ + PreparedStatement stmt3 = con.prepareStatement( + "INSERT INTO salary_change VALUES(?, ?, ?)"); + + stmt3.setInt(1, id); + stmt3.setDouble(2, old_salary); + stmt3.setDouble(3, salary); + stmt3.execute(); + stmt3.close(); + } + rs.close(); + stmt.close(); + + /* The following DELETE statement references a SELECT statement in its + FROM clause. It lays off the highest paid manager. This DELETE + statement removes the manager from the table company_b. + */ + PreparedStatement stmt4 = con.prepareStatement( + "DELETE FROM (SELECT * FROM company_b ORDER BY SALARY DESC FETCH " + + "FIRST ROW ONLY)"); + stmt4.execute(); + stmt4.close(); + + /* The following UPDATE statement references a SELECT statement in its + FROM clause. It gives the most senior employee a $10000 bonus. + This UPDATE statement raises the employee's salary in the table + company_b. + */ + PreparedStatement stmt5 = con.prepareStatement( + "UPDATE (SELECT MAX(YEARS) OVER() AS max_years, " + + "YEARS, " + + "SALARY" + + " FROM company_b) " + + " SET SALARY = SALARY + 10000 " + + " WHERE max_years = YEARS"); + stmt5.execute(); + stmt5.close(); + + // Commit + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // Buy_Company + + /* The Print function outputs the data in the tables: company_a, company_b + and salary_change. For each table, a while loop and ResultSet are used + to fetch and display row data. + */ + static void Print(Connection con) + { + try + { + int id; // Employee's ID + int department; // Employee's department + int years; // Number of years employee has + // worked with the company + int new_id = 0; // Employee's new ID when they + // switch companies + + String name; // Employee's name + String job; // Employee's job title + String benefits = new String(); // Employee's benefits + + double salary; // Employee's current salary + double old_salary; // Employee's old salary + + System.out.println("\nSELECT * FROM company_a\n"); + System.out.println( + "ID NAME DEPARTMENT JOB YEARS SALARY\n" + + "------ --------- ---------- ----- ------ ---------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM company_a"); + + while (rs.next()) + { + id = rs.getInt(1); + name = rs.getString(2); + department = rs.getInt(3); + job = rs.getString(4); + years = rs.getInt(5); + salary = rs.getDouble(6); + + System.out.println( + Data.format(id, 6) + " " + + Data.format(name, 9) + " " + + Data.format(department, 10) + " " + + Data.format(job, 5) + " " + + Data.format(years, 6) + " " + + Data.format(String.valueOf(salary), 9)); + } + rs.close(); + stmt.close(); + + System.out.println(); + System.out.println("SELECT * FROM company_b\n"); + System.out.println( + "ID NAME DEPARTMENT JOB YEARS SALARY \nBENEFITS OLD_ID\n" + + "------ --------- ---------- ----- ------ --------- \n-------------------------------------------------- ------"); + + Statement stmt1 = con.createStatement(); + ResultSet rs1 = stmt1.executeQuery("SELECT * FROM company_b"); + + while (rs1.next()) + { + new_id = rs1.getInt(1); + name = rs1.getString(2); + department = rs1.getInt(3); + job = rs1.getString(4); + years = rs1.getInt(5); + salary = rs1.getDouble(6); + benefits = rs1.getString(7); + id = rs1.getInt(8); + + System.out.println( + Data.format(new_id, 6) + " " + + Data.format(name, 9) + " " + + Data.format(department, 10) + " " + + Data.format(job, 5) + " " + + Data.format(years, 6) + " " + + Data.format(String.valueOf(salary), 9) + "\n" + + Data.format(benefits, 50) + " " + + Data.format(id, 6) + "\n"); + } + rs1.close(); + stmt1.close(); + + System.out.println("SELECT * FROM salary_change\n"); + System.out.println( + "ID OLD_SALARY SALARY\n" + + "------ ---------- ---------"); + + Statement stmt2 = con.createStatement(); + ResultSet rs2 = stmt2.executeQuery("SELECT * FROM salary_change"); + + while (rs2.next()) + { + id = rs2.getInt(1); + old_salary = rs2.getDouble(2); + salary = rs2.getDouble(3); + + System.out.println( + Data.format(id, 6) + " " + + Data.format(String.valueOf(old_salary), 11) + " " + + Data.format(String.valueOf(salary), 9)); + } + rs2.close(); + stmt2.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // Print + + /* The Drop function drops the tables used by this sample. */ + static void Drop() + { + try + { + System.out.println(); + System.out.println("DROP TABLE company_a\n"); + #sql {DROP TABLE company_a}; + + System.out.println("DROP TABLE company_b\n"); + #sql {DROP TABLE company_b}; + + System.out.println("DROP TABLE salary_change"); + #sql {DROP TABLE salary_change}; + + // Commit + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // Drop +} // TbSel diff --git a/java/sqlj/TbTemp.sqlj b/java/sqlj/TbTemp.sqlj new file mode 100644 index 0000000..2d7df8f --- /dev/null +++ b/java/sqlj/TbTemp.sqlj @@ -0,0 +1,482 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbTemp.sqlj +// +// SAMPLE: How to use Declared Temporary Table +// +// This sample: +// 1. Creates a user temporary table space required for declared +// temporary tables +// 2. Creates and populates a declared temporary table +// 3. Shows that the declared temporary table exists after a commit +// and shows the declared temporary table's use in a procedure +// 4. Shows that the temporary table can be recreated with the same +// name using the "with replace" option and without "not logged" +// clause, to enable logging. +// 5. Shows the creation of an index on the temporary table. +// 6. Show the usage of "describe" command to obtain information +// regarding the tempraroy table. +// 7. Shows that the temporary table is implicitly dropped with a +// disconnect from the database +// 8. Drops the user temporary table space +// +// To Run on the Command line: +// sqlj TbTemp.sqlj +// javac TbTemp.java +// java TbTemp [dbUserName][password] +// +// This sample assumes that the database specified by databaseAlias +// contains a table named "department" and that the table's structure +// is the same as the one for the department table in the SAMPLE +// database. +// +// The following objects are made and later removed: +// (If objects with these names already exist, an error message will +// be printed out.) +// 1. a user temporary tablespace named usertemp1 +// 2. a declared global temporary table named temptb1 +// +// +// SQL STATEMENTS USED: +// CREATE USER TEMPORARY TABLESPACE +// DECLARE GLOBAL TEMPORARY TABLE +// INSERT +// DROP TABLESPACE +// +// Classes used from Util.java are: +// Db +// SqljException +// +// OUTPUT FILE: TbTemp.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** + +import java.sql.*; +import java.lang.*; +import java.io.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +// declare an iterator for result of the select command on temptb1 +#sql iterator TbTemp_Cursor0(String, String, String, String, String); + +public class TbTemp +{ + public static void main (String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("HOW TO USE DECLARED TEMPORARY TABLES.\n"); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + // make sure a user temporary table space exists before creating + // the table + createTablespace(); + + // show how to make a declared temporary table + declareTempTable(); + + // show that the temporary table exists in ShowAfterCommit() even + // though it was declared in DeclareTempTable(). The temporary table + // is accessible to the whole session as the connection still exists + // at this point. Show that the temporary table exists after a commit. + showAfterCommit(); + + // declare the temporary table again. The old one will be dropped and + // a new one will be made. + recreateTempTableWithLogging(); + #sql {COMMIT}; + + // create an index for the global temporary table + createIndex(); + + // use the ResultSetMetaData to describe the temp table + describeTemporaryTable(ctx.getConnection()); + + // disconnect from the 'sample' database. This implicitly drops the + // temporary table. Alternatively, an explicit drop statement could + // have been used. + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + Db db = new Db(argv); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + dropTablespace(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // Create a user temporary tablespace for the temp table. A user + // temporary tablespace is required for temp tables and none are created + // at database creation time. + static void createTablespace() throws SQLException + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " CREATE USER TEMPORARY TABLESPACE \n" + + "TO MAKE A USER TEMPORARY TABLESPACE FOR THE TEMP TABLE \n" + + "IN A DIRECTORY CALLED usertemp, RELATIVE TO THE DATABASE" + + "\n Perform:\n" + + " CREATE USER TEMPORARY TABLESPACE usertemp1"); + + #sql {CREATE USER TEMPORARY TABLESPACE usertemp1}; + #sql {COMMIT}; + } // createTableSpace + + // Declare a temporary table with the same columns as the one for the + // database's department table. Populate the temporary table and + // show the contents. + static void declareTempTable() throws Exception + { + // Declare the declared temporary table. It is created empty. + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " DECLARE GLOBAL TEMPORARY TABLE\n" + + "TO MAKE A GLOBAL DECLARED TEMPORARY TABLE WITH THE SAME \n" + + "COLUMNS AS THE DEPARTMENT TABLE." + + "\n Perform:\n" + + " DECLARE GLOBAL TEMPORARY TABLE temptb1 \n" + + " LIKE department \n" + + " NOT LOGGED\n"); + + #sql {DECLARE GLOBAL TEMPORARY TABLE temptb1 + LIKE department + NOT LOGGED + IN usertemp1}; + #sql {COMMIT}; + + populateTempTable(); + showTableContents(); + } // declareTempTable + + // Drop the user temp tablespace. This function assumes that the tablespace + // can be dropped. If the declared temporary table still exists in the + // tablespace, then the tablespace cannot be dropped. + static void dropTablespace() throws SQLException + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " DROP TABLESPACE \n" + + "TO REMOVE THE TABLESPACE THAT THIS PROGRAM CREATED\n" + + "\n Perform:\n" + + " DROP TABLESPACE usertemp1\n"); + + #sql {DROP TABLESPACE usertemp1}; + #sql {COMMIT}; + } // dropTablespace + + // Populate the temp table with the department table's contents + static void populateTempTable() throws Exception + { + // Populating the temp table is done the same way as a normal table + // except the qualifier "session" is required whenever the table name + // is referenced. + System.out.println( + "\nUSE THE SQL STATEMENTS:\n" + + " INSERT\n" + + "TO POPULATE THE DECLARED TEMPORARY TABLE WITH DATA FROM\n" + + "THE DEPARTMENT TABLE\n" + + "\n Perform:\n" + + " INSERT INTO session.temptb1\n" + + " (SELECT deptno, deptname, mgrno, admrdept, location\n" + + " FROM department)\n"); + + #sql {INSERT INTO session.temptb1 + (SELECT deptno, deptname, mgrno, admrdept, location + FROM department)}; + } // populateTempTable + + // Declare the temp table temptb1 again, this time with logging option, + // thereby replacing the existing one. If the "with replace" option is not + // used, then an error will result if the table name is already associated + // with an existing temp table. Populate and show contents again. + static void recreateTempTableWithLogging() throws Exception + { + // Declare the declared temporary table again, this time without the + // NOT LOGGED clause. It is created empty. + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + "\nDECLARE GLOBAL TEMPORARY TABLE\n" + + "TO REPLACE A GLOBAL DECLARED TEMPORARY TABLE WITH A NEW\n" + + "TEMPORARY TABLE OF THE SAME NAME WITH LOGGING ENABLED.\n" + + "\n Perform:\n" + + " DECLARE GLOBAL TEMPORARY TABLE temptb1 \n" + + " LIKE department \n" + + " WITH REPLACE\n" + + " ON COMMIT PRESERVE ROWS\n" + + " IN usertemp1"); + + #sql {DECLARE GLOBAL TEMPORARY TABLE temptb1 + LIKE department + WITH REPLACE + ON COMMIT PRESERVE ROWS + IN usertemp1}; + + populateTempTable(); + showTableContents(); + + } // recreateTempTableWithLogging + + // Show that the temp table still exists after the commit. All the + // rows will be deleted because the temp table was declared, by default, + // with "on commit delete rows". If "on commit preserve rows" was used, + // then the rows would have remained. + static void showAfterCommit() throws Exception + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENTS:\n" + + " COMMIT\n" + + "TO SHOW THAT THE TEMP TABLE EXISTS AFTER A COMMIT BUT WITH\n" + + "ALL ROWS DELETED\n" + + "\n Perform:\n" + + " COMMIT\n"); + + + #sql {COMMIT}; + + showTableContents(); + + } // showAftercommit + + // Use cursors to access each row of the declared temp table and then print + // each row. This function assumes that the declared temp table exists. + // This access is the same as accessing a normal table except the qualifier, + // "session", is required in the table name. + static void showTableContents() + { + // Variables to store data from the department table + String deptno = ""; + String deptname = ""; + String mgrno = ""; + String admrdept = ""; + String location = ""; + + TbTemp_Cursor0 cur0; + + System.out.println("\n SELECT * FROM session.temptb1\n"); + System.out.println( + " DEPT# DEPTNAME MGRNO ADMRDEPT LOCATION\n"+ + " ----- ---------------------------- ------ -------- --------"); + try + { + #sql cur0 = {SELECT * FROM session.temptb1}; + + while (true) + { + #sql {FETCH :cur0 INTO :deptno, :deptname, :mgrno, :admrdept, :location}; + + if (cur0.endFetch()) + { + break; + } + + System.out.print(" "); + + try + { + System.out.print(Data.format(deptno, 5) + " "); + } + catch(Exception e) + { + System.out.print(" - "); + } + + try + { + System.out.print(Data.format(deptname, 28) + " "); + } + catch(Exception e) + { + System.out.print(" - "); + } + + try + { + System.out.print(Data.format(mgrno, 6) + " "); + } + catch(Exception e) + { + System.out.print(" - "); + } + + try + { + System.out.print(Data.format(admrdept, 8) + " "); + } + catch(Exception e) + { + System.out.print(" - "); + } + + try + { + System.out.println(Data.format(location, 8)); + } + catch(Exception e) + { + System.out.println(" -"); + } + } // while + + cur0.close(); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + } // showTableContents + + // create Index command can be used on temporary tables to improve + // the performance of queries + static void createIndex() throws Exception + { + System.out.print( + "\n-----------------------------------------------------------"); + System.out.print( + "\n Indexes can be created for temporary tables. Indexing a table\n" + + " optimizes query performance \n"); + + System.out.print( + "\n CREATE INDEX session.tb1ind \n" + + " ON session.temptb1 (deptno DESC) \n" + + " DISALLOW REVERSE SCANS \n"); + + #sql {CREATE INDEX session.tb1ind + ON session.temptb1(deptno DESC) + DISALLOW REVERSE SCANS}; + + System.out.print( + "\n Following clauses in create index are not supported \n" + + " for temporary tables:\n" + + " SPECIFICATION ONLY\n" + + " CLUSTER\n" + + " EXTEND USING\n" + + " Option SHRLEVEL will have no effect when creating indexes \n" + + " on DGTTs and will be ignored \n"); + + System.out.print( + "\n Indexes can be dropped by issuing DROP INDEX statement, \n" + + " or they will be implicitly dropped when the underlying temp \n" + + " table is dropped.\n"); + + } // createIndex + + // Issue a SELECT * command on the temporary table created and use + // ResultSetMetaData to obtain description of the temporary table + static void describeTemporaryTable(Connection conn) throws Exception + { + System.out.print( + "\n-----------------------------------------------------------"); + System.out.print( + "\n Use ResultSetMetaData to get temporary table description\n" + + "\n Perform:" + + "\n SELECT * FROM session.temptb1\n" + + "\n Use ResultSetMetaData to get information about structure of" + + "\n the temporary table\n"); + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM session.temptb1"); + ResultSetMetaData rsmd = rs.getMetaData(); + int numberOfColumns = rsmd.getColumnCount(); + + String colName = ""; + String schemaName = ""; + String colType = ""; + int colLength, colScale, colNull; + + System.out.print( + "\n Column Type Type \n" + + " name schema name Length Scale Nulls\n"+ + " -------------------- -------- -------------- ------ ----- -----"); + + for (int i = 1; i <= numberOfColumns; i++) + { + colName = rsmd.getColumnName(i); + schemaName = rsmd.getSchemaName(i); + colType = rsmd.getColumnTypeName(i); + colLength = rsmd.getColumnDisplaySize(i); + colScale = rsmd.getScale(i); + colNull = rsmd.isNullable(i); + + System.out.print( + "\n " + Data.format(colName, 20) + " " + + Data.format(schemaName, 8) + " " + + Data.format(colType, 14) + " " + + Data.format(colLength, 6) + " " + + Data.format(colScale, 5) + " "); + + if (colNull == rsmd.columnNullable) + System.out.print("Yes"); + else if (colNull == rsmd.columnNoNulls) + System.out.print("No"); + else + System.out.print("Unknown"); + } + System.out.println(); + + rs.close(); + + } // describeTemporaryTable +} // TbTemp diff --git a/java/sqlj/TbTrig.sqlj b/java/sqlj/TbTrig.sqlj new file mode 100644 index 0000000..22b6564 --- /dev/null +++ b/java/sqlj/TbTrig.sqlj @@ -0,0 +1,1008 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbTrig.sqlj +// +// SAMPLE: How to use triggers +// +// SQL Statements USED: +// CREATE TABLE +// CREATE TRIGGER +// DROP TABLE +// DROP TRIGGER +// SELECT +// INSERT +// UPDATE +// DELETE +// COMMIT +// ROLLBACK +// +// JAVA 2 CLASSES USED: +// Statement +// +// Classes used from Util.sqlj are: +// Db +// Data +// SqljException +// +// OUTPUT FILE: TbTrig.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator TbTrig_Cursor1(int, String, int, String, Integer, + double, Double); + +class TbTrig +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO USE TRIGGERS."); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + beforeInsertTriggerUse(); + afterInsertTriggerUse( ctx.getConnection() ); + beforeDeleteTriggerUse(); + beforeUpdateTriggerUse( ctx.getConnection() ); + afterUpdateTriggerUse( ctx.getConnection() ); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + // helping function + static void staffTbContentDisplay() + { + try + { + int id = 0; + int dept = 0; + double salary = 0.0; + String name = null; + String job = null; + Integer years = new Integer(0); + Double comm = new Double(0.0); + TbTrig_Cursor1 c1; + + System.out.println(); + System.out.println(" SELECT * FROM staff WHERE id <= 50"); + System.out.println( + " ID NAME DEPT JOB YEARS SALARY COMM\n" + + " --- ------- ---- ----- ----- -------- --------"); + + #sql c1 = {SELECT * FROM staff WHERE id <= 50}; + + #sql {FETCH :c1 INTO :id, :name, :dept, :job, :years, :salary, :comm}; + + while (!c1.endFetch()) + { + System.out.print(" " + Data.format(id,3) + + " " + Data.format(name,7) + + " " + Data.format(dept,4)); + if (job != null) + { + System.out.print(" " + Data.format(job,5)); + } + else + { + System.out.print(" -"); + } + if (years != null) + { + System.out.print(" " + Data.format(years,5)); + } + else + { + System.out.print(" -"); + } + System.out.print(" " + Data.format(salary,7,2)); + if (comm != null) + { + System.out.print(" " + Data.format(comm,7,2)); + } + else + { + System.out.print(" -"); + } + System.out.println(); + + #sql {FETCH :c1 INTO :id, :name, :dept, :job, :years, :salary, :comm}; + } + c1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // staffTbContentDisplay + + // helping function + static void staffStatsTbCreate(Connection con) + { + try + { + System.out.println(); + System.out.println(" CREATE TABLE staff_stats(nbemp SMALLINT)"); + + #sql {CREATE TABLE staff_stats(nbemp SMALLINT)}; + + System.out.println(); + System.out.println( + " INSERT INTO staff_stats VALUES(SELECT COUNT(*) FROM staff)"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO staff_stats VALUES(SELECT COUNT(*) FROM staff)"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // staffStatsTbCreate + + // helping function + static void staffStatsTbContentDisplay(Connection con) + { + try + { + System.out.println(); + System.out.println(" SELECT nbemp FROM staff_stats"); + System.out.println(" NBEMP\n" + + " -----"); + + Statement stmt = con.createStatement(); + ResultSet rs2 = stmt.executeQuery("SELECT * FROM staff_stats"); + rs2.next(); + + System.out.println(" " + Data.format(rs2.getShort("nbemp"),5)); + rs2.close(); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // staffStatsTbContentDisplay + + // helping function + static void staffStatsTbDrop() + { + try + { + System.out.println(); + System.out.println(" DROP TABLE staff_stats"); + + #sql {DROP TABLE staff_stats}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // staffStatsTbDrop + + // helping function + static void salaryStatusTbCreate(Connection con) + { + try + { + System.out.println(); + System.out.println( + " CREATE TABLE salary_status(emp_name VARCHAR(9),\n" + + " sal DECIMAL(7, 2),\n" + + " status CHAR(15))"); + + #sql {CREATE TABLE salary_status(emp_name VARCHAR(9), + sal DECIMAL(7, 2), + status CHAR(15))}; + + System.out.println(); + System.out.println(" INSERT INTO salary_status\n" + + " SELECT name, salary, 'Not Defined'\n" + + " FROM staff\n" + + " WHERE id <= 50"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("INSERT INTO salary_status " + + " SELECT name, salary, 'Not Defined' " + + " FROM staff " + + " WHERE id <= 50"); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // salaryStatusTbCreate + + // helping function + static void salaryStatusTbContentDisplay(Connection con) + { + try + { + System.out.println(); + System.out.println(" SELECT * FROM salary_status"); + System.out.println(" EMP_NAME SALARY STATUS\n" + + " ---------- -------- ----------------"); + + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM salary_status"); + + while (rs.next()) + { + System.out.println( + " " + Data.format(rs.getString("emp_name"), 10) + + " " + Data.format(rs.getDouble("sal"), 7, 2) + + " " + Data.format(rs.getString("status"), 15)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // salaryStatusTbContentDisplay + + // helping function + static void salaryStatusTbDrop() + { + try + { + System.out.println(); + System.out.println(" DROP TABLE salary_status"); + + #sql {DROP TABLE salary_status}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // salaryStatusTbDrop + + // helping function + static void salaryHistoryTbCreate() + { + try + { + System.out.println(); + System.out.println( + " CREATE TABLE salary_history(employee_name VARCHAR(9),\n" + + " salary_record DECIMAL(7, 2),\n" + + " change_date DATE)"); + + #sql {CREATE TABLE salary_history(employee_name VARCHAR(9), + salary_record DECIMAL(7, 2), + change_date DATE)}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // salaryHistoryTbCreate + + // helping function + static void salaryHistoryTbContentDisplay(Connection con) + { + try + { + System.out.println(); + System.out.println(" SELECT * FROM salary_history"); + System.out.println(" EMPLOYEE_NAME SALARY_RECORD CHANGE_DATE\n" + + " -------------- -------------- -----------"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM salary_history"); + + while (rs.next()) + { + System.out.println( + " " + Data.format(rs.getString("employee_name"),14) + + " " + Data.format(rs.getDouble("salary_record"),13,2) + + " " + rs.getDate("change_date")); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // salaryHistoryTbContentDisplay + + // helping function + static void salaryHistoryTbDrop() + { + try + { + System.out.println(); + System.out.println(" DROP TABLE salary_history"); + + #sql {DROP TABLE salary_history}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // salaryHistoryTbDrop + + static void beforeInsertTriggerUse() + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " INSERT\n" + + " ROLLBACK\n" + + " DROP TRIGGER\n" + + "TO SHOW A 'BEFORE INSERT' TRIGGER."); + + // display the initial content of the 'staff' table + staffTbContentDisplay(); + + // create a 'BEFORE INSERT' trigger + try + { + System.out.println(); + System.out.println( + " CREATE TRIGGER min_sal\n" + + " NO CASCADE BEFORE INSERT\n" + + " ON staff\n" + + " REFERENCING NEW AS newstaff\n" + + " FOR EACH ROW \n" + + " BEGIN ATOMIC\n" + + " SET newstaff.salary =\n" + + " CASE\n" + + " WHEN newstaff.job = 'Mgr' AND\n" + + " newstaff.salary < 17000.00\n" + + " THEN 17000.00\n" + + " WHEN newstaff.job = 'Sales' AND\n" + + " newstaff.salary < 14000.00\n" + + " THEN 14000.00\n" + + " WHEN newstaff.job = 'Clerk' AND\n" + + " newstaff.salary < 10000.00\n" + + " THEN 10000.00\n" + + " ELSE newstaff.salary\n" + + " END;\n" + + " END"); + + #sql {CREATE TRIGGER min_sal + NO CASCADE BEFORE INSERT + ON staff + REFERENCING NEW AS newstaff + FOR EACH ROW + BEGIN ATOMIC + SET newstaff.salary = + CASE + WHEN newstaff.job = 'Mgr' AND + newstaff.salary < 17000.00 + THEN 17000.00 + WHEN newstaff.job = 'Sales' AND + newstaff.salary < 14000.00 + THEN 14000.00 + WHEN newstaff.job = 'Clerk' AND + newstaff.salary < 10000.00 + THEN 10000.00 + ELSE newstaff.salary + END; + END}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // insert table data using values + try + { + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " INSERT INTO staff(id, name, dept, job, salary)\n" + + " VALUES(25, 'Pearce', 38, 'Clerk', 7217.50),\n" + + " (35, 'Hachey', 38, 'Mgr', 21270.00),\n" + + " (45, 'Wagland', 38, 'Sales', 11575.00)"); + + #sql {INSERT INTO staff(id, name, dept, job, salary) + VALUES(25, 'Pearce', 38, 'Clerk', 7217.50), + (35, 'Hachey', 38, 'Mgr', 21270.00), + (45, 'Wagland', 38, 'Sales', 11575.00)}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction and then drop the trigger + try + { + System.out.println(); + System.out.println(" Roll back the transaction."); + + #sql {ROLLBACK}; + + System.out.println(); + System.out.println(" DROP TRIGGER min_sal"); + + #sql {DROP TRIGGER min_sal}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // beforeInsertTriggerUse + + static void afterInsertTriggerUse(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " INSERT\n" + + " ROLLBACK\n" + + " DROP TRIGGER\n" + + "TO SHOW AN 'AFTER INSERT' TRIGGER."); + + // create a table called 'staff_stats' + staffStatsTbCreate(con); + + // display the content of the 'staff_stats' table + staffStatsTbContentDisplay(con); + + // create an 'AFTER INSERT' trigger + try + { + System.out.println(); + System.out.println(" CREATE TRIGGER new_hire\n" + + " AFTER INSERT\n" + + " ON staff\n" + + " FOR EACH ROW \n" + + " BEGIN ATOMIC\n" + + " UPDATE staff_stats\n" + + " SET nbemp = nbemp + 1;\n" + + " END"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("CREATE TRIGGER new_hire " + + " AFTER INSERT " + + " ON staff " + + " FOR EACH ROW " + + " BEGIN ATOMIC " + + " UPDATE staff_stats " + + " SET nbemp = nbemp + 1; " + + " END"); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // insert table data using values + try + { + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " INSERT INTO staff(id, name, dept, job, salary)\n" + + " VALUES(25, 'Pearce', 38, 'Clerk', 7217.50),\n" + + " (35, 'Hachey', 38, 'Mgr', 21270.00),\n" + + " (45, 'Wagland', 38, 'Sales', 11575.00)"); + + #sql {INSERT INTO staff(id, name, dept, job, salary) + VALUES(25, 'Pearce', 38, 'Clerk', 7217.50), + (35, 'Hachey', 38, 'Mgr', 21270.00), + (45, 'Wagland', 38, 'Sales', 11575.00)}; + + // display the content of the 'staff_stats' table + staffStatsTbContentDisplay(con); + + // roll back the transaction + System.out.println(); + System.out.println(" Roll back the transaction."); + + #sql {ROLLBACK}; + + // drop the trigger + System.out.println(); + System.out.println(" DROP TRIGGER new_hire"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TRIGGER new_hire"); + stmt.close(); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the 'staff_stats' table + staffStatsTbDrop(); + + } // afterInsertTriggerUse + + static void beforeDeleteTriggerUse() + { + String sqlstate; + String sqlerrmsg; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " DELETE\n" + + " ROLLBACK\n" + + " DROP TRIGGER\n" + + "TO SHOW A 'BEFORE DELETE' TRIGGER."); + + // display the initial content of the 'staff' table + staffTbContentDisplay(); + + // create a 'BEFORE DELETE' trigger + try + { + System.out.println(); + System.out.println(" CREATE TRIGGER do_not_delete_sales\n" + + " NO CASCADE BEFORE DELETE\n" + + " ON staff\n" + + " REFERENCING OLD AS oldstaff\n" + + " FOR EACH ROW \n" + + " WHEN (oldstaff.job = 'Sales')\n" + + " BEGIN ATOMIC\n" + + " SIGNAL SQLSTATE '75000' " + + "('Sales cannot be deleted now.');\n" + + " END"); + + #sql {CREATE TRIGGER do_not_delete_sales + NO CASCADE BEFORE DELETE + ON staff + REFERENCING OLD AS oldstaff + FOR EACH ROW + WHEN(oldstaff.job = 'Sales') + BEGIN ATOMIC + SIGNAL SQLSTATE '75000' ('Sales cannot be deleted now.'); + END}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // delete data from the 'staff' table + try + { + System.out.println(); + System.out.println(" Invoke the statement:\n" + + " DELETE FROM staff WHERE id <= 50"); + + #sql {DELETE FROM staff WHERE id <= 50}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + // display the final content of the 'staff' table + staffTbContentDisplay(); + + // roll back the transaction and then drop the trigger + try + { + System.out.println(); + System.out.println(" Roll back the transaction."); + + #sql {ROLLBACK}; + + System.out.println(); + System.out.println(" DROP TRIGGER do_not_delete_sales"); + + #sql {DROP TRIGGER do_not_delete_sales}; + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // beforeDeleteTriggerUse + + static void beforeUpdateTriggerUse(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " UPDATE\n" + + " ROLLBACK\n" + + " DROP TRIGGER\n" + + "TO SHOW A 'BEFORE UPDATE' TRIGGER."); + + // create a table called salary_status + salaryStatusTbCreate(con); + + // display the content of the 'salary_status' table + salaryStatusTbContentDisplay(con); + + // create a 'BEFORE UPDATE' trigger + try + { + System.out.println(); + System.out.println( + " CREATE TRIGGER salary_status\n" + + " NO CASCADE BEFORE UPDATE OF sal\n" + + " ON salary_status\n" + + " REFERENCING NEW AS new OLD AS old\n" + + " FOR EACH ROW \n" + + " BEGIN ATOMIC\n" + + " SET new.status =\n" + + " CASE\n" + + " WHEN new.sal < old.sal\n" + + " THEN 'Decreasing'\n" + + " WHEN new.sal > old.sal\n" + + " THEN 'Increasing'\n" + + " END;\n" + + " END"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("CREATE TRIGGER sal_status " + + " NO CASCADE BEFORE UPDATE OF sal " + + " ON salary_status " + + " REFERENCING NEW AS new OLD AS old " + + " FOR EACH ROW " + + " BEGIN ATOMIC " + + " SET new.status = " + + " CASE " + + " WHEN new.sal < old.sal " + + " THEN 'Decreasing' " + + " WHEN new.sal > old.sal " + + " THEN 'Increasing' " + + " END; " + + " END"); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // update data in table 'salary_status' + try + { + System.out.println(); + System.out.println(" Invoke the statement:\n" + + " UPDATE salary_status SET sal = 18000.00"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("UPDATE salary_status SET sal = 18000.00"); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the content of the 'salary_status' table + salaryStatusTbContentDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" Roll back the transaction."); + + #sql {ROLLBACK}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the trigger + try + { + System.out.println(); + System.out.println(" DROP TRIGGER sal_status"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("DROP TRIGGER sal_status"); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop salary_status table + salaryStatusTbDrop(); + + } // beforeUpdateTriggerUse + + static void afterUpdateTriggerUse(Connection con) + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " CREATE TRIGGER\n" + + " COMMIT\n" + + " UPDATE\n" + + " DROP TRIGGER\n" + + "TO SHOW AN 'AFTER UPDATE' TRIGGER."); + + // create a table called 'salary_history' + salaryHistoryTbCreate(); + + // display the content of the 'salary_history' table + salaryHistoryTbContentDisplay(con); + + try + { + System.out.println(); + System.out.println(" CREATE TRIGGER sal_history\n" + + " AFTER UPDATE OF salary\n" + + " ON staff\n" + + " REFERENCING NEW AS newstaff\n" + + " FOR EACH ROW \n" + + " BEGIN ATOMIC\n" + + " INSERT INTO salary_history\n" + + " VALUES(newstaff.name,\n" + + " newstaff.salary,\n" + + " CURRENT DATE);\n" + + " END"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate("CREATE TRIGGER sal_history " + + " AFTER UPDATE OF salary " + + " ON staff " + + " REFERENCING NEW AS newstaff " + + " FOR EACH ROW " + + " BEGIN ATOMIC " + + " INSERT INTO salary_history " + + " VALUES(newstaff.name, " + + " newstaff.salary, " + + " CURRENT DATE); " + + " END"); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // update table data + try + { + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 20000.00 WHERE name = 'Sanders'"); + + #sql {UPDATE staff SET salary = 20000.00 WHERE name = 'Sanders'}; + + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 21000.00 WHERE name = 'Sanders'"); + + #sql {UPDATE staff SET salary = 21000.00 WHERE name = 'Sanders'}; + + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 23000.00 WHERE name = 'Sanders'"); + + #sql {UPDATE staff SET salary = 23000.00 WHERE name = 'Sanders'}; + + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 20000.00 WHERE name = 'Hanes'"); + + #sql {UPDATE staff SET salary = 20000.00 WHERE name = 'Hanes'}; + + System.out.println(); + System.out.println( + " Invoke the statement:\n" + + " UPDATE staff SET salary = 21000.00 WHERE name = 'Hanes'"); + + #sql {UPDATE staff SET salary = 21000.00 WHERE name = 'Hanes'}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the content of the 'salary_history' table + salaryHistoryTbContentDisplay(con); + + // roll back the transaction + try + { + System.out.println(); + System.out.println(" Roll back the transaction."); + + #sql {ROLLBACK}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the trigger + try + { + System.out.println(); + System.out.println(" DROP TRIGGER sal_history"); + + Statement stmt = con.createStatement(); + stmt.execute("DROP TRIGGER sal_history"); + + System.out.println(); + System.out.println(" COMMIT"); + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // drop the 'salary_history' table + salaryHistoryTbDrop(); + + } // afterUpdateTriggerUse +} // TbTrig + diff --git a/java/sqlj/TbUMQT.sqlj b/java/sqlj/TbUMQT.sqlj new file mode 100644 index 0000000..e738f99 --- /dev/null +++ b/java/sqlj/TbUMQT.sqlj @@ -0,0 +1,872 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: TbUMQT.sqlj +// +// SAMPLE: How to use user materialized query tables (summary tables). +// +// This sample: +// 1. Query Table (UMQT) for the 'employee' table. +// 2. Shows the usage and update mechanisms for non-partitioned UMQTs. +// 3. Creates a new partitioned Maintained Materialized +// Query Table (MQT). +// 4. Shows the availability of partitioned MQTs during SET INTEGRITY +// after add/detach of a partition via ALTER ADD PARTITION and +// ALTER DETACH PARTITION. +// +// SQL Statements USED: +// ALTER TABLE +// CREATE TABLE +// EXECUTE IMMEDIATE +// DROP +// INSERT +// SELECT +// SET CURRENT +// SET INTEGRITY +// REFRESH TABLE +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// sqljException +// +// OUTPUT FILE: TbUMQT.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//************************************************************************** + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +// declare an iterator for result of the select command +#sql iterator TbUMQT_Cursor1(int); +#sql iterator TbUMQT_Cursor2(int, int); + +class TbUMQT +{ + public static void main(String argv[]) + { + DefaultContext ctx = null; + + try + { + Db db = new Db(argv); + + System.out.println( + "\nTHIS SAMPLE SHOWS THE USAGE OF USER MAINTAINED MATERIALIZED.\n" + + " QUERY TABLES(MQTs).\n"); + + // connect to the 'sample' database + ctx = db.getDefaultContext(); + + // create summary tables + createMQT(); + + // bring the summary tables out of check-pending state + setIntegrity(); + + // populate the base table and update contents of the summary tables + updateUserMQT(); + + // set registers to optimize query processing by routing queries to + // UMQT + setRegisters(); + + // issue a select statement that is routed to the summary tables + showTableContents( ctx.getConnection() ); + + // drop summary tables + dropTables(); + + // creates regular DMS tablespaces + dmsTspaceaceCreate(); + + // creates a partitioned table + partitionedTbCreate(); + + // create MQT on a paartitioned table + createMQT_on_Partitionedtb(); + + // create partitione MQT on a partitioned table + createPartitioned_MQT(); + + // drop tablespaces + tablespacesDrop(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + + } + } // main + + // Create summary tables. + static void createMQT() + { + Statement stmt; + + System.out.println( + "\n----------------------------------------------------------\n" + + "Creating UMQT on EMPLOYEE table...\n"); + try + { + System.out.println( + "USE THE SQL STATEMENT:\n" + + " CREATE SUMMARY TABLE \n" + + "To create a UMQT with deferred refresh\n\n" + + "Execute the statement:\n" + + "CREATE SUMMARY TABLE umqt_employee AS \n" + + " (SELECT workdept, count(*) AS no_of_employees \n" + + " FROM employee GROUP BY workdept)\n" + + " DATA INITIALLY DEFERRED REFRESH DEFERRED\n" + + " MAINTAINED BY USER\n"); + + #sql {CREATE SUMMARY TABLE umqt_employee AS + (SELECT workdept, count(*) AS no_of_employees + FROM employee GROUP BY workdept) + DATA INITIALLY DEFERRED REFRESH DEFERRED + MAINTAINED BY USER}; + + // commit the transaction + #sql {COMMIT}; + } + + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // creating a UMQT with immediate refresh option is not supported + try + { + System.out.println( + "\nCREATE SUMMARY TABLE to create a UMQT with immediate\n" + + "refresh option is not supported\n\n" + + "Execute the statement:\n" + + "CREATE SUMMARY TABLE aimdusr AS \n" + + " (SELECT workdept, count(*) AS no_of_employees \n" + + " FROM employee GROUP BY workdept)\n" + + " DATA INITIALLY DEFERRED REFRESH IMMEDIATE\n" + + " MAINTAINED BY USER\n"); + + #sql {CREATE SUMMARY TABLE aimdusr AS + (SELECT workdept, count(*) AS no_of_employees + FROM employee GROUP BY workdept) + DATA INITIALLY DEFERRED REFRESH IMMEDIATE + MAINTAINED BY USER}; + + // commit the transaction + System.out.println("\n COMMIT"); + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handleExpectedErr(); + } + } // createMQT + + // Bring the summary tables out of check-pending state. + static void setIntegrity() + { + System.out.println( + "\n-----------------------------------------------------------"); + System.out.println( + "USE THE SQL STATEMENT:\n" + + " SET INTEGRITY \n" + + "To bring the MQTs out of check pending state\n"); + try + { + System.out.println( + "Execute the statement:\n" + + "SET INTEGRITY FOR umqt_employee ALL IMMEDIATE UNCHECKED"); + + #sql {SET INTEGRITY FOR umqt_employee ALL IMMEDIATE UNCHECKED}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // setIntegrity + + // Populate the base table and update the contents of the summary tables. + static void updateUserMQT() + { + System.out.println( + "\n-----------------------------------------------------------\n" + + "\nUMQT_EMPLOYEE must be updated manually by the user\n\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "To update the UMQT\n "); + try + { + System.out.println( + "Execute the statement:" + + "\nINSERT INTO umqt_employee \n" + + " (SELECT workdept, count(*) AS no_of_employees\n" + + " FROM employee GROUP BY workdept)"); + + #sql { + INSERT INTO umqt_employee + (SELECT workdept, count(*) AS no_of_employees + FROM employee GROUP BY workdept)}; + + // commit the transaction + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + } // updateUserMQT + + // Set registers to optimize query processing by routing queries to UMQT. + static void setRegisters() + { + // the CURRENT REFRESH AGE special register must be set to a value other + // than zero for the specified table types to be considered when + // optimizing the processing of dynamic SQL queries. + + System.out.println( + "\n-----------------------------------------------------------\n" + + "The following registers must be set to route queries to UMQT"); + + try + { + System.out.println( + "\n SET CURRENT REFRESH AGE ANY\n" + + "\nIndicates that any table types specified by CURRENT MAINTAINED" + + "\nTABLE TYPES FOR OPTIMIZATION, and MQTs defined with REFRESH \n" + + "IMMEDIATE option, can be used to optimize the \n" + + "processing of a query. \n\n"); + + #sql {SET CURRENT REFRESH AGE ANY}; + + System.out.println( + " SET CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION USER \n\n" + + "Specifies that user-maintained refresh-deferred materialized \n" + + "query tables can be considered to optimize the processing of \n" + + "dynamic SQL queries. "); + + #sql {SET CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION USER}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // setRegisters + + // Issue a select statement that is routed to the summary tables. + static void showTableContents(Connection con) + { + String workDept = null; + int countWorkDept = 0; + + System.out.println( + "\n-----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " SELECT\n" + + "On EMPLOYEE table. This is routed to the UMQT umqt_employee\n"); + + try + { + Statement stmt = con.createStatement(); + ResultSet rs; + + System.out.println( + "Execute the statement:\n" + + "SELECT workdept, count(*) AS no_of_employees \n" + + " FROM employee GROUP BY workdept\n"); + System.out.println( + " DEPT CODE NO. OF EMPLOYEES \n" + + " ---------- ----------------"); + + // perform a SELECT against the "employee" table in the sample database + rs = stmt.executeQuery( + "SELECT workdept, count(*) AS no_of_employees " + + "FROM employee GROUP BY workdept"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + workDept = rs.getString("workdept"); + countWorkDept = rs.getInt("no_of_employees"); + + System.out.println( + " " + + Data.format(workDept, 7) + " " + + Data.format(countWorkDept, 10)); + } + rs.close(); + + System.out.println( + "\nA SELECT query on umqt_employee yields similar results\n\n" + + " SELECT * FROM umqt_employee \n"); + System.out.println( + " DEPT CODE NO. OF EMPLOYEES \n" + + " ---------- ----------------\n"); + + // perform a SELECT against umqt_employee query table + rs = stmt.executeQuery(" SELECT * FROM umqt_employee"); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + workDept = rs.getString("workdept"); + countWorkDept = rs.getInt("no_of_employees"); + + System.out.println( + " " + + Data.format(workDept, 7) + " " + + Data.format(countWorkDept, 10)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // showTableContents + + // drop tables. + static void dropTables() + { + System.out.println( + "\nDropping tables...\n\n" + + "USE THE SQL STATEMENT:\n" + + " DROP\n" + + "To drop the UMQT umqt_employee\n"); + + try + { + System.out.println( + "Execute the statement:\n" + + " DROP TABLE umqt_employee"); + #sql {DROP TABLE umqt_employee}; + + // commit the transaction + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // dropTables + + // creates regular DMS tablespaces. + static void dmsTspaceaceCreate() throws SQLException + { + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " CREATE REGULAR TABLESPACE \n" + + "TO CREATE A REGULAR DMS TABLESPACES \n" + + "\nExecute the statement:\n" + + " CREATE REGULAR TABLESPACE tspace\n" + + " MANAGED BY DATABASE \n" + + " USING (FILE 'tspace_cont.dat' 1000)"); + + // create regular DMS table space tspace + #sql {CREATE REGULAR TABLESPACE tspace + MANAGED BY DATABASE USING (FILE 'tspace_cont.dat' 10000)}; + + System.out.println( + "\nExecute the statement:\n" + + " CREATE REGULAR TABLESPACE tspace1\n" + + " MANAGED BY DATABASE \n" + + " USING (FILE 'tspace1_cont1.dat' 1000)"); + + // create regular DMS table space tspace1 + #sql {CREATE REGULAR TABLESPACE tspace1 + MANAGED BY DATABASE USING (FILE 'tspace1_cont1.dat' 10000)}; + + System.out.println( + "\nExecute the statement:\n" + + " CREATE REGULAR TABLESPACE tspace2\n" + + " MANAGED BY DATABASE \n" + + " USING (FILE 'tspace2_cont2.dat' 1000)"); + + // create regular DMS table space tspace2 + #sql {CREATE REGULAR TABLESPACE tspace2 + MANAGED BY DATABASE USING (FILE 'tspace2_cont2.dat' 10000)}; + + System.out.println( + "\nExecute the statement:\n" + + " CREATE REGULAR TABLESPACE tspace3\n" + + " MANAGED BY DATABASE \n" + + " USING (FILE 'tspace3_cont3.dat' 1000)"); + + // create regular DMS table space tspace3 + #sql {CREATE REGULAR TABLESPACE tspace3 + MANAGED BY DATABASE USING (FILE 'tspace3_cont3.dat' 10000)}; + + System.out.println( + "\n-----------------------------------------------------------"); + #sql {COMMIT}; + + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // dmsTspaceaceCreate + + // create a partitioned table in regular DMS tablespaces i.e; 'part1' is + // placed in 'tspace1', 'part2' is placed in 'tspace2' and + // 'part3' in 'tspace3' and inserts data into it. + static void partitionedTbCreate() throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n" + + "\nExecute the statement:\n" + + " CREATE TABLE fact_table (max SMALLINT NOT NULL,\n" + + " CONSTRAINT CC CHECK (max>0))\n" + + " PARTITION BY RANGE (max)\n "+ + " (PART part1 STARTING FROM (1) ENDING (3) IN tspace1,\n" + + " PART part2 STARTING FROM (4) ENDING (6) IN tspace2,\n" + + " PART part3 STARTING FROM (7) ENDING (9) IN tspace3)"); + + #sql {CREATE TABLE fact_table + (max SMALLINT NOT NULL, CONSTRAINT CC CHECK (max>0)) + PARTITION BY RANGE (max) + (PART part1 STARTING FROM (1) ENDING (3) IN tspace1, + PART part2 STARTING FROM (4) ENDING (6) IN tspace2, + PART part3 STARTING FROM (7) ENDING (9) IN tspace3)}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " INSERT INTO \n" + + "TO INSERT DATA IN A TABLE \n" + + "\nExecute the statement:\n" + + " INSERT INTO fact_table VALUES (1), (2), (3),\n" + + " (4), (5), (6),\n" + + " (7), (8), (9)"); + + // insert data into the table + #sql {INSERT INTO fact_table VALUES (1), (2), (3), (4), + (5), (6), (7), (8), (9)}; + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + } // partitionedTbCreate + + // creates MQT on a partitioned table. Performs SET INTEGRITY on MQT to + // bring MQT out of check pending state and to get changes reflected. + static void createMQT_on_Partitionedtb() throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " CREATE TABLE \n" + + "TO CREATE A TABLE \n" + + "\nExecute the statement:\n" + + " CREATE TABLE mqt_fact_table AS\n" + + " (SELECT max, COUNT (*) AS no_of_rows FROM fact_table)\n" + + " GROUP BY max) DATA INITIALLY DEFERRED REFRESH IMMEDIATE"); + + #sql {CREATE TABLE mqt_fact_table AS + (SELECT max, COUNT (*) AS no_of_rows FROM fact_table GROUP BY max) + DATA INITIALLY DEFERRED REFRESH IMMEDIATE}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:" + + "\n SET INTEGRITY " + + "\nTO PERFORM SET INTEGRITY ON A TABLE\n" + + "\nExecute the statement:" + + "\n SET INTEGRITY FOR mqt_fact_table IMMEDIATE CHECKED"); + + #sql {SET INTEGRITY FOR mqt_fact_table IMMEDIATE CHECKED}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the contents of a table. + displaytbData(); + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " DROP\n" + + "TO DROP A TABLE.\n" + + + "\nExecute the statements:" + + "\n DROP TABLE mqt_fact_table" + + "\n DROP TABLE fact_table"); + + #sql {DROP TABLE mqt_fact_table}; + + #sql {COMMIT}; + + #sql {DROP TABLE fact_table}; + + #sql {COMMIT}; + } // createMQT_on_Partitionedtb + + // creates a partitioned MQT on a partitioned table whose range is less + // then that of the base table. Partition is added to MQT and + // REFRESH TABLE is performed on MQT to bring MQT out of check pending + // state and to get changes reflected to MQT. + static void createPartitioned_MQT() throws SQLException + { + // creates a partitioned table + partitionedTbCreate(); + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " CREATE\n" + + "TO CREATE A PARTITIONED MQT ON A PARTITIONED TABLE .\n" + + + "\nExecute the statement:" + + "\n CREATE TABLE mqt_fact_table AS" + + "\n (SELECT max, COUNT (*) AS no_of_rows FROM fact_table GROUP BY max)" + + "\n DATA INITIALLY DEFERRED REFRESH IMMEDIATE\n" + + " PARTITION BY RANGE (max)\n" + + " (STARTING 0 ENDING 6 EVERY 3)\n"); + + #sql {CREATE TABLE mqt_fact_table AS + (SELECT max, COUNT (*) AS no_of_rows FROM fact_table GROUP BY max) + DATA INITIALLY DEFERRED REFRESH IMMEDIATE + PARTITION BY RANGE (max) + (STARTING 0 ENDING 6 EVERY 3)}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLE \n" + + "TO ADD PARTITION TO MQT\n" + + "\nExecute the statement:" + + "\n ALTER TABLE mqt_fact_table ADD PARTITION part4 STARTING (7) ENDING (9)"); + + #sql {ALTER TABLE mqt_fact_table ADD PARTITION part4 + STARTING (7) ENDING (9)}; + + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " REFRESH\n" + + "TO REFRESH TABLE\n" + + "\nExecute the statement:" + + "\n REFRESH TABLE mqt_fact_table"); + + #sql {REFRESH TABLE mqt_fact_table}; + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + // display the contents of a table. + displaytbData(); + + // detach partition from a table. + detach_Partitiontb(); + } // createPartitioned_MQT + + // detach a partition from 'fact_table'. + // SET INTEGRITY is performed on MQT to bring it out of + // check pending state. Later, a partition is detached form + // 'mqt_fact_table'. REFRESH TABLE is performed on MQT to bring it out of + // check pending state and to get changes reflected into MQT. + static void detach_Partitiontb() throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " ALTER TABLE \n" + + "TO DETACH A PARTITION FROM A TABLE\n" + + + "\nExecute the statement\n" + + " ALTER TABLE fact_table DETACH PARTITION part2 INTO TABLE detach_part1"); + + #sql {ALTER TABLE fact_table DETACH PARTITION part2 INTO TABLE detach_part1}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + System.out.println( + "\nUSE THE SQL STATEMENT:" + + "\n SET INTEGRITY \n" + + "TO BRING THE MQTs OUT OF CHECK PENDING STATE\n" + + + "\nExecute the statement:" + + "\n SET INTEGRITY FOR mqt_fact_table IMMEDIATE CHECKED"); + + #sql {SET INTEGRITY FOR mqt_fact_table IMMEDIATE CHECKED}; + #sql {COMMIT}; + + System.out.println( + "\nExecute the statement:\n" + + " ALTER TABLE mqt_fact_table DETACH PARTITION part2 INTO TABLE detach_part2"); + + #sql {ALTER TABLE mqt_fact_table DETACH PARTITION part2 INTO TABLE detach_part2}; + + #sql {COMMIT}; + + System.out.println( + "\nUSE THE SQL STATEMENT:" + + "\n REFRESH\n" + + "TO GET CHANGES REFLECTED\n" + + + "\nExecute the statement:" + + "\n REFRESH TABLE mqt_fact_table"); + + #sql {REFRESH TABLE mqt_fact_table}; + + #sql {COMMIT}; + + // display the contents of a table. + displaytbData(); + } // detach_Partitiontb + + // display the contents of a table. + static void displaytbData() throws SQLException + { + System.out.println( + "\n-----------------------------------------------------------"); + try + { + int max = 0; + TbUMQT_Cursor1 cur1; + + System.out.println(); + System.out.println("SELECT * FROM fact_table"); + System.out.println( + " MAX\n" + + " ------"); + + #sql cur1 = {SELECT * FROM fact_table}; + + while (true) + { + #sql {FETCH :cur1 INTO :max}; + + if (cur1.endFetch()) + { + break; + } + + System.out.print(" " + Data.format(max, 3)); + System.out.println(); + } + + // close the cursor + cur1.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + + try + { + int max = 0; + int no_of_rows = 0; + TbUMQT_Cursor2 cur2; + + System.out.println(); + System.out.println("SELECT * FROM mqt_fact_table"); + System.out.println( + " MAX NO_OF_ROWS \n" + + " ------ -----------"); + + #sql cur2 = {SELECT * FROM mqt_fact_table}; + + while (true) + { + #sql {FETCH :cur2 INTO :max, :no_of_rows}; + if (cur2.endFetch()) + { + break; + } + + System.out.print(" " + Data.format(max, 3)+ + " " + Data.format(no_of_rows, 5)); + System.out.println(); + } + + // close the cursor + cur2.close(); + + System.out.println( + "\n-----------------------------------------------------------"); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // displaytbData + + // drop tables. + static void cleanup() throws SQLException + { + try + { + System.out.println( + "\nUSE THE SQL STATEMENT:\n" + + " DROP \n" + + "TO DROP THE TABLES \n" + + "\nExecute the statements:\n" + + " DROP TABLE fact_table\n" + + " DROP TABLE mqt_fact_table\n" + + " DROP TABLE detach_part1\n" + + " DROP TABLE detach_part2"); + + // drop the tables + #sql {DROP TABLE mqt_fact_table}; + #sql {DROP TABLE fact_table}; + #sql {DROP TABLE detach_part1}; + #sql {DROP TABLE detach_part2}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // cleanup + + // drop tablespaces. + static void tablespacesDrop() throws SQLException + { + // drop tables. + cleanup(); + + try + { + System.out.println( + "\n-----------------------------------------------------------" + + "\nUSE THE SQL STATEMENT:\n" + + " DROP \n" + + "TO DROP THE TABLESPACES \n" + + "\nExecute the statements:\n" + + " DROP TABLESPACE tspace\n" + + " DROP TABLESPACE tspace1\n" + + " DROP TABLESPACE tspace2\n" + + " DROP TABLESPACE tspace3"); + + // drop the tablespaces + #sql {DROP TABLESPACE tspace}; + #sql {DROP TABLESPACE tspace1}; + #sql {DROP TABLESPACE tspace2}; + #sql {DROP TABLESPACE tspace3}; + + #sql {COMMIT}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // tablespacesDrop +} // TbUMQT diff --git a/java/sqlj/UDFCreate.db2 b/java/sqlj/UDFCreate.db2 new file mode 100644 index 0000000..34d9aec --- /dev/null +++ b/java/sqlj/UDFCreate.db2 @@ -0,0 +1,68 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFCreate.db2 +-- +-- SAMPLE: How to catalog the UDFs contained in UDFsrv.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +CREATE FUNCTION scratchpadScUDF( ) +RETURNS INTEGER +EXTERNAL NAME 'UDFsrv!scratchpadScUDF' +FENCED +SCRATCHPAD 10 +FINAL CALL +VARIANT +NO SQL +PARAMETER STYLE DB2GENERAL +LANGUAGE JAVA +NO EXTERNAL ACTION@ + +CREATE FUNCTION scUDFReturningErr( DOUBLE, DOUBLE ) +RETURNS DOUBLE +EXTERNAL NAME 'UDFsrv!scUDFReturningErr' +FENCED +NOT VARIANT +NO SQL +PARAMETER STYLE DB2GENERAL +LANGUAGE JAVA +NO EXTERNAL ACTION@ + +CREATE FUNCTION tableUDF ( DOUBLE ) +RETURNS TABLE ( name VARCHAR(20), job VARCHAR(20), salary DOUBLE ) +EXTERNAL NAME 'UDFsrv!tableUDF' +LANGUAGE JAVA +PARAMETER STYLE DB2GENERAL +NOT DETERMINISTIC +FENCED +NO SQL +NO EXTERNAL ACTION +SCRATCHPAD 10 +FINAL CALL +DISALLOW PARALLEL +NO DBINFO@ + +connect reset@ diff --git a/java/sqlj/UDFDrop.db2 b/java/sqlj/UDFDrop.db2 new file mode 100644 index 0000000..353c1d7 --- /dev/null +++ b/java/sqlj/UDFDrop.db2 @@ -0,0 +1,38 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFDrop.db2 +-- +-- SAMPLE: How to uncatalog the UDFs contained in UDFsrv.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +DROP FUNCTION scratchpadScUDF@ + +DROP FUNCTION scUDFReturningErr@ + +DROP FUNCTION TableUDF@ + +connect reset@ diff --git a/java/sqlj/UDFcli.sqlj b/java/sqlj/UDFcli.sqlj new file mode 100644 index 0000000..5aee170 --- /dev/null +++ b/java/sqlj/UDFcli.sqlj @@ -0,0 +1,274 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFcli.sqlj +// +// SAMPLE: Call the UDFs in UDFsrv.java +// +// Parameter Style used in this program is "DB2GENERAL". +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Update makefile with a valid (userid, ) password and +// an available port number. +// 2. Compile the server source file UDFsrv.java (this will also +// compile the Utility file, Util.sqlj, erase the existing +// library/class files and copy the newly compiled class files, +// UDFsrv.class and Person.class from the current directory +// to the $(DB2PATH)\function directory): +// nmake/make UDFsrv +// 3. Compile the client source file UDFcli (this will also call +// the script 'udfcat' to create and catalog the UDFs): +// nmake/make UDFcli +// 4. Run the client UDFcli: +// java UDFcli +// +// II) If you don't have a compatible make/nmake program on your +// system, do the following: +// 1. Compile the server source file with the following command: +// javac UDFsrv.java +// 2. Erase the existing library/class files (if exists), +// UDFsrv.class and Person.class from the following path, +// $(DB2PATH)\function. +// 3. copy the class files, UDFsrv.class and Person.class from +// the current directory to the $(DB2PATH)\function. +// 4. Register/catalog the UDFs with: +// udfcat +// 5. Compile the utility file with the following command: +// sqlj Util.sqlj +// 6. Update bldsqljs and bldsqlj build files with a valid userid +// and password. +// 7. Build the SQLj UDFs with with: +// bldsqlj UDFcli +// 8. Run UDFcli with: +// java UDFcli +// +// SQL Statements USED: +// FETCH +// SELECT +// +// OUTPUT FILE: UDFcli.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; // JDBC classes +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator CursorForScratchpadScUDF(int, String, String); +#sql iterator CursorForScUDFReturningErr(String, String, double); +#sql iterator CursorForTableUDF(String, String, double); + +class UDFcli +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO WORK WITH UDFs."); + + // connect database + db.getDefaultContext(); + + demoExternalScratchpadScalarUDF(); + demoExternalScalarUDFReturningErr(); + demoExternalTableUDF(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + static void demoExternalScratchpadScalarUDF() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH SCRATCHPAD SCALAR UDF."); + + // use SCRATCHPAD scalar UDF + System.out.println(); + System.out.println(" Use the SCRATCHPAD scalar UDF:\n" + + " SELECT scratchpadScUDF(), name, job\n" + + " FROM staff\n" + + " WHERE name LIKE 'S%'"); + + CursorForScratchpadScUDF cur; + int counter = 0; + String name = null; + String job = null; + + #sql cur = {SELECT scratchpadScUDF(), name, job + FROM staff + WHERE name LIKE 'S%'}; + + System.out.println(" COUNTER NAME JOB\n" + + " ------- ---------- -------"); + + #sql {FETCH :cur INTO :counter, :name, :job}; + + while (!cur.endFetch()) + { + System.out.println(" " + Data.format(counter, 7) + + " " + Data.format(name, 10) + + " " + Data.format(job, 7)); + + #sql {FETCH :cur INTO :counter, :name, :job}; + } + cur.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demoExternalScratchpadScalarUDF + + static void demoExternalScalarUDFReturningErr() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH SCALAR UDF THAT RETURNS ERROR."); + + // use scalar UDF + System.out.println(); + System.out.println( + " Use the scalar UDF that returns error:\n" + + " SELECT name, job, scUDFReturningErr(salary, 0.00)\n"+ + " FROM staff\n" + + " WHERE name LIKE 'S%'"); + + CursorForScUDFReturningErr cur; + String name = null; + String job = null; + double comm = 0.0; + + #sql cur = {SELECT name, job, scUDFReturningErr(salary, 0.00) + FROM staff + WHERE name LIKE 'S%'}; + + System.out.println(" NAME JOB COMM\n" + + " ------- ---------- --------"); + + #sql {FETCH :cur INTO :name, :job, :comm}; + + while(!cur.endFetch()) + { + System.out.println(" " + Data.format(name, 7) + + " " + Data.format(job, 10) + + " " + Data.format(comm, 7, 2)); + + #sql {FETCH :cur INTO :name, :job, :comm}; + } + cur.close(); + } + catch (SQLException e) + { + if (e.getSQLState().equals("38999")) + { + System.out.println(); + System.out.println("--------- Expected Error ---------\n"); + } + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demoExternalscalarUDFReturningErr + + static void demoExternalTableUDF() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH TABLE UDF."); + + // use table UDF + System.out.println(); + System.out.println( + " Use the table UDF:\n" + + " SELECT udfTb.name, udfTb.job, udfTb.salary\n" + + " FROM TABLE(TableUDF(1.5)) AS udfTb"); + + CursorForTableUDF cur; + String name = null; + String job = null; + double newSalary = 0.0; + + #sql cur = {SELECT udfTb.name, udfTb.job, udfTb.salary + FROM TABLE(TableUDF(1.5)) AS udfTb}; + + System.out.println(" NAME JOB SALARY\n" + + " ------- ---------- --------"); + + #sql {FETCH :cur INTO :name, :job, :newSalary}; + + while (!cur.endFetch()) + { + System.out.println(" " + Data.format(name, 7) + + " " + Data.format(job, 10) + + " " + Data.format(newSalary, 7, 2)); + + #sql {FETCH :cur INTO :name, :job, :newSalary}; + } + cur.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demoExternalTableUDF +} + diff --git a/java/sqlj/UDFjCreate.db2 b/java/sqlj/UDFjCreate.db2 new file mode 100644 index 0000000..3116d74 --- /dev/null +++ b/java/sqlj/UDFjCreate.db2 @@ -0,0 +1,43 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFjCreate.db2 +-- +-- SAMPLE: How to catalog the UDFs contained in UDFjsrv.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +CREATE FUNCTION scalarUDF(CHAR(5), DOUBLE) +RETURNS DOUBLE +EXTERNAL NAME 'UDFjsrv!scalarUDF' +LANGUAGE JAVA +PARAMETER STYLE JAVA +NOT VARIANT +FENCED +CALLED ON NULL INPUT +NO SQL +NO EXTERNAL ACTION@ + +connect reset@ diff --git a/java/sqlj/UDFjDrop.db2 b/java/sqlj/UDFjDrop.db2 new file mode 100644 index 0000000..ed513c0 --- /dev/null +++ b/java/sqlj/UDFjDrop.db2 @@ -0,0 +1,34 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: UDFjDrop.db2 +-- +-- SAMPLE: How to uncatalog the UDFs contained in UDFjsrv.java +-- +-- To run this script from the CLP issue the below command: +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +connect to sample@ + +DROP FUNCTION scalarUDF@ + +connect reset@ diff --git a/java/sqlj/UDFjcli.sqlj b/java/sqlj/UDFjcli.sqlj new file mode 100644 index 0000000..92980bf --- /dev/null +++ b/java/sqlj/UDFjcli.sqlj @@ -0,0 +1,167 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFjcli.sqlj +// +// SAMPLE: Call the UDFs in UDFjsrv.java +// +// Parameter Style used in this program is "JAVA". +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Update makefile with a valid (userid,) password and +// an available port number. +// 2. Compile the server source file UDFjsrv.java (this will also +// compile the Utility file, Util.sqlj, erase the existing +// library/class file and copy the newly compiled class file, +// UDFjsrv.class from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make UDFjsrv +// 3. Compile the client source file UDFcli (this will also call +// the script 'udfjcat' to create and catalog the UDFs): +// nmake/make UDFjcli +// 4. Run the client UDFjcli: +// java UDFjcli +// +// II) If you don't have a compatible make/nmake program on your +// system, do the following: +// 1. Compile the server source file with the following command: +// javac UDFjsrv.java +// 2. Erase the existing library/class files (if exists), +// UDFsrv.class from the $(DB2PATH)\function directory. +// 3. copy the class files, UDFsrv.class from the current +// directory to the $(DB2PATH)\function. +// 4. Register/catalog the UDFs with: +// udfjcat +// 5. Compile the utility file with the following command: +// sqlj Util.sqlj +// 6. Update bldsqljs and bldsqlj build files with a valid userid +// and password. +// 7. Build the SQLj UDFs with with: +// bldsqlj UDFjcli +// 8. Run UDFcli with: +// java UDFjcli +// +// SQL Statements USED: +// FETCH +// SELECT +// +// OUTPUT FILE: UDFjcli.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; // JDBC classes +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator CursorForScalarUDF(String, String, double, double); + +class UDFjcli +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO WORK WITH UDFs."); + + // connect database + db.getDefaultContext(); + + demoExternalScalarUDF(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + static void demoExternalScalarUDF() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENTS:\n" + + " SELECT\n" + + "TO WORK WITH SCALAR UDF."); + + // use scalar UDF + System.out.println(); + System.out.println( + " Use the scalar UDF:\n" + + " SELECT name, job, salary, scalarUDF(job, salary)\n" + + " FROM staff\n" + + " WHERE name LIKE 'S%'"); + + CursorForScalarUDF cur; + String name = null; + String job = null; + double salary = 0.0; + double newSalary = 0.0; + + #sql cur = {SELECT name, job, salary, scalarUDF(job, salary) + FROM staff + WHERE name LIKE 'S%'}; + + System.out.println(); + System.out.println(" NAME JOB SALARY NEW_SALARY\n" + + " ---------- ------- -------- ----------"); + + #sql {FETCH :cur INTO :name, :job, :salary, :newSalary}; + + while (!cur.endFetch()) + { + System.out.println(" " + Data.format(name, 10) + + " " + Data.format(job, 7) + + " " + Data.format(salary, 7, 2) + + " " + Data.format(newSalary, 7, 2)); + + #sql {FETCH :cur INTO :name, :job, :salary, :newSalary}; + } + cur.close(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // demoExternalScalarUDF + + +} // UDFjcli + diff --git a/java/sqlj/UDFjsrv.java b/java/sqlj/UDFjsrv.java new file mode 100644 index 0000000..fe0fbae --- /dev/null +++ b/java/sqlj/UDFjsrv.java @@ -0,0 +1,107 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFjsrv.java +// +// SAMPLE: Provide UDFs to be called by UDFjcli.sqlj +// +// Parameter Style used in this program is "JAVA". +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Update makefile with a valid (userid,) password and +// an available port number. +// 2. Compile the server source file UDFjsrv.java (this will also +// compile the Utility file, Util.sqlj, erase the existing +// library/class file and copy the newly compiled class file, +// UDFjsrv.class from the current directory to the +// $(DB2PATH)\function directory): +// nmake/make UDFjsrv +// 3. Compile the client source file UDFcli (this will also call +// the script 'udfjcat' to create and catalog the UDFs): +// nmake/make UDFjcli +// 4. Run the client UDFjcli: +// java UDFjcli +// +// II) If you don't have a compatible make/nmake program on your +// system, do the following: +// 1. Compile the server source file with the following command: +// javac UDFjsrv.java +// 2. Erase the existing library/class files (if exists), +// UDFsrv.class from the $(DB2PATH)\function directory. +// 3. copy the class files, UDFsrv.class from the current +// directory to the $(DB2PATH)\function. +// 4. Register/catalog the UDFs with: +// udfjcat +// 5. Compile the utility file with the following command: +// sqlj Util.sqlj +// 6. Update bldsqljs and bldsqlj build files with a valid userid +// and password. +// 7. Build the SQLj UDFs with with: +// bldsqlj UDFjcli +// 8. Run UDFcli with: +// java UDFjcli +// +// OUTPUT FILE: UDFjcli.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; // for String class +import java.io.*; // for ...Stream classes + +public class UDFjsrv +{ + // scalar UDF + public static double scalarUDF(String inJob, double inSalary) + throws Exception + { + double outNewSalary = 0.00; + + if (inJob.equals("Mgr ")) + { + outNewSalary = inSalary * 1.20; + } + else if (inJob.equals("Sales")) + { + outNewSalary = inSalary * 1.10; + } + else + { + // Job is clerk + outNewSalary = inSalary * 1.05; + } + // set the output value + return outNewSalary; + } + +} + diff --git a/java/sqlj/UDFsrv.java b/java/sqlj/UDFsrv.java new file mode 100644 index 0000000..5f83d99 --- /dev/null +++ b/java/sqlj/UDFsrv.java @@ -0,0 +1,271 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: UDFsrv.java +// +// SAMPLE: Provide UDFs to be called by UDFcli.sqlj +// +// Parameter Style used in this program is "DB2GENERAL". +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Update makefile with a valid (userid,) password and +// an available port number. +// 2. Compile the server source file UDFsrv.java (this will also +// compile the Utility file, Util.sqlj, erase the existing +// library/class files and copy the newly compiled class files, +// UDFsrv.class and Person.class from the current directory +// to the $(DB2PATH)\function directory): +// nmake/make UDFsrv +// 3. Compile the client source file UDFcli (this will also call +// the script 'udfcat' to create and catalog the UDFs): +// nmake/make UDFcli +// 4. Run the client UDFcli: +// java UDFcli +// +// II) If you don't have a compatible make/nmake program on your +// system, do the following: +// 1. Compile the server source file with the following command: +// javac UDFsrv.java +// 2. Erase the existing library/class files (if exists), +// UDFsrv.class and Person.class from the following path, +// $(DB2PATH)\function. +// 3. copy the class files, UDFsrv.class and Person.class from +// the current directory to the $(DB2PATH)\function. +// 4. Register/catalog the UDFs with: +// udfcat +// 5. Compile the utility file with the following command: +// sqlj Util.sqlj +// 6. Update bldsqljs and bldsqlj build files with a valid userid +// and password. +// 7. Build the SQLj UDFs with with: +// bldsqlj UDFcli +// 8. Run UDFcli with: +// java UDFcli +// +// OUTPUT FILE: UDFcli.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; // for String class +import java.io.*; // for ...Stream classes +import COM.ibm.db2.app.UDF; // UDF classes + +// Java user-defined functions are in this class +public class UDFsrv extends UDF +{ + // SCRATCHPAD scalar UDF + public void scratchpadScUDF(int outCounter) throws Exception + { + int intCounter = 0; + byte[] scratchpad = getScratchpad(); + + // variables to read from SCRATCHPAD area + ByteArrayInputStream byteArrayIn = new ByteArrayInputStream(scratchpad); + DataInputStream dataIn = new DataInputStream(byteArrayIn); + + // variables to write into SCRATCHPAD area + byte[] byteArrayCounter; + int i; + ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(10); + DataOutputStream dataOut = new DataOutputStream(byteArrayOut); + + switch (getCallType()) + { + case SQLUDF_FIRST_CALL: + // initialize data + intCounter = 1; + // save data into SCRATCHPAD area + dataOut.writeInt(intCounter); + byteArrayCounter = byteArrayOut.toByteArray(); + for (i = 0; i < byteArrayCounter.length; i++) + { + scratchpad[i] = byteArrayCounter[i]; + } + setScratchpad(scratchpad); + break; + case SQLUDF_NORMAL_CALL: + // read data from SCRATCHPAD area + intCounter = dataIn.readInt(); + // work with data + intCounter = intCounter + 1; + // save data into SCRATCHPAD area + dataOut.writeInt(intCounter); + byteArrayCounter = byteArrayOut.toByteArray(); + for (i = 0; i < byteArrayCounter.length; i++) + { + scratchpad[i] = byteArrayCounter[i]; + } + setScratchpad(scratchpad); + + break; + } + // set the output value + set(1, intCounter); + + } // scratchpadScUDF + + public void scUDFReturningErr(double inOperand1, + double inOperand2, + double outResult) + throws Exception + { + if (inOperand2 == 0.00) + { + setSQLstate("38999"); + setSQLmessage("DIVIDE BY ZERO ERROR"); + } + else + { + outResult = inOperand1 / inOperand2; + } + set(3, outResult); + } // scUDFReturningErr + + // variable for tableUDF + static final Person[] staff = + { + new Person("Pearce" , "Mgr" , 17300.00), + new Person("Wagland", "Sales", 15000.00), + new Person("Davis" , "Clerk", 10000.00)}; + + // the table UDF + public void tableUDF(double inSalaryFactor, + String outName, + String outJob, + double outNewSalary) + throws Exception + { + int intRow = 0; + byte[] scratchpad = getScratchpad(); + + // variables to read from SCRATCHPAD area + ByteArrayInputStream byteArrayIn = new ByteArrayInputStream(scratchpad); + DataInputStream dataIn = new DataInputStream(byteArrayIn); + + // variables to write into SCRATCHPAD area + byte[] byteArrayRow; + int i; + ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(10); + DataOutputStream dataOut = new DataOutputStream(byteArrayOut); + + switch (getCallType()) + { + case SQLUDF_TF_FIRST: + // do initialization for the whole statement + // (the statement may invoke tableUDF more than once) + break; + case SQLUDF_TF_OPEN: + // do initialization valid for this invokation of tableUDF + intRow = 1; + // save data in SCRATCHPAD area + dataOut.writeInt(intRow); + byteArrayRow = byteArrayOut.toByteArray(); + for (i = 0; i < byteArrayRow.length; i++) + { + scratchpad[i] = byteArrayRow[i]; + } + setScratchpad(scratchpad); + break; + case SQLUDF_TF_FETCH: + // get data from SCRATCHPAD area + intRow = dataIn.readInt(); + + // work with data + if (intRow > staff.length) + { + // Set end-of-file signal and return + setSQLstate("02000"); + } + else + { + // Set the current output row and increment the row number + set(2, staff[intRow - 1].getName()); + set(3, staff[intRow - 1].getJob()); + set(4, staff[intRow - 1].getSalary() * inSalaryFactor); + intRow++; + } + + // save data in SCRATCHPAD area + dataOut.writeInt(intRow); + byteArrayRow = byteArrayOut.toByteArray(); + for (i = 0; i < byteArrayRow.length; i++) + { + scratchpad[i] = byteArrayRow[i]; + } + setScratchpad(scratchpad); + break; + case SQLUDF_TF_CLOSE: + break; + case SQLUDF_TF_FINAL: + break; + } + } // tableUDF +} // UDFsrv class + +// the class Person is used by the table UDF +class Person +{ + String name; + String job; + double salary; + + Person() + { + name = null; + job = null; + salary = 0.00; + } + + Person(String n , String j, double s) + { + name = n; + job = j; + salary = s; + } + + public String getName() + { + return name; + } + + public String getJob() + { + return job; + } + + public double getSalary() + { + return salary; + } +} // Person class + diff --git a/java/sqlj/Util.sqlj b/java/sqlj/Util.sqlj new file mode 100644 index 0000000..0698946 --- /dev/null +++ b/java/sqlj/Util.sqlj @@ -0,0 +1,319 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Util.sqlj +// +// SAMPLE: Utilities for SQLJ sample programs +// +// This sample has 3 classes: +// 1. Data - Display the data in the table +// 2. Db - Connect to or disconnect from the 'sample' database +// 3. SqljException - Handle Java Exceptions +// +// JAVA 2 CLASSES USED: +// DriverManager +// Connection +// Exception +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.util.*; +import java.sql.*; +import java.math.BigDecimal; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class Data +{ + public static String format(String strData, int finalLen) + throws Exception + { + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = strData; + for (int i = strData.length(); i < finalLen; i++) + { + finalStr = finalStr + " "; + } + } + return (finalStr); + } // format(String, int) + + public static String format(int intData, int finalLen) + throws Exception + { + String strData = String.valueOf(intData); + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + return (finalStr); + } // format(int, int) + + public static String format(Integer integerData, int finalLen) + throws Exception + { + int intData; + String finalStr; + + intData = integerData.intValue(); + finalStr = format(intData, finalLen); + + return finalStr; + } // format(Integer, int) + + public static String format(double doubData, int precision, int scale) + throws Exception + { + BigDecimal decData = new BigDecimal(doubData); + decData = decData.setScale(scale, BigDecimal.ROUND_HALF_EVEN); + String strData = decData.toString(); + + // prepare the final string + int finalLen = precision + 1; + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + return (finalStr); + } // format(double, int, int) + + public static String format(Double doubleData, int precision, int scale) + throws Exception + { + double doubData; + String finalStr; + + doubData = doubleData.doubleValue(); + return (format(doubData, precision, scale)); + } // format(Double, int, int) +} // Data + +class Db +{ + public String alias; + public String server; + public int portNumber = -1; // < 0 use universal type 2 connection + // > 0 use universal type 4 connection + public String userId; + public String password; + private Connection con; + private DefaultContext ctx; + + public Db() + { + } + + public Db(String argv[]) throws Exception + { + if( argv.length > 5 || + ( argv.length == 1 && + ( argv[0].equals( "?" ) || + argv[0].equals( "-?" ) || + argv[0].equals( "/?" ) || + argv[0].equalsIgnoreCase( "-h" ) || + argv[0].equalsIgnoreCase( "/h" ) || + argv[0].equalsIgnoreCase( "-help" ) || + argv[0].equalsIgnoreCase( "/help" ) ) ) ) + { + throw new Exception( + "Usage: prog_name [dbAlias] [userId passwd] (use universal JDBC type 2 driver)\n" + + " prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)" ); + } + + switch (argv.length) + { + case 0: // Type 2, use all defaults + alias = "sample"; + userId = ""; + password = ""; + break; + case 1: // Type 2, dbAlias specified + alias = argv[0]; + userId = ""; + password = ""; + break; + case 2: // Type 2, userId & passwd specified + alias = "sample"; + userId = argv[0]; + password = argv[1]; + break; + case 3: // Type 2, dbAlias, userId & passwd specified + alias = argv[0]; + userId = argv[1]; + password = argv[2]; + break; + case 4: // Type 4, use default dbAlias + alias = "sample"; + server = argv[0]; + portNumber = Integer.valueOf( argv[1] ).intValue(); + userId = argv[2]; + password = argv[3]; + break; + case 5: // Type 4, everything specified + alias = argv[0]; + server = argv[1]; + portNumber = Integer.valueOf( argv[2] ).intValue(); + userId = argv[3]; + password = argv[4]; + break; + } + } // Db constructor + + public Connection connect() throws Exception + { + String url = null; + + // In Partitioned Database environment, set this to the node number + // to which you wish to connect (leave as "0" in non-Partitioned Database environment) + String nodeNumber = "0"; + + Properties props = new Properties(); + + if ( portNumber < 0 ) + { + url = "jdbc:db2:" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 2 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + else + { + url = "jdbc:db2://" + server + ":" + portNumber + "/" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 4 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + + if( null != userId ) + { + props.setProperty("user", userId); + props.setProperty("password", password); + } + + props.setProperty("CONNECTNODE", nodeNumber); + + con = DriverManager.getConnection( url, props ); + + // enable transactions + con.setAutoCommit(false); + return con; + } // connect + + public DefaultContext getDefaultContext() throws Exception + { + ctx = new DefaultContext( connect() ); + DefaultContext.setDefaultContext(ctx); + return( ctx ); + } // connect + + public void disconnect() throws Exception + { + System.out.println(); + System.out.println(" Disconnect from '" + alias + "' database."); + + // makes all changes made since the previous commit/rollback permanent + // and releases any database locks currrently held by the Connection. + con.commit(); + + // releases a Connection's database and JDBC resources immediately + if( ctx != null ) + { + ctx.close(); + } + else + { + con.close(); + } + } // disconnect +} // Db + +class SqljException extends Exception +{ + public SqljException(Exception e) + { + super(e.getMessage()); + } + + public void handle() + { + try + { + System.out.println(getMessage()); + System.out.println(); + System.out.println("--Rollback the transaction-----"); + #sql {ROLLBACK}; + System.out.println(" Rollback done!"); + } + catch (Exception e) + { + }; + } // handle + + public void handleExpectedErr() + { + System.out.println(); + System.out.println( + "**************** Expected Error ******************\n"); + System.out.println(getMessage()); + System.out.println( + "**************************************************"); + } // handleExpectedErr +} // SqljException + diff --git a/java/sqlj/bldsqlj b/java/sqlj/bldsqlj new file mode 100644 index 0000000..9163753 --- /dev/null +++ b/java/sqlj/bldsqlj @@ -0,0 +1,90 @@ +#!/bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldsqlj +# Builds Java embedded SQL (SQLJ) applications and applets on UNIX +# Usage: bldsqlj prog_name (requires hardcoding user ID and password) +# bldsqlj prog_name userid password +# bldsqlj prog_name userid password server_name +# bldsqlj prog_name userid password server_name port_number +# bldsqlj prog_name userid password server_name port_number db_name +# +# Defaults: +# userid = $USER variable requires updating if used +# password = $PSWD variable requires updating if used +# server_name = $SERVER variable set to local hostname +# port_number = $PORTNUM variable set to 50000 +# db_name = $DB variable set to "sample" + +# To hardcode user ID (USER) and password (PSWD) +# Replace "NULL" with the correct values in quotes +USER="NULL" +PSWD="NULL" +# You can replace the defaults for each of the following +# with a new value. Note that the PORTNUM number cannot +# be one already used by another process. +SERVER=`hostname` +PORTNUM=50000 +DB="sample" + + +# Translate and compile the SQLJ source file +# and bind the package to the database. + if ( [ $# -eq 1 ] && [ $USER != "NULL" ] && [ $PSWD != "NULL" ] ) || ( [ $# -ge 3 ] && [ $# -le 6 ] ) + then + # Remove .sqlj extension + progname=${1%.sqlj} + + sqlj "${progname}.sqlj" + + if [ $# -eq 1 ] + then + db2sqljcustomize -url jdbc:db2://$SERVER:$PORTNUM/$DB \ + -user $USER -password $PSWD "${progname}_SJProfile0" + elif [ $# -eq 3 ] + then + db2sqljcustomize -url jdbc:db2://$SERVER:$PORTNUM/$DB -user $2 -password $3 \ + "${progname}_SJProfile0" + elif [ $# -eq 4 ] + then + db2sqljcustomize -url jdbc:db2://$4:$PORTNUM/$DB -user $2 -password $3 \ + "${progname}_SJProfile0" + elif [ $# -eq 5 ] + then + db2sqljcustomize -url jdbc:db2://$4:$5/$DB -user $2 -password $3 \ + "${progname}_SJProfile0" + else + db2sqljcustomize -url jdbc:db2://$4:$5/$6 -user $2 -password $3 \ + "${progname}_SJProfile0" + fi + else + echo 'Usage: bldsqlj prog_name (requires hardcoding user ID and password)' + echo ' bldsqlj prog_name userid password' + echo ' bldsqlj prog_name userid password server_name' + echo ' bldsqlj prog_name userid password server_name port_number' + echo ' bldsqlj prog_name userid password server_name port_number db_name' + echo '' + echo ' Defaults:' + echo ' userid = '$USER + echo ' password = '$PSWD + echo ' server_name = '$SERVER + echo ' port_number = '$PORTNUM + echo ' db_name = '$DB + fi diff --git a/java/sqlj/bldsqljds b/java/sqlj/bldsqljds new file mode 100644 index 0000000..5cc9675 --- /dev/null +++ b/java/sqlj/bldsqljds @@ -0,0 +1,66 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +# +# Builds a Java embedded SQL (SQLJ) application that uses DataSource +############################################################################# +# SCRIPT: bldsqljds +# Builds UNIX Java embedded SQLJ application that uses DataSource +# Usage: see usage() function, below + +# Translate and compile the SQLJ source file +# and bind the package to the database. + + +usage(){ + print "usage: bldsqljds " +} + +case $1 in + DbConnDataSource) + sqlj Util.sqlj + sqlj $1.sqlj + db2sqljcustomize -dataSource jdbc/defaultDataSource -longpkgname $1_SJProfile0 + exit 0; + ;; + DbConMDataSources) + sqlj Util.sqlj + sqlj $1.sqlj + db2sqljcustomize -dataSource jdbc/DB2SimpleDataSource_ds1 $1_SJProfile0 + db2sqljcustomize -dataSource jdbc/DB2SimpleDataSource_ds2 $1_SJProfile0 + exit 0; + ;; + Batch1Demo | Batch2Demo | Batch3Demo | ScrollIterDemo) + sqlj Util.sqlj + sqlj $1.sqlj + db2sqljcustomize -dataSource jdbc/DB2SimpleDataSource_ds1 $1_SJProfile0 + exit 0; + ;; + BlobClobDemo) + sqlj Util.sqlj + sqlj $1.sqlj + db2sqljcustomize -dataSource jdbc/DB2SimpleDataSource_ds1 $1_SJProfile0 + exit 0; + ;; +esac + +usage +exit 1 + + diff --git a/java/sqlj/bldsqljs b/java/sqlj/bldsqljs new file mode 100644 index 0000000..59ba7e3 --- /dev/null +++ b/java/sqlj/bldsqljs @@ -0,0 +1,97 @@ +#!/bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldsqljs +# Builds Java embedded SQL (SQLJ) stored procedures on UNIX +# Usage: bldsqljs prog_name (requires hardcoding user ID and password) +# bldsqljs prog_name userid password +# bldsqljs prog_name userid password server_name +# bldsqljs prog_name userid password server_name port_number +# bldsqljs prog_name userid password server_name port_number db_name +# +# Defaults: +# userid = $USER variable requires updating if used +# password = $PSWD variable requires updating if used +# server_name = $SERVER variable set to local hostname +# port_number = $PORTNUM variable set to 50000 +# db_name = $DB variable set to "sample" + +# To hardcode user ID (USER) and password (PSWD) +# Replace "NULL" with the correct values in quotes +USER="NULL" +PSWD="NULL" +# You can replace the defaults for each of the following +# with a new value. Note that the PORTNUM number cannot +# be one already used by another process. +SERVER=`hostname` +PORTNUM=50000 +DB="sample" + + +# Translate and compile the SQLJ source file +# and bind the package to the database. + if (( [ $# -eq 1 ] && [ $USER != "NULL" ] && [ $PSWD != "NULL" ] ) || ( [ $# -ge 3 ] && [ $# -le 6 ] ) ) + then + # Remove .sqlj extension + progname=${1%.sqlj} + + sqlj "${progname}.sqlj" + + if [ $# -eq 1 ] + then + db2sqljcustomize -url jdbc:db2://$SERVER:$PORTNUM/$DB \ + -user $USER -password $PSWD "${progname}_SJProfile0" + elif [ $# -eq 3 ] + then + db2sqljcustomize -url jdbc:db2://$SERVER:$PORTNUM/$DB -user $2 -password $3 \ + "${progname}_SJProfile0" + elif [ $# -eq 4 ] + then + db2sqljcustomize -url jdbc:db2://$4:$PORTNUM/$DB -user $2 -password $3 \ + "${progname}_SJProfile0" + elif [ $# -eq 5 ] + then + db2sqljcustomize -url jdbc:db2://$4:$5/$DB -user $2 -password $3 \ + "${progname}_SJProfile0" + else + db2sqljcustomize -url jdbc:db2://$4:$5/$6 -user $2 -password $3 \ + "${progname}_SJProfile0" + fi + + # Copy the *.class and *.ser files to the 'function' directory. + rm -f "$DB2PATH/function/${progname}*.class" + rm -f "$DB2PATH/function/${progname}*.ser" + cp "${progname}*.class" "$DB2PATH/function" + cp "${progname}*.ser" "$DB2PATH/function" + + else + echo 'Usage: bldsqljs prog_name (requires hardcoding user ID and password)' + echo ' bldsqljs prog_name userid password' + echo ' bldsqljs prog_name userid password server_name' + echo ' bldsqljs prog_name userid password server_name port_number' + echo ' bldsqljs prog_name userid password server_name port_number db_name' + echo '' + echo ' Defaults:' + echo ' userid = '$USER + echo ' password = '$PSWD + echo ' server_name = '$SERVER + echo ' port_number = '$PORTNUM + echo ' db_name = '$DB + fi diff --git a/java/sqlj/createRegisterDS.java b/java/sqlj/createRegisterDS.java new file mode 100644 index 0000000..b424f7c --- /dev/null +++ b/java/sqlj/createRegisterDS.java @@ -0,0 +1,127 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: createRegisterDS.java +// +// SAMPLE: Create & Register DataSources as specfied by the property files +// +// The DataSources will be created in the temp directory. +// It uses File System SPI - Creates a .bindings file in +// temp directory C:/temp (as defined in jndi.properties) +// +// Use this & one of the 3 property files to create : +// DS1.prop: jdbc/defaultDataSource +// DS2.prop: jdbc/DB2SimpleDataSource_ds1 +// DS3.prop: jdbc/DB2SimpleDataSource_ds2 +// +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import com.ibm.db2.jcc.DB2SimpleDataSource; +import javax.naming.*; +import java.util.*; +import java.io.*; + +public class createRegisterDS +{ + public static void main (String args[]) + { + if (args.length != 1) + { + System.out.println( "Usage: createRegisterDS "); + return; + } + createRegisterDS crds = new createRegisterDS(); + System.out.println (""); + + crds.runThis(args[0]); + System.out.println(">>>Registering DataSource using Property File: " + args[0] ); + System.out.println(">>>Done Register"); + System.out.println (""); + } + private void runThis(String args) + { + try + { + + registerDS( args, new InitialContext()); + } + catch (Exception e) + { + System.err.println ("Problem with registration: " + e.getMessage()); + e.printStackTrace(); + return; + } + } + private void registerDS( String DSname, Context registry) + throws Exception + { + DB2SimpleDataSource dataSource = new DB2SimpleDataSource(); + Properties prop = new Properties(); + FileInputStream dsPropFile = null; + try + { + dsPropFile = new FileInputStream( DSname); + } + catch (FileNotFoundException fe) + { + System.out.println (fe.getMessage()); + throw fe; + } + prop.load( dsPropFile ); + + dataSource.setServerName (prop.getProperty("serverName")); + + String portNum = prop.getProperty("portNumber"); + int portNo = (new Integer(portNum)).intValue() ; + dataSource.setPortNumber (portNo); + + + dataSource.setDatabaseName (prop.getProperty("databaseName")); + dataSource.setUser (prop.getProperty("userName")); + dataSource.setPassword (prop.getProperty("password")); + String DSName = prop.getProperty("dataSourceName"); + dataSource.setDataSourceName (DSName); + String dType = prop.getProperty("driverType"); + int drType = (new Integer(dType)).intValue() ; + dataSource.setDriverType(drType); + + String sMech = prop.getProperty("securityMechanism"); + short secMech = (new Integer(sMech)).shortValue(); + dataSource.setSecurityMechanism (secMech); + + dataSource.setKerberosServerPrincipal ( + prop.getProperty("kerberosPrincipal")); + + registry.rebind(DSName, dataSource); + } +} diff --git a/java/sqlj/jndi.properties b/java/sqlj/jndi.properties new file mode 100644 index 0000000..9c792bf --- /dev/null +++ b/java/sqlj/jndi.properties @@ -0,0 +1,2 @@ +java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory +java.naming.provider.url=file:. diff --git a/java/sqlj/makefile b/java/sqlj/makefile new file mode 100644 index 0000000..d5aa220 --- /dev/null +++ b/java/sqlj/makefile @@ -0,0 +1,439 @@ +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# +# MAKEFILE for SQLj samples on Unix +# +# Enter one of the following commands +# +# make - Builds the program designated by . +# +# make all - Builds all supplied sample programs. +# +# make srv - Builds samples that can only be run on the server, +# including routines, stored procedures and UDFs. +# +# make rtn - Builds all routines, stored procedures and UDFs. +# +# make all_client - Builds all client samples (all programs in the +# 'call_rtn' and 'client_run' categories). +# +# make call_rtn - Builds all client programs that call routines, +# stored procedures and UDFs. +# +# make client_run - Builds all programs that run completely on the +# client (not ones that call routines, stored +# procedures or UDFs). +# +# make java_beans - Builds all Java Beans samples. +# +# make clean - Erases all intermediate files produced in the +# build process. +# +# make cleanall - Erases all files produced in the build process +# (all files except the original source files). +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +############################################################################ +# 1 -- VARIABLES +############################################################################ + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +# To connect to a remote SAMPLE database cataloged on the client machine +# with another name, update the DB variable. +DB=sample +# Set UID, PWD, SERVER_NAME and PORT_NUMBER +UID=$(USER) +PWD= +SERVER_NAME=$(HOSTNAME) +PORT_NUMBER=50000 + +COPY=cp +ERASE=rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all (srv + all_client) +# 2b - make srv +# 2c - make rtn +# 2d - make all_client (call_rtn + client_run + java_beans) +# 2e - make call_rtn +# 2f - make client_run +# 2g - make java_beans +# 2h - make clean +# 2i - make cleanall +############################################################################# + +#**************************************************************************** +# 2a - make all (srv + all_client) +#**************************************************************************** + +all : \ + srv \ + all_client \ + sqljds + +#**************************************************************************** +# 2b - make srv +#**************************************************************************** + +srv : \ + rtn + +#**************************************************************************** +# 2c - make rtn +#**************************************************************************** + +rtn : \ + SpServer \ + UDFsrv \ + UDFjsrv + +#**************************************************************************** +# 2d - make all_client (call_rtn + client_run + java_beans) +#**************************************************************************** + +all_client : \ + call_rtn \ + client_run \ + sqljds \ + java_beans + +#**************************************************************************** +# 2e - make call_rtn +#**************************************************************************** + +call_rtn : \ + SpClient \ + UDFcli \ + UDFjcli + +#**************************************************************************** +# 2f - make client_run +#**************************************************************************** + +client_run : \ + Applt \ + DbAuth DbConn DbMCon DbUse \ + DtUdt \ + LargeRid SetIntegrity \ + TbAST TbCompress TbConstr TbCreate TbIdent TbInfo TbMod TbOnlineInx \ + TbPriv TbRead TbRowcompress TbRunstats TbSel TbTemp TbTrig TbUMQT \ + +#**************************************************************************** +# 2g - make java_beans +#**************************************************************************** + +java_beans : \ + CreateEmployee \ + GeneratePayroll + +#**************************************************************************** +# 2h - make clean +#**************************************************************************** + +clean : + $(ERASE) Applt.java + $(ERASE) CreateEmployee.java + $(ERASE) DbAuth.java + $(ERASE) DbConn.java + $(ERASE) DbMCon.java + $(ERASE) DbUse.java + $(ERASE) DtUdt.java + $(ERASE) GeneratePayroll.java + $(ERASE) LargeRid.java + $(ERASE) SetIntegrity.java + $(ERASE) TbAST.java + $(ERASE) TbCompress.java + $(ERASE) TbConstr.java + $(ERASE) TbCreate.java + $(ERASE) TbIdent.java + $(ERASE) TbInfo.java + $(ERASE) TbMod.java + $(ERASE) TbOnlineInx.java + $(ERASE) TbPriv.java + $(ERASE) TbRead.java + $(ERASE) TbRowcompress.java + $(ERASE) TbRunstats.java + $(ERASE) TbSel.java + $(ERASE) TbTemp.java + $(ERASE) TbTrig.java + $(ERASE) TbUMQT.java + $(ERASE) SpClient.java + $(ERASE) SpIterat.java + $(ERASE) SpServer.java + $(ERASE) UDFcli.java + $(ERASE) UDFjcli.java + $(ERASE) Util.java + $(ERASE) Batch1Demo.java + $(ERASE) Batch2Demo.java + $(ERASE) Batch3Demo.java + $(ERASE) BlobClobDemo.java + $(ERASE) CreateDemoSchema.java + $(ERASE) DbConnDataSource.java + $(ERASE) DbConMDataSources.java + $(ERASE) ScrollIterDemo.java + +#**************************************************************************** +# 2i - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) *.class *.ser + $(ERASE) $(DB2PATH)/function/SpContext.class + $(ERASE) $(DB2PATH)/function/SpIterat.class + $(ERASE) $(DB2PATH)/function/SpServer.class + $(ERASE) $(DB2PATH)/function/SpServerEmployees.class + $(ERASE) $(DB2PATH)/function/SpServerSalary.class + $(ERASE) $(DB2PATH)/function/SpServer_SJProfileKeys.class + $(ERASE) $(DB2PATH)/function/SpServer_SJProfile0.ser + $(ERASE) $(DB2PATH)/function/Person.class + $(ERASE) $(DB2PATH)/function/UDFsrv.class + $(ERASE) $(DB2PATH)/function/UDFjsrv.class + + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3b - applet +# 3c - standalone applications +# 3d - client/server applications +# 3e - Java Beans applications +############################################################################# + +#*************************************************************************** +# 3b - applet +#*************************************************************************** +Applt : Applt.sqlj + bldsqlj Applt $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +#*************************************************************************** +# 3c - standalone applications +#*************************************************************************** +DbAuth : Util.class DbAuth.sqlj + bldsqlj DbAuth $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +DbConn : Util.class DbConn.sqlj + bldsqlj DbConn $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +DbMCon : Util.class DbMCon.sqlj +# Re-catalog sample database as sample2, +# ignore errors since it may be cataloged already + -db2 catalog db $(DB) as sample2 + bldsqlj DbMCon $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + java com.ibm.db2.jcc.sqlj.Binder \ + -url jdbc:db2://$(SERVER_NAME):$(PORT_NUMBER)/sample2 \ + -user $(UID) -password $(PWD) $@_SJProfile0.ser + +DbUse : Util.class DbUse.sqlj + bldsqlj DbUse $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +DtUdt : Util.class DtUdt.sqlj + bldsqlj DtUdt $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +LargeRid : Util.class LargeRid.sqlj + LargeRidScrpt + bldsqlj LargeRid $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +SetIntegrity: Util.class SetIntegrity.sqlj + SetIntegrityScrpt + bldsqlj SetIntegrity $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbAST : Util.class TbAST.sqlj + TbASTScrpt + bldsqlj TbAST $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbCompress : Util.class TbCompress.sqlj + bldsqlj TbCompress $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbConstr : Util.class TbConstr.sqlj + sqlj TbConstr.sqlj + +TbCreate : Util.class TbCreate.sqlj + bldsqlj TbCreate $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbIdent : Util.class TbIdent.sqlj + bldsqlj TbIdent $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbInfo : Util.class TbInfo.sqlj + bldsqlj TbInfo $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbMod : Util.class TbMod.sqlj + bldsqlj TbMod $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbOnlineInx : Util.class TbOnlineInx.sqlj + bldsqlj TbOnlineInx $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbPriv : Util.class TbPriv.sqlj + bldsqlj TbPriv $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbRead : Util.class TbRead.sqlj + bldsqlj TbRead $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbRowcompress : Util.class TbRowcompress.sqlj + TbRowcompressScrpt + bldsqlj TbRowcompress $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbRunstats : Util.class TbRunstats.sqlj + bldsqlj TbRunstats $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbSel : Util.class TbSel.sqlj + bldsqlj TbSel $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbTemp : Util.class TbTemp.sqlj + sqlj TbTemp.sqlj + +TbTrig : Util.class TbTrig.sqlj + bldsqlj TbTrig $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +TbUMQT : Util.class TbUMQT.sqlj + sqlj TbUMQT.sqlj + +Util.class : Util.sqlj + bldsqlj Util $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +#*************************************************************************** +# 3d - client/server applications +#*************************************************************************** + +#--------------------SpClient / SpServer------------------------------------# +# Note: before you execute SpClient for the first time, you must call the +# SpCreate.db2 CLP script to catalog the methods in SpServer as stored +# procedures + +SpCat : + spcat + +SpClient : Util.class SpClient.sqlj + bldsqlj SpClient $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +SpIterat.class : SpIterat.sqlj + sqlj SpIterat.sqlj + +SpServer : SpIterat.class SpServer.sqlj + bldsqlj SpServer $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + $(ERASE) $(DB2PATH)/function/SpContext.class + $(ERASE) $(DB2PATH)/function/SpIterat.class + $(ERASE) $(DB2PATH)/function/SpServer.class + $(ERASE) $(DB2PATH)/function/SpServerEmployees.class + $(ERASE) $(DB2PATH)/function/SpServerSalary.class + $(ERASE) $(DB2PATH)/function/SpServer_SJProfileKeys.class + $(ERASE) $(DB2PATH)/function/SpServer_SJProfile0.ser + $(COPY) SpContext.class $(DB2PATH)/function + $(COPY) SpIterat.class $(DB2PATH)/function + $(COPY) SpServer.class $(DB2PATH)/function + $(COPY) SpServerEmployees.class $(DB2PATH)/function + $(COPY) SpServerSalary.class $(DB2PATH)/function + $(COPY) SpServer_SJProfileKeys.class $(DB2PATH)/function + $(COPY) SpServer_SJProfile0.ser $(DB2PATH)/function + spcat + +#--------------------UDFcli / UDFsrv------------------------------# +# Note: before you execute UDFcli for the first time, you must call the +# UDFCreate.db2 CLP script to register the functions in UDFsrv as +# User Defined Functions (UDFs). + +UDFcat : + udfcat + +UDFcli : UDFcat Util.class UDFcli.sqlj + bldsqlj UDFcli $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +UDFsrv : UDFsrv.java + javac UDFsrv.java + $(ERASE) $(DB2PATH)/function/UDFsrv.class + $(ERASE) $(DB2PATH)/function/Person.class + $(COPY) UDFsrv.class $(DB2PATH)/function + $(COPY) Person.class $(DB2PATH)/function + +#-------------------- UDFjcli / UDFjsrv ------------------------------# +# Note: before you execute UDFjcli for the first time, you must call the +# UDFjCreate.db2 CLP script to register the functions in UDFjsrv as +# User Defined Functions (UDFs). + +UDFjcat : + udfjcat + +UDFjcli : UDFjcat Util.class UDFjcli.sqlj + bldsqlj UDFjcli $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +UDFjsrv : UDFjsrv.java + javac UDFjsrv.java + $(ERASE) $(DB2PATH)/function/UDFjsrv.class + $(COPY) UDFjsrv.class $(DB2PATH)/function + +#*************************************************************************** +# 3e - Java Beans applications +#*************************************************************************** + +CreateEmployee : Util.class CreateEmployee.sqlj + bldsqlj CreateEmployee $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +GeneratePayroll : Util.class GeneratePayroll.sqlj + bldsqlj GeneratePayroll $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +#*************************************************************************** +# 3f - Data Source sample application +#*************************************************************************** + +Batch1Demo : + bldsqljds Batch1Demo + +Batch2Demo : + bldsqljds Batch2Demo + +Batch3Demo : + bldsqljds Batch3Demo + +BlobClobDemo : + bldsqljds BlobClobDemo + +DbConnDataSource : + bldsqljds DbConnDataSource + +DbConMDataSources : + bldsqljds DbConMDataSources + +ScrollIterDemo : + bldsqljds ScrollIterDemo + +#*************************************************************************** +# 3g - Data Source sample applications +#*************************************************************************** + +sqljdssetup : + javac createRegisterDS.java + java createRegisterDS DS1.prop + java createRegisterDS DS2.prop + java createRegisterDS DS3.prop + sqlj CreateDemoSchema.sqlj + java CreateDemoSchema + +sqljds : sqljdssetup Batch1Demo Batch2Demo Batch3Demo BlobClobDemo \ + DbConnDataSource DbConMDataSources ScrollIterDemo + diff --git a/java/sqlj/spcat b/java/sqlj/spcat new file mode 100755 index 0000000..b74ab67 --- /dev/null +++ b/java/sqlj/spcat @@ -0,0 +1,31 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: spcat +# To catalog SQLj stored procedures on UNIX +# Catalogs the stored procedures in the SpServer library +# SpDrop.db2 uncatalogs the stored procedures if previously cataloged +# SpCreate.db2 catologs the stored procedures +# Both CLP scripts can be run on their own +# Usage: spcat + +db2 -td@ -vf SpDrop.db2 +db2 -td@ -vf SpCreate.db2 + diff --git a/java/sqlj/udfcat b/java/sqlj/udfcat new file mode 100755 index 0000000..05f8876 --- /dev/null +++ b/java/sqlj/udfcat @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: udfcat +# To catalog SQLj user-defined functions on UNIX +# Catalogs the user-defined functions in the UDFsrv library +# UDFDrop.db2 uncatalogs the functions if previously cataloged +# UDFCreate.db2 catalogs the user-defined functions +# Both CLP scripts can be run on their own +# Usage: udfcat + +db2 -td@ -vf UDFDrop.db2 +db2 -td@ -vf UDFCreate.db2 diff --git a/java/sqlj/udfjcat b/java/sqlj/udfjcat new file mode 100755 index 0000000..21f79f3 --- /dev/null +++ b/java/sqlj/udfjcat @@ -0,0 +1,31 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: udfjcat +# To catalog SQLj user-defined functions on UNIX +# Catalogs the user-defined functions in the UDFjsrv library +# UDFjDrop.db2 uncatalogs the functions if previously cataloged +# UDFjCreate.db2 catalogs the user-defined functions +# Both CLP scripts can be run on their own +# Usage: udfjcat + +db2 -td@ -vf UDFjDrop.db2 +db2 -td@ -vf UDFjCreate.db2 + diff --git a/lifesci/SCRIPT_DAEMON.config b/lifesci/SCRIPT_DAEMON.config new file mode 100644 index 0000000..b2ec4ec --- /dev/null +++ b/lifesci/SCRIPT_DAEMON.config @@ -0,0 +1,7 @@ += +DAEMON_PORT=4099 +MAX_PENDING_REQUESTS=10 +DAEMON_LOGFILE_DIR=./ +SCRIPT_OUT_DIR_PATH=./ +foo=/home2/alinbui/script_wrapper/foo.pl +param_script=/home2/alinbui/script_wrapper/param_script.pl diff --git a/lifesci/biors/create_function_mappings.ddl b/lifesci/biors/create_function_mappings.ddl new file mode 100644 index 0000000..f937faf --- /dev/null +++ b/lifesci/biors/create_function_mappings.ddl @@ -0,0 +1,214 @@ +------------------------------------------------------------------------------- +-- +-- Source File Name: create_function_mappings.ddl +-- +-- (C) COPYRIGHT International Business Machines Corp. 2002, 2003 +-- All Rights Reserved +-- Licensed Materials - Property of IBM +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +-- +-- Function = Data Definition Language file containing +-- Function template declarations for BioRS wrapper +-- custom functions. +-- +-- Operating System: All +-- +------------------------------------------------------------------------------- + +-- DROP FUNCTION biors.contains (varchar(), varchar()) ; +-- DROP FUNCTION biors.contains (varchar(), char()) ; +-- DROP FUNCTION biors.contains (varchar(), date) ; +-- DROP FUNCTION biors.contains (varchar(), timestamp) ; +-- DROP FUNCTION biors.contains (varchar(), integer) ; +-- DROP FUNCTION biors.contains (varchar(), smallint) ; +-- DROP FUNCTION biors.contains (varchar(), bigint) ; +-- DROP FUNCTION biors.contains (varchar(), decimal) ; +-- DROP FUNCTION biors.contains (varchar(), double) ; +-- DROP FUNCTION biors.contains (varchar(), real) ; +-- DROP FUNCTION biors.contains (char(), varchar()) ; +-- DROP FUNCTION biors.contains (char(), char()) ; +-- DROP FUNCTION biors.contains (char(), date) ; +-- DROP FUNCTION biors.contains (char(), timestamp) ; +-- DROP FUNCTION biors.contains (char(), integer) ; +-- DROP FUNCTION biors.contains (char(), smallint) ; +-- DROP FUNCTION biors.contains (char(), bigint) ; +-- DROP FUNCTION biors.contains (char(), decimal) ; +-- DROP FUNCTION biors.contains (char(), double) ; +-- DROP FUNCTION biors.contains (char(), real) ; +-- DROP FUNCTION biors.contains (clob, varchar()) ; +-- DROP FUNCTION biors.contains (clob, char()) ; +-- DROP FUNCTION biors.contains (clob, date) ; +-- DROP FUNCTION biors.contains (clob, timestamp) ; +-- DROP FUNCTION biors.contains (clob, integer) ; +-- DROP FUNCTION biors.contains (clob, smallint) ; +-- DROP FUNCTION biors.contains (clob, bigint) ; +-- DROP FUNCTION biors.contains (clob, decimal) ; +-- DROP FUNCTION biors.contains (clob, double) ; +-- DROP FUNCTION biors.contains (clob, real) ; + +CREATE FUNCTION biors.contains (varchar(), varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (varchar(), char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (varchar(), date) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (varchar(), timestamp) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (varchar(), integer) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (varchar(), smallint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (varchar(), bigint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (varchar(), decimal) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (varchar(), double) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (varchar(), real) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), date) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), timestamp) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), integer) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), smallint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), bigint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), decimal) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), double) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (char(), real) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, date) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, timestamp) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, integer) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, smallint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, bigint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, decimal) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, double) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains (clob, real) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; + +-- DROP FUNCTION biors.contains_le (varchar(), varchar()) ; +-- DROP FUNCTION biors.contains_le (varchar(), char()) ; +-- DROP FUNCTION biors.contains_le (varchar(), date) ; +-- DROP FUNCTION biors.contains_le (varchar(), timestamp) ; +-- DROP FUNCTION biors.contains_le (varchar(), integer) ; +-- DROP FUNCTION biors.contains_le (varchar(), smallint) ; +-- DROP FUNCTION biors.contains_le (varchar(), bigint) ; +-- DROP FUNCTION biors.contains_le (varchar(), decimal) ; +-- DROP FUNCTION biors.contains_le (varchar(), double) ; +-- DROP FUNCTION biors.contains_le (varchar(), real) ; +-- DROP FUNCTION biors.contains_le (char(), varchar()) ; +-- DROP FUNCTION biors.contains_le (char(), char()) ; +-- DROP FUNCTION biors.contains_le (char(), date) ; +-- DROP FUNCTION biors.contains_le (char(), timestamp) ; +-- DROP FUNCTION biors.contains_le (char(), integer) ; +-- DROP FUNCTION biors.contains_le (char(), smallint) ; +-- DROP FUNCTION biors.contains_le (char(), bigint) ; +-- DROP FUNCTION biors.contains_le (char(), decimal) ; +-- DROP FUNCTION biors.contains_le (char(), double) ; +-- DROP FUNCTION biors.contains_le (char(), real) ; +-- DROP FUNCTION biors.contains_le (clob, varchar()) ; +-- DROP FUNCTION biors.contains_le (clob, char()) ; +-- DROP FUNCTION biors.contains_le (clob, date) ; +-- DROP FUNCTION biors.contains_le (clob, timestamp) ; +-- DROP FUNCTION biors.contains_le (clob, integer) ; +-- DROP FUNCTION biors.contains_le (clob, smallint) ; +-- DROP FUNCTION biors.contains_le (clob, bigint) ; +-- DROP FUNCTION biors.contains_le (clob, decimal) ; +-- DROP FUNCTION biors.contains_le (clob, double) ; +-- DROP FUNCTION biors.contains_le (clob, real) ; + +CREATE FUNCTION biors.contains_le (varchar(), varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (varchar(), char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (varchar(), date) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (varchar(), timestamp) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (varchar(), integer) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (varchar(), smallint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (varchar(), bigint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (varchar(), decimal) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (varchar(), double) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (varchar(), real) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), date) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), timestamp) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), integer) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), smallint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), bigint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), decimal) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), double) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (char(), real) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, date) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, timestamp) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, integer) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, smallint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, bigint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, decimal) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, double) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_le (clob, real) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; + +-- DROP FUNCTION biors.contains_ge (varchar(), varchar()) ; +-- DROP FUNCTION biors.contains_ge (varchar(), char()) ; +-- DROP FUNCTION biors.contains_ge (varchar(), date) ; +-- DROP FUNCTION biors.contains_ge (varchar(), timestamp) ; +-- DROP FUNCTION biors.contains_ge (varchar(), integer) ; +-- DROP FUNCTION biors.contains_ge (varchar(), smallint) ; +-- DROP FUNCTION biors.contains_ge (varchar(), bigint) ; +-- DROP FUNCTION biors.contains_ge (varchar(), decimal) ; +-- DROP FUNCTION biors.contains_ge (varchar(), double) ; +-- DROP FUNCTION biors.contains_ge (varchar(), real) ; +-- DROP FUNCTION biors.contains_ge (char(), varchar()) ; +-- DROP FUNCTION biors.contains_ge (char(), char()) ; +-- DROP FUNCTION biors.contains_ge (char(), date) ; +-- DROP FUNCTION biors.contains_ge (char(), timestamp) ; +-- DROP FUNCTION biors.contains_ge (char(), integer) ; +-- DROP FUNCTION biors.contains_ge (char(), smallint) ; +-- DROP FUNCTION biors.contains_ge (char(), bigint) ; +-- DROP FUNCTION biors.contains_ge (char(), decimal) ; +-- DROP FUNCTION biors.contains_ge (char(), double) ; +-- DROP FUNCTION biors.contains_ge (char(), real) ; +-- DROP FUNCTION biors.contains_ge (clob, varchar()) ; +-- DROP FUNCTION biors.contains_ge (clob, char()) ; +-- DROP FUNCTION biors.contains_ge (clob, date) ; +-- DROP FUNCTION biors.contains_ge (clob, timestamp) ; +-- DROP FUNCTION biors.contains_ge (clob, integer) ; +-- DROP FUNCTION biors.contains_ge (clob, smallint) ; +-- DROP FUNCTION biors.contains_ge (clob, bigint) ; +-- DROP FUNCTION biors.contains_ge (clob, decimal) ; +-- DROP FUNCTION biors.contains_ge (clob, double) ; +-- DROP FUNCTION biors.contains_ge (clob, real) ; + +CREATE FUNCTION biors.contains_ge (varchar(), varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (varchar(), char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (varchar(), date) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (varchar(), timestamp) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (varchar(), integer) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (varchar(), smallint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (varchar(), bigint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (varchar(), decimal) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (varchar(), double) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (varchar(), real) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), date) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), timestamp) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), integer) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), smallint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), bigint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), decimal) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), double) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (char(), real) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, date) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, timestamp) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, integer) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, smallint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, bigint) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, decimal) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, double) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.contains_ge (clob, real) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; + +-- DROP FUNCTION biors.search_term (varchar(), varchar()) ; +-- DROP FUNCTION biors.search_term (varchar(), char()) ; +-- DROP FUNCTION biors.search_term (char(), varchar ()) ; +-- DROP FUNCTION biors.search_term (char(), char ()) ; + +CREATE FUNCTION biors.search_term (varchar(), varchar()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.search_term (varchar(), char()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.search_term (char(), varchar ()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; +CREATE FUNCTION biors.search_term (char(), char ()) RETURNS INTEGER AS TEMPLATE DETERMINISTIC NO EXTERNAL ACTION; diff --git a/lifesci/script/create_function_mappings.ddl b/lifesci/script/create_function_mappings.ddl new file mode 100644 index 0000000..435bd5c --- /dev/null +++ b/lifesci/script/create_function_mappings.ddl @@ -0,0 +1,38 @@ +------------------------------------------------------------------------------- +-- +-- Source File Name: create_function_mappings.ddl +-- +-- (C) COPYRIGHT International Business Machines Corp. 2002, 2003 +-- All Rights Reserved +-- Licensed Materials - Property of IBM +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +-- +-- Function = Data Definition Language file containing +-- Function template declarations for Script wrapper +-- custom functions. +-- +-- Operating System: All +-- +------------------------------------------------------------------------------- + +CREATE FUNCTION lsscript.args (varchar(), varchar()) + RETURNS INTEGER AS TEMPLATE + DETERMINISTIC NO EXTERNAL ACTION; + +CREATE FUNCTION lsscript.args (CLOB(), CLOB()) + RETURNS INTEGER AS TEMPLATE + DETERMINISTIC NO EXTERNAL ACTION; + +CREATE FUNCTION lsscript.args (double, double) + RETURNS INTEGER AS TEMPLATE + DETERMINISTIC NO EXTERNAL ACTION; + +CREATE FUNCTION lsscript.args (date, date) + RETURNS INTEGER AS TEMPLATE + DETERMINISTIC NO EXTERNAL ACTION; + +CREATE FUNCTION lsscript.args (integer, integer) + RETURNS INTEGER AS TEMPLATE + DETERMINISTIC NO EXTERNAL ACTION; diff --git a/pd/db2_hang_analyze b/pd/db2_hang_analyze new file mode 100755 index 0000000..a6b9b45 --- /dev/null +++ b/pd/db2_hang_analyze @@ -0,0 +1,2621 @@ +#!/usr/bin/perl + +# -*-Perl-*- +# vim: ft=perl + +eval 'exec perl5 -w -S $0 ${1+"$@"}' + if 0 ; + +############################################################################# +# +# (C) COPYRIGHT International Business Machines Corp. 1994, 2002 +# All Rights Reserved +# +# US Government Users Restricted Rights - Use, duplication or +# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# +################################ db2_hang_analyze ############################ +# +# db2_hang_analyze is a Perl script that is used to detect possible hangs on DB2 by +# checking various metrics gathered from db2pd. For example, an active database +# might unexpectedly crash without exiting or generating any error messages, +# causing an application level hang. While this is happening, a user executes a +# query to the database but the execution does not complete because of the hang. +# The user might suspect that a hang has occurred but it might as well be that +# the query just takes a long time to execute, which is the case with queries +# that involve Cartesian products on large tables. Now, the user is faced with +# the decision of either restarting the database, which will bring down the +# system, or waiting for the execution to complete, which might take hours in +# some cases. In either case, this decision is more complex when it comes to +# more complicated system where clients are accessing the database around the +# clock and when the system is executing more than just simple queries. +# +# With the db2_hang_analyze script, possible hangs are flagged and the database +# administrator can make better decisions in how to remediate the system. When +# the script is running in the background, metrics on each active applications +# are gathered in each iterations, which the database administrator can set to +# a particular time interval sleeptime. +# +# To get the help screen, run: db2_hang_analyze -h +# +# DESCRIPTION +# The db2_hang_analyze script is used to detect possible application hanging in +# DB2. It runs in a loop until a hang is detected, upon which the list of +# possible applications hanging is dumped into report file. +# +# SYNOPSIS +# db2_hang_analyze [-h] +# db2_hang_analyze [-list] +# db2_hang_analyze -db DBNAME [-member MEMBERNUMBER] [-timerlimit SECONDS] +# [-sleeptime SECONDS] [-retrylimit ATTEMPTS] [-path PATH] +# [-cputhreshold PERCENTAGE] [-exec PATH] [-log] [-sql] +# +# REQUIRED: +# -db +# Specifies the database for which to detect hangs. +# +# OPTIONAL: +# -member +# The member partition number of the database. This option is ignored +# if the instance is configured as serial mode. +# Default: If defined, the value of environment variable DB2NODE, +# else use the db2pd default +# +# -timerlimit +# Time limit an application can be idle (no change in the counters) +# Default: 300 (seconds) +# +# -sleeptime +# The sleeptime between each iteration of hang detect. +# Default: 60 (seconds) +# +# -retrylimit +# Retry limit for any db2pd timeout or failures. +# Default: 3 +# +# -path +# Path where the report file and logfile will be stored. +# Default: DIAGPATH +# +# -cputhreshold +# Set the threshold of the percentage change in the application +# CPU time. If an application exceeds such threshold, then it is +# flagged as active. +# Default: 0.1 (= 0.1%) +# +# -exec + + +All Classes +
+ + + + + +
ActivateSubscriptionMsg +
+AddColumnMsg +
+Column +
+ColumnSchema +
+ControlMsg +
+DataMsg +
+DeactivateSubscriptionMsg +
+ErrorReportMsg +
+HeartbeatMsg +
+InformationalMsg +
+InvalidateSendQueueMsg +
+LoadDoneControlMsg +
+LoadDoneReceivedMsg +
+LOBMsg +
+Msg +
+PublicationMsgListener +
+PublicationMsgProvider +
+PublicationMsgProviderFactory +
+Row +
+RowOperationMsg +
+SubscriptionDeactivatedMsg +
+SubscriptionSchemaMsg +
+TransactionMsg +
+Utils +
+
+ + + diff --git a/repl/xmlpubtk/doc/allclasses-noframe.html b/repl/xmlpubtk/doc/allclasses-noframe.html new file mode 100644 index 0000000..bbc488c --- /dev/null +++ b/repl/xmlpubtk/doc/allclasses-noframe.html @@ -0,0 +1,77 @@ + + + + + + +All Classes + + + + + + +All Classes +
+ + + + + +
ActivateSubscriptionMsg +
+AddColumnMsg +
+Column +
+ColumnSchema +
+ControlMsg +
+DataMsg +
+DeactivateSubscriptionMsg +
+ErrorReportMsg +
+HeartbeatMsg +
+InformationalMsg +
+InvalidateSendQueueMsg +
+LoadDoneControlMsg +
+LoadDoneReceivedMsg +
+LOBMsg +
+Msg +
+PublicationMsgListener +
+PublicationMsgProvider +
+PublicationMsgProviderFactory +
+Row +
+RowOperationMsg +
+SubscriptionDeactivatedMsg +
+SubscriptionSchemaMsg +
+TransactionMsg +
+Utils +
+
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ActivateSubscriptionMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ActivateSubscriptionMsg.html new file mode 100644 index 0000000..c33faf1 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ActivateSubscriptionMsg.html @@ -0,0 +1,379 @@ + + + + + + +ActivateSubscriptionMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class ActivateSubscriptionMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.ControlMsg
+        |
+        +--com.ibm.db2.tools.repl.publication.ActivateSubscriptionMsg
+
+
+
+
public class ActivateSubscriptionMsg
extends ControlMsg
+ +

+The ActivateSubscriptionMsg sends a message to QCapture asking it to invalidate the send + queue and perform the error action specified in the publication. + +

+ An example of sending a message: +

+

+   try {
+     ControlMsg msg = new ActivateSubscriptionMsg("SubscriptionName");
+     msg.send("QueueMgrName", "AdminQueueName");
+   } catch (Exception e) {
+     System.out.println("Message failed...error " + e);
+   }
+ 
+ This will send a message on the "AdminQueueName" on queue manager "QueueMgrName" to + activate the subscription "SubscriptionName" at the QCapture program. +

+ +

+


+ +

+ + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringsubscriptionName + +
+           
+  + + + + + + + + + + +
+Constructor Summary
ActivateSubscriptionMsg(java.lang.String subscriptionName) + +
+          Craste a new ActivateSubscriptionMsg.
+  + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+protected  voidgenerateXML(java.lang.StringBuffer xmlDocument) + +
+          Actually create the xml.
+ java.lang.StringgetSubscriptionName() + +
+          Get the subscription name.
+ voidsetSubscriptionName(java.lang.String subscriptionName) + +
+          Set the subscription name.
+protected  voidvalidate() + +
+          This will valiadate that everything is present for the xml document to be created.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.ControlMsg
getXML, send, send, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+ActivateSubscriptionMsg

+
+public ActivateSubscriptionMsg(java.lang.String subscriptionName)
+
+
Craste a new ActivateSubscriptionMsg. The message is not sent until the send() message is called. +

+

Parameters:
subscriptionName - The name of the subscription.
+ + + + + + + + +
+Method Detail
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
Get the subscription name. +

+

+ +
Returns:
String The name of the subscription.
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String subscriptionName)
+
+
Set the subscription name. +

+

+
Parameters:
subscriptionName - The name of the subscription to activate.
+
+
+
+ +

+validate

+
+protected void validate()
+                 throws java.lang.Exception
+
+
This will valiadate that everything is present for the xml document to be created. It + will throw an exception if something is not valid. +

+

+
Overrides:
validate in class ControlMsg
+
+
+ +
java.lang.Exception
+
+
+
+ +

+generateXML

+
+protected void generateXML(java.lang.StringBuffer xmlDocument)
+
+
Actually create the xml. +

+

+
Overrides:
generateXML in class ControlMsg
+
+
+
Parameters:
xmlDocument - Generate the xml here.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/AddColumnMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/AddColumnMsg.html new file mode 100644 index 0000000..20ff74d --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/AddColumnMsg.html @@ -0,0 +1,505 @@ + + + + + + +AddColumnMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class AddColumnMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.InformationalMsg
+              |
+              +--com.ibm.db2.tools.repl.publication.AddColumnMsg
+
+
+
+
public class AddColumnMsg
extends InformationalMsg
+ +

+The AddColumnMsg is sent when the Q Capture programs add a column to an existing XML Publication. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  ColumnSchemacolumn + +
+           
+protected  java.lang.StringsrcName + +
+           
+protected  java.lang.StringsrcOwner + +
+           
+protected  java.lang.StringsubscriptionName + +
+           
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
AddColumnMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ ColumnSchemagetColumn() + +
+          Returns the column that was added to the publication.
+ java.lang.StringgetSrcName() + +
+          Returns the name of the source db object (table, view, etc...).
+ java.lang.StringgetSrcOwner() + +
+          Returns the owner of the source db object (table, view, etc...).
+ java.lang.StringgetSubscriptionName() + +
+          Returns the name of the XML Publication.
+ voidsetColumn(ColumnSchema column) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcOwner(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSubscriptionName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+
+ +

+srcOwner

+
+protected java.lang.String srcOwner
+
+
+
+
+
+ +

+srcName

+
+protected java.lang.String srcName
+
+
+
+
+
+ +

+column

+
+protected ColumnSchema column
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+AddColumnMsg

+
+public AddColumnMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getColumn

+
+public ColumnSchema getColumn()
+
+
Returns the column that was added to the publication. +

+

+ +
Returns:
ColumnSchema The column that was added to the publication.
+
+
+
+ +

+getSrcName

+
+public java.lang.String getSrcName()
+
+
Returns the name of the source db object (table, view, etc...). +

+

+ +
Returns:
String The source name.
+
+
+
+ +

+getSrcOwner

+
+public java.lang.String getSrcOwner()
+
+
Returns the owner of the source db object (table, view, etc...). +

+

+ +
Returns:
String The owner name.
+
+
+
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
Returns the name of the XML Publication. +

+

+ +
Returns:
String The publication name.
+
+
+
+ +

+setColumn

+
+public void setColumn(ColumnSchema column)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
column -
+
+
+
+ +

+setSrcName

+
+public void setSrcName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSrcOwner

+
+public void setSrcOwner(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Column.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Column.html new file mode 100644 index 0000000..fd3f350 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Column.html @@ -0,0 +1,570 @@ + + + + + + +Column + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class Column

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Column
+
+
+
+
public class Column
extends java.lang.Object
+ +

+The Column class represents an actual value of a column for a specific row. The Column + contains the value after the update, and may optionally also contain the pre-update value (called + the "before" value). +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.ObjectbeforeValue + +
+           
+protected  booleanbeforeValuePresent + +
+           
+protected  booleankey + +
+           
+protected  java.lang.Stringname + +
+           
+protected  java.lang.Objectvalue + +
+           
+  + + + + + + + + + + +
+Constructor Summary
Column() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.lang.ObjectgetBeforeValue() + +
+          Returns the original value of the column, before it was updated.
+ java.lang.StringgetName() + +
+          Returns the name of the column.
+ java.lang.ObjectgetValue() + +
+          Returns the value of the column.
+ booleanisBeforeValuePresent() + +
+          Returns true if the original value of the column is present.
+ booleanisKey() + +
+          Returns true if the column is a key column.
+ voidsetBeforeValue(java.lang.Object object) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetBeforeValuePresent(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetKey(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetValue(java.lang.Object object) + +
+          This method has no effect when used by a PublicationListener.
+ java.lang.StringtoString() + +
+           
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+name

+
+protected java.lang.String name
+
+
+
+
+
+ +

+key

+
+protected boolean key
+
+
+
+
+
+ +

+beforeValuePresent

+
+protected boolean beforeValuePresent
+
+
+
+
+
+ +

+value

+
+protected java.lang.Object value
+
+
+
+
+
+ +

+beforeValue

+
+protected java.lang.Object beforeValue
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+Column

+
+public Column()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getName

+
+public java.lang.String getName()
+
+
Returns the name of the column. +

+

+ +
Returns:
String The column name.
+
+
+
+ +

+isKey

+
+public boolean isKey()
+
+
Returns true if the column is a key column. +

+

+ +
Returns:
boolean True: The column is a key column. False: The column is not part of a key.
+
+
+
+ +

+getBeforeValue

+
+public java.lang.Object getBeforeValue()
+
+
Returns the original value of the column, before it was updated. This is optional when + the publication is defined. +

+

+ +
Returns:
Object The original value of the column. Null if not available.
+
+
+
+ +

+isBeforeValuePresent

+
+public boolean isBeforeValuePresent()
+
+
Returns true if the original value of the column is present. This is optional when + the publication is defined. +

+

+ +
Returns:
boolean True: The original value is present.
+
+
+
+ +

+getValue

+
+public java.lang.Object getValue()
+
+
Returns the value of the column. +

+

+ +
Returns:
Object The column value.
+
+
+
+ +

+setKey

+
+public void setKey(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setName

+
+public void setName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setBeforeValue

+
+public void setBeforeValue(java.lang.Object object)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
object -
+
+
+
+ +

+setBeforeValuePresent

+
+public void setBeforeValuePresent(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setValue

+
+public void setValue(java.lang.Object object)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
object -
+
+
+
+ +

+toString

+
+public java.lang.String toString()
+
+
+
Overrides:
toString in class java.lang.Object
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ColumnSchema.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ColumnSchema.html new file mode 100644 index 0000000..0f704ad --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ColumnSchema.html @@ -0,0 +1,718 @@ + + + + + + +ColumnSchema + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class ColumnSchema

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.ColumnSchema
+
+
+
+
public class ColumnSchema
extends java.lang.Object
+ +

+The ColumnSchema class reprenents a column defintion in a table. These objects are used in the + SubscriptionSchemaMsg and the AddColumnSchemaMsg. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  intcodepage + +
+           
+protected  booleankey + +
+           
+protected  intlength + +
+           
+protected  java.lang.Stringname + +
+           
+protected  intprecision + +
+           
+protected  intscale + +
+           
+protected  java.lang.Stringtype + +
+           
+  + + + + + + + + + + +
+Constructor Summary
ColumnSchema() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ intgetCodepage() + +
+          Returns the codepage of the column.
+ intgetJDBCType() + +
+          Returns the datatype of the column as a JDBC type.
+ intgetLength() + +
+          Returns the length of the column.
+ java.lang.StringgetName() + +
+          Returns the name of the column.
+ intgetPrecision() + +
+          Returns the precision of the column.
+ intgetScale() + +
+          Returns the scale of the column.
+ java.lang.StringgetType() + +
+          Returns the datatype of the column.
+ booleanisKey() + +
+          Returns true if the column is a key column.
+ voidsetCodepage(int i) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetKey(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetLength(int i) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetPrecision(int i) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetScale(int i) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetType(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ java.lang.StringtoString() + +
+          Override so we can print the values in a nice textual format.
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+name

+
+protected java.lang.String name
+
+
+
+
+
+ +

+type

+
+protected java.lang.String type
+
+
+
+
+
+ +

+length

+
+protected int length
+
+
+
+
+
+ +

+precision

+
+protected int precision
+
+
+
+
+
+ +

+scale

+
+protected int scale
+
+
+
+
+
+ +

+codepage

+
+protected int codepage
+
+
+
+
+
+ +

+key

+
+protected boolean key
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+ColumnSchema

+
+public ColumnSchema()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getCodepage

+
+public int getCodepage()
+
+
Returns the codepage of the column. If the column does not have a codepage, like an + integer column, this returns 0. +

+

+ +
Returns:
int The codepage of the column, or 0 if not valid.
+
+
+
+ +

+isKey

+
+public boolean isKey()
+
+
Returns true if the column is a key column. +

+

+ +
Returns:
boolean True: The column is a key column. False: The column is not part of a key.
+
+
+
+ +

+getLength

+
+public int getLength()
+
+
Returns the length of the column. If the column does not have a length, like an + integer column, this returns 0. +

+

+ +
Returns:
int The length of the column, or 0 if not valid.
+
+
+
+ +

+getName

+
+public java.lang.String getName()
+
+
Returns the name of the column. +

+

+ +
Returns:
String The column name.
+
+
+
+ +

+getPrecision

+
+public int getPrecision()
+
+
Returns the precision of the column. If the column does not have a precision, like an + integer column, this returns 0. +

+

+ +
Returns:
int The precision of the column, or 0 if not valid.
+
+
+
+ +

+getScale

+
+public int getScale()
+
+
Returns the scale of the column. If the column does not have a scale, like an + integer column, this returns 0. +

+

+ +
Returns:
int The scale of the column, or 0 if not valid.
+
+
+
+ +

+getType

+
+public java.lang.String getType()
+
+
Returns the datatype of the column. +

+

+ +
Returns:
String The datatype of the column.
+
+
+
+ +

+getJDBCType

+
+public int getJDBCType()
+
+
Returns the datatype of the column as a JDBC type. +

+

+ +
Returns:
int The JDBC datatype of the column.
+
+
+
+ +

+setCodepage

+
+public void setCodepage(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+
+ +

+setKey

+
+public void setKey(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setLength

+
+public void setLength(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+
+ +

+setName

+
+public void setName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setPrecision

+
+public void setPrecision(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+
+ +

+setScale

+
+public void setScale(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+
+ +

+setType

+
+public void setType(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+toString

+
+public java.lang.String toString()
+
+
Override so we can print the values in a nice textual format. +

+

+
Overrides:
toString in class java.lang.Object
+
+
+ +
Returns:
String Formatted output of all the instance variables.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ControlMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ControlMsg.html new file mode 100644 index 0000000..176b2ac --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ControlMsg.html @@ -0,0 +1,381 @@ + + + + + + +ControlMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class ControlMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.ControlMsg
+
+
+
Direct Known Subclasses:
ActivateSubscriptionMsg, DeactivateSubscriptionMsg, InvalidateSendQueueMsg, LoadDoneControlMsg
+
+
+
+
public abstract class ControlMsg
extends java.lang.Object
+ +

+The ControlMsg class represents a message that is sent to a QCapture program. + The message is a request for QCapture to perform a certain operation. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + +
+Constructor Summary
ControlMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+protected  voidgenerateXML(java.lang.StringBuffer xmlDocument) + +
+          Actually create the xml.
+protected  java.lang.StringgetXML() + +
+          This will create the xml document and return it
+ voidsend(javax.jms.Session session, + javax.jms.MessageProducer msgProducer) + +
+          This will send the msg to the + the specified messageProducer (MQ queue).
+ voidsend(java.lang.String qMgrName, + java.lang.String qName) + +
+          This will send the msg to the specified queue manager and queue.
+ java.lang.StringtoString() + +
+          Override so we can print the values in a nice textual format.
+protected  voidvalidate() + +
+          This will valiadate that everything is present for the xml document to be created.
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + + + + +
+Constructor Detail
+ +

+ControlMsg

+
+public ControlMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+send

+
+public void send(javax.jms.Session session,
+                 javax.jms.MessageProducer msgProducer)
+          throws java.lang.Exception
+
+
This will send the msg to the + the specified messageProducer (MQ queue). Nothing is done to the MessageProducer other + than sending the message. An exception is thrown if there is an error. + This is the preferred way of sending a message, since it lets the caller manage the + queue and session. +

+

+
Parameters:
session - The session that was used to create the MessageProducer. Used to create a new + text message.
msgProducer - The message is sent here. +
java.lang.Exception
+
+
+
+ +

+send

+
+public void send(java.lang.String qMgrName,
+                 java.lang.String qName)
+          throws java.lang.Exception
+
+
This will send the msg to the specified queue manager and queue. + A connection to the queue is created, the message sent, and the connection destroyed. + This is very inefficient if there are many control messages to be sent. + An exception is thrown if there is an error. +

+

+ +
java.lang.Exception
+
+
+
+ +

+validate

+
+protected void validate()
+                 throws java.lang.Exception
+
+
This will valiadate that everything is present for the xml document to be created. It + will throw an exception if something is not valid. +

+

+ +
java.lang.Exception
+
+
+
+ +

+getXML

+
+protected java.lang.String getXML()
+
+
This will create the xml document and return it +

+

+ +
Returns:
String The xml document for the message.
+
+
+
+ +

+generateXML

+
+protected void generateXML(java.lang.StringBuffer xmlDocument)
+
+
Actually create the xml. +

+

+
Parameters:
xmlDocument - Generate the xml here.
+
+
+
+ +

+toString

+
+public java.lang.String toString()
+
+
Override so we can print the values in a nice textual format. +

+

+
Overrides:
toString in class java.lang.Object
+
+
+ +
Returns:
String Formatted output of all the instance variables.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/DataMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/DataMsg.html new file mode 100644 index 0000000..8f06689 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/DataMsg.html @@ -0,0 +1,244 @@ + + + + + + +DataMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class DataMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.DataMsg
+
+
+
Direct Known Subclasses:
LOBMsg, RowOperationMsg, TransactionMsg
+
+
+
+
public class DataMsg
extends Msg
+ +

+A DataMsg is a XML Publication message about modified data, relating to a + transaction that updated, inserted, or deleted rows. +

+ +

+


+ +

+ + + + + + + + + + +
+Field Summary
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
DataMsg() + +
+           
+  + + + + + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + + + + +
+Constructor Detail
+ +

+DataMsg

+
+public DataMsg()
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/DeactivateSubscriptionMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/DeactivateSubscriptionMsg.html new file mode 100644 index 0000000..04af298 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/DeactivateSubscriptionMsg.html @@ -0,0 +1,379 @@ + + + + + + +DeactivateSubscriptionMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class DeactivateSubscriptionMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.ControlMsg
+        |
+        +--com.ibm.db2.tools.repl.publication.DeactivateSubscriptionMsg
+
+
+
+
public class DeactivateSubscriptionMsg
extends ControlMsg
+ +

+The DeactivateSubscriptionMsg sends a message to QCapture asking it to invalidate the send + queue and perform the error action specified in the publication. + +

+ An example of sending a message: +

+

+   try {
+     ControlMsg msg = new DeactivateSubscriptionMsg("SubscriptionName");
+     msg.send("QueueMgrName", "AdminQueueName");
+   } catch (Exception e) {
+     System.out.println("Message failed...error " + e);
+   }
+ 
+ This will send a message on the "AdminQueueName" on queue manager "QueueMgrName" to + deactivate the subscription "SubscriptionName" at the QCapture program. +

+ +

+


+ +

+ + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringsubscriptionName + +
+           
+  + + + + + + + + + + +
+Constructor Summary
DeactivateSubscriptionMsg(java.lang.String subscriptionName) + +
+          Create a new DeactivateSubscriptionMsg.
+  + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+protected  voidgenerateXML(java.lang.StringBuffer xmlDocument) + +
+          Actually create the xml.
+ java.lang.StringgetSubscriptionName() + +
+          Get the subscription name.
+ voidsetSubscriptionName(java.lang.String subscriptionName) + +
+          Set the subscription name.
+protected  voidvalidate() + +
+          This will valiadate that everything is present for the xml document to be created.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.ControlMsg
getXML, send, send, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+DeactivateSubscriptionMsg

+
+public DeactivateSubscriptionMsg(java.lang.String subscriptionName)
+
+
Create a new DeactivateSubscriptionMsg. The message is not sent until the send() message is called. +

+

Parameters:
subscriptionName - The name of the subscription.
+ + + + + + + + +
+Method Detail
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
Get the subscription name. +

+

+ +
Returns:
String The name of the subscription.
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String subscriptionName)
+
+
Set the subscription name. +

+

+
Parameters:
subscriptionName - The name of the subscription to activate.
+
+
+
+ +

+validate

+
+protected void validate()
+                 throws java.lang.Exception
+
+
This will valiadate that everything is present for the xml document to be created. It + will throw an exception if something is not valid. +

+

+
Overrides:
validate in class ControlMsg
+
+
+ +
java.lang.Exception
+
+
+
+ +

+generateXML

+
+protected void generateXML(java.lang.StringBuffer xmlDocument)
+
+
Actually create the xml. +

+

+
Overrides:
generateXML in class ControlMsg
+
+
+
Parameters:
xmlDocument - Generate the xml here.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ErrorReportMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ErrorReportMsg.html new file mode 100644 index 0000000..9b5bbfe --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/ErrorReportMsg.html @@ -0,0 +1,507 @@ + + + + + + +ErrorReportMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class ErrorReportMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.InformationalMsg
+              |
+              +--com.ibm.db2.tools.repl.publication.ErrorReportMsg
+
+
+
+
public class ErrorReportMsg
extends InformationalMsg
+ +

+The QCapture program sends an ErrorReportMsg when it cannot perform the request of + a user application that was made through a control message. For example, the Q Capture + programs send an error report message if it cannot activate or deactivate an XML Publication. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringmsgText + +
+           
+protected  java.lang.StringsrcName + +
+           
+protected  java.lang.StringsrcOwner + +
+           
+protected  java.lang.StringsubscriptionName + +
+           
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
ErrorReportMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.lang.StringgetMsgText() + +
+          Returns the text of the error message.
+ java.lang.StringgetSrcName() + +
+          Returns the name of the source db object (table, view, etc...).
+ java.lang.StringgetSrcOwner() + +
+          Returns the owner of the source db object (table, view, etc...).
+ java.lang.StringgetSubscriptionName() + +
+          Returns the name of the XML Publication.
+ voidsetMsgText(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcOwner(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSubscriptionName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+
+ +

+srcOwner

+
+protected java.lang.String srcOwner
+
+
+
+
+
+ +

+srcName

+
+protected java.lang.String srcName
+
+
+
+
+
+ +

+msgText

+
+protected java.lang.String msgText
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+ErrorReportMsg

+
+public ErrorReportMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getMsgText

+
+public java.lang.String getMsgText()
+
+
Returns the text of the error message. +

+

+ +
Returns:
String The text of the error message.
+
+
+
+ +

+getSrcName

+
+public java.lang.String getSrcName()
+
+
Returns the name of the source db object (table, view, etc...). +

+

+ +
Returns:
String The source name.
+
+
+
+ +

+getSrcOwner

+
+public java.lang.String getSrcOwner()
+
+
Returns the owner of the source db object (table, view, etc...). +

+

+ +
Returns:
String The owner name.
+
+
+
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
Returns the name of the XML Publication. +

+

+ +
Returns:
String The publication name.
+
+
+
+ +

+setMsgText

+
+public void setMsgText(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSrcName

+
+public void setSrcName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSrcOwner

+
+public void setSrcOwner(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/HeartbeatMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/HeartbeatMsg.html new file mode 100644 index 0000000..ab10972 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/HeartbeatMsg.html @@ -0,0 +1,388 @@ + + + + + + +HeartbeatMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class HeartbeatMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.InformationalMsg
+              |
+              +--com.ibm.db2.tools.repl.publication.HeartbeatMsg
+
+
+
+
public class HeartbeatMsg
extends InformationalMsg
+ +

+The HeartbeatMsg is sent by the QCapture program to tell that QCapture is still running. The + HeartbeatMsg is optional, and is specified when the capture control tables are defined. + The QCaptupre program puts this msg on the queue when the heartbeat interval is reached, and + no other messages have been put on the queue. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringlastCommitTime + +
+           
+protected  java.lang.StringsendQueueName + +
+           
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
HeartbeatMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.lang.StringgetLastCommitTime() + +
+          The timestamp (in GMT) of the last committed transaction.
+ java.lang.StringgetSendQueueName() + +
+          Returns the name of the send queue (the name of the queue on the capture server) that this + msg was placed.
+ voidsetLastCommitTime(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSendQueueName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+sendQueueName

+
+protected java.lang.String sendQueueName
+
+
+
+
+
+ +

+lastCommitTime

+
+protected java.lang.String lastCommitTime
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+HeartbeatMsg

+
+public HeartbeatMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getLastCommitTime

+
+public java.lang.String getLastCommitTime()
+
+
The timestamp (in GMT) of the last committed transaction. May be null if no committed transactions. +

+

+ +
Returns:
String The timestamp of the last committed transaction (or null if none).
+
+
+
+ +

+getSendQueueName

+
+public java.lang.String getSendQueueName()
+
+
Returns the name of the send queue (the name of the queue on the capture server) that this + msg was placed. +

+

+ +
Returns:
String The send queue name.
+
+
+
+ +

+setLastCommitTime

+
+public void setLastCommitTime(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSendQueueName

+
+public void setSendQueueName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/InformationalMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/InformationalMsg.html new file mode 100644 index 0000000..2986a70 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/InformationalMsg.html @@ -0,0 +1,244 @@ + + + + + + +InformationalMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class InformationalMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.InformationalMsg
+
+
+
Direct Known Subclasses:
AddColumnMsg, ErrorReportMsg, HeartbeatMsg, LoadDoneReceivedMsg, SubscriptionDeactivatedMsg, SubscriptionSchemaMsg
+
+
+
+
public class InformationalMsg
extends Msg
+ +

+An InformationalMsg is a XML Publication message about the status of the QCapture program. + For example, when an XML Publication is deactivated, an SubscriptionDeactivatedMsg is sent. +

+ +

+


+ +

+ + + + + + + + + + +
+Field Summary
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
InformationalMsg() + +
+           
+  + + + + + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + + + + +
+Constructor Detail
+ +

+InformationalMsg

+
+public InformationalMsg()
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/InvalidateSendQueueMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/InvalidateSendQueueMsg.html new file mode 100644 index 0000000..8f4d5e9 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/InvalidateSendQueueMsg.html @@ -0,0 +1,379 @@ + + + + + + +InvalidateSendQueueMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class InvalidateSendQueueMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.ControlMsg
+        |
+        +--com.ibm.db2.tools.repl.publication.InvalidateSendQueueMsg
+
+
+
+
public class InvalidateSendQueueMsg
extends ControlMsg
+ +

+The InvalidateSendQueueMsg sends a message to QCapture asking it to invalidate the send + queue and perform the error action specified in the publication. + +

+ An example of sending a message: +

+

+   try {
+     ControlMsg msg = new InvalidateSendQueueMsg("SendQueueName");
+     msg.send("QueueMgrName", "AdminQueueName");
+   } catch (Exception e) {
+     System.out.println("Message failed...error " + e);
+   }
+ 
+ This will send a message on the "AdminQueueName" on queue manager "QueueMgrName" to + invalidate the "SendQueueName" at the QCapture program. +

+ +

+


+ +

+ + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringqName + +
+           
+  + + + + + + + + + + +
+Constructor Summary
InvalidateSendQueueMsg(java.lang.String qName) + +
+          Craste a new InvalidateSendQueueMsg.
+  + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+protected  voidgenerateXML(java.lang.StringBuffer xmlDocument) + +
+          Actually create the xml.
+ java.lang.StringgetQueueName() + +
+          Get the send queue name.
+ voidsetQueueName(java.lang.String qName) + +
+          Set the send queue name.
+protected  voidvalidate() + +
+          This will valiadate that everything is present for the xml document to be created.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.ControlMsg
getXML, send, send, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+qName

+
+protected java.lang.String qName
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+InvalidateSendQueueMsg

+
+public InvalidateSendQueueMsg(java.lang.String qName)
+
+
Craste a new InvalidateSendQueueMsg. The message is not sent until the send() message is called. +

+

Parameters:
qName - The name of the send queue to invalidate.
+ + + + + + + + +
+Method Detail
+ +

+getQueueName

+
+public java.lang.String getQueueName()
+
+
Get the send queue name. +

+

+ +
Returns:
String The name of the send queue to invalidate.
+
+
+
+ +

+setQueueName

+
+public void setQueueName(java.lang.String qName)
+
+
Set the send queue name. +

+

+
Parameters:
qName - The name of the send queue to invalidate.
+
+
+
+ +

+validate

+
+protected void validate()
+                 throws java.lang.Exception
+
+
This will valiadate that everything is present for the xml document to be created. It + will throw an exception if something is not valid. +

+

+
Overrides:
validate in class ControlMsg
+
+
+ +
java.lang.Exception
+
+
+
+ +

+generateXML

+
+protected void generateXML(java.lang.StringBuffer xmlDocument)
+
+
Actually create the xml. +

+

+
Overrides:
generateXML in class ControlMsg
+
+
+
Parameters:
xmlDocument - Generate the xml here.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LOBMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LOBMsg.html new file mode 100644 index 0000000..9c5a02c --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LOBMsg.html @@ -0,0 +1,867 @@ + + + + + + +LOBMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class LOBMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.DataMsg
+              |
+              +--com.ibm.db2.tools.repl.publication.LOBMsg
+
+
+
+
public class LOBMsg
extends DataMsg
+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringcolumnName + +
+           
+protected  booleanisLast + +
+           
+protected  java.lang.StringlobType + +
+           
+protected  introwNumber + +
+           
+protected  intsegmentLength + +
+           
+protected  java.lang.StringsrcName + +
+           
+protected  java.lang.StringsrcOwner + +
+           
+protected  java.lang.StringsubscriptionName + +
+           
+protected  inttotalDataLength + +
+           
+protected  java.lang.Objectvalue + +
+           
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
LOBMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.lang.StringgetColumnName() + +
+          The name of the LOB column.
+ java.lang.StringgetLobType() + +
+          The datatype of the LOB.
+ intgetRowNumber() + +
+          Within the database transaction, the position number of the row operation that contains the LOB value.
+ intgetSegmentLength() + +
+          The length of the LOB value contained in a single message, in bytes.
+ java.lang.StringgetSrcName() + +
+          Returns the name of the source db object (table, view, etc...).
+ java.lang.StringgetSrcOwner() + +
+          Returns the owner of the source db object (table, view, etc...).
+ java.lang.StringgetSubscriptionName() + +
+          Returns the name of the XML Publication.
+ intgetTotalDataLength() + +
+          The length of the total LOB value contained in the source table, in bytes.
+ java.lang.ObjectgetValue() + +
+          The value of the LOB.
+ booleanisLast() + +
+          If this is the last LOB message, then this is true.
+ voidsetColumnName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetLast(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetLobType(java.lang.String strLobType) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetRowNumber(int i) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSegmentLength(int i) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcOwner(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSubscriptionName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetTotalDataLength(int i) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetValue(java.lang.Object obj) + +
+          This method has no effect when used by a PublicationListener.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+
+ +

+isLast

+
+protected boolean isLast
+
+
+
+
+
+ +

+srcOwner

+
+protected java.lang.String srcOwner
+
+
+
+
+
+ +

+srcName

+
+protected java.lang.String srcName
+
+
+
+
+
+ +

+rowNumber

+
+protected int rowNumber
+
+
+
+
+
+ +

+columnName

+
+protected java.lang.String columnName
+
+
+
+
+
+ +

+totalDataLength

+
+protected int totalDataLength
+
+
+
+
+
+ +

+segmentLength

+
+protected int segmentLength
+
+
+
+
+
+ +

+value

+
+protected java.lang.Object value
+
+
+
+
+
+ +

+lobType

+
+protected java.lang.String lobType
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+LOBMsg

+
+public LOBMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getColumnName

+
+public java.lang.String getColumnName()
+
+
The name of the LOB column. +

+

+ +
Returns:
The name of the column.
+
+
+
+ +

+isLast

+
+public boolean isLast()
+
+
If this is the last LOB message, then this is true. +

+

+ +
Returns:
True: The last LOB message. False : more LOB messages are coming.
+
+
+
+ +

+getLobType

+
+public java.lang.String getLobType()
+
+
The datatype of the LOB. +

+

+ +
Returns:
String One of "blob", "clob", or "dbclob".
+
+
+
+ +

+getValue

+
+public java.lang.Object getValue()
+
+
The value of the LOB. +

+

+ +
Returns:
Object The LOB data.
+
+
+
+ +

+getRowNumber

+
+public int getRowNumber()
+
+
Within the database transaction, the position number of the row operation that contains the LOB value. +

+

+ +
Returns:
int The position number.
+
+
+
+ +

+getSegmentLength

+
+public int getSegmentLength()
+
+
The length of the LOB value contained in a single message, in bytes. +

+

+ +
Returns:
int The number of LOB bytes in just this message.
+
+
+
+ +

+getSrcName

+
+public java.lang.String getSrcName()
+
+
Returns the name of the source db object (table, view, etc...). +

+

+ +
Returns:
String The source name.
+
+
+
+ +

+getSrcOwner

+
+public java.lang.String getSrcOwner()
+
+
Returns the owner of the source db object (table, view, etc...). +

+

+ +
Returns:
String The owner name.
+
+
+
+ +

+getTotalDataLength

+
+public int getTotalDataLength()
+
+
The length of the total LOB value contained in the source table, in bytes. +

+

+ +
Returns:
int The number of bytes of the LOB value.
+
+
+
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
Returns the name of the XML Publication. +

+

+ +
Returns:
String The publication name.
+
+
+
+ +

+setColumnName

+
+public void setColumnName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setLast

+
+public void setLast(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setLobType

+
+public void setLobType(java.lang.String strLobType)
+
+
This method has no effect when used by a PublicationListener. +

+

+
+
+
+
+ +

+setValue

+
+public void setValue(java.lang.Object obj)
+
+
This method has no effect when used by a PublicationListener. +

+

+
+
+
+
+ +

+setRowNumber

+
+public void setRowNumber(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+
+ +

+setSegmentLength

+
+public void setSegmentLength(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+
+ +

+setSrcName

+
+public void setSrcName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSrcOwner

+
+public void setSrcOwner(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setTotalDataLength

+
+public void setTotalDataLength(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LoadDoneControlMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LoadDoneControlMsg.html new file mode 100644 index 0000000..d411235 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LoadDoneControlMsg.html @@ -0,0 +1,379 @@ + + + + + + +LoadDoneControlMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class LoadDoneControlMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.ControlMsg
+        |
+        +--com.ibm.db2.tools.repl.publication.LoadDoneControlMsg
+
+
+
+
public class LoadDoneControlMsg
extends ControlMsg
+ +

+The LoadDoneControlMsg sends a message to QCapture informing it that the target table + is loaded. + +

+ An example of sending a message: +

+

+   try {
+     ControlMsg msg = new LoadDoneControlMsg("SubscriptionName");
+     msg.send("QueueMgrName", "AdminQueueName");
+   } catch (Exception e) {
+     System.out.println("Message failed...error " + e);
+   }
+ 
+ This will send a message on the "AdminQueueName" on queue manager "QueueMgrName" to + tell QCapture that the load is finished for the subscription. +

+ +

+


+ +

+ + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringsubscriptionName + +
+           
+  + + + + + + + + + + +
+Constructor Summary
LoadDoneControlMsg(java.lang.String subscriptionName) + +
+          Craste a new LoadDoneControlMsg.
+  + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+protected  voidgenerateXML(java.lang.StringBuffer xmlDocument) + +
+          Actually create the xml.
+ java.lang.StringgetSubscriptionName() + +
+          Get the subscription name.
+ voidsetSubscriptionName(java.lang.String subscriptionName) + +
+          Set the subscription name.
+protected  voidvalidate() + +
+          This will valiadate that everything is present for the xml document to be created.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.ControlMsg
getXML, send, send, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+LoadDoneControlMsg

+
+public LoadDoneControlMsg(java.lang.String subscriptionName)
+
+
Craste a new LoadDoneControlMsg. The message is not sent until the send() message is called. +

+

Parameters:
subscriptionName - The name of the subscription.
+ + + + + + + + +
+Method Detail
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
Get the subscription name. +

+

+ +
Returns:
String The name of the subscription.
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String subscriptionName)
+
+
Set the subscription name. +

+

+
Parameters:
subscriptionName - The name of the subscription to activate.
+
+
+
+ +

+validate

+
+protected void validate()
+                 throws java.lang.Exception
+
+
This will valiadate that everything is present for the xml document to be created. It + will throw an exception if something is not valid. +

+

+
Overrides:
validate in class ControlMsg
+
+
+ +
java.lang.Exception
+
+
+
+ +

+generateXML

+
+protected void generateXML(java.lang.StringBuffer xmlDocument)
+
+
Actually create the xml. +

+

+
Overrides:
generateXML in class ControlMsg
+
+
+
Parameters:
xmlDocument - Generate the xml here.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LoadDoneReceivedMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LoadDoneReceivedMsg.html new file mode 100644 index 0000000..e97d803 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/LoadDoneReceivedMsg.html @@ -0,0 +1,505 @@ + + + + + + +LoadDoneReceivedMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class LoadDoneReceivedMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.InformationalMsg
+              |
+              +--com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg
+
+
+
+
public class LoadDoneReceivedMsg
extends InformationalMsg
+ +

+The LoadDoneReceivedMsg is sent when the QCapture program receives a LoadDone signal. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringsrcName + +
+           
+protected  java.lang.StringsrcOwner + +
+           
+protected  java.lang.StringstateInformation + +
+           
+protected  java.lang.StringsubscriptionName + +
+           
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
LoadDoneReceivedMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.lang.StringgetSrcName() + +
+          Returns the name of the source db object (table, view, etc...).
+ java.lang.StringgetSrcOwner() + +
+          Returns the owner of the source db object (table, view, etc...).
+ java.lang.StringgetStateInformation() + +
+          Additional information regarding the state of the XML publication.
+ java.lang.StringgetSubscriptionName() + +
+          Returns the name of the XML Publication.
+ voidsetSrcName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcOwner(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetStateInformation(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSubscriptionName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+
+ +

+srcOwner

+
+protected java.lang.String srcOwner
+
+
+
+
+
+ +

+srcName

+
+protected java.lang.String srcName
+
+
+
+
+
+ +

+stateInformation

+
+protected java.lang.String stateInformation
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+LoadDoneReceivedMsg

+
+public LoadDoneReceivedMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getSrcName

+
+public java.lang.String getSrcName()
+
+
Returns the name of the source db object (table, view, etc...). +

+

+ +
Returns:
String The source name.
+
+
+
+ +

+getSrcOwner

+
+public java.lang.String getSrcOwner()
+
+
Returns the owner of the source db object (table, view, etc...). +

+

+ +
Returns:
String The owner name.
+
+
+
+ +

+getStateInformation

+
+public java.lang.String getStateInformation()
+
+
Additional information regarding the state of the XML publication. This may contain an ASN message number. +

+

+ +
Returns:
String Additional information.
+
+
+
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
Returns the name of the XML Publication. +

+

+ +
Returns:
String The publication name.
+
+
+
+ +

+setSrcName

+
+public void setSrcName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSrcOwner

+
+public void setSrcOwner(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setStateInformation

+
+public void setStateInformation(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Msg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Msg.html new file mode 100644 index 0000000..71e810f --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Msg.html @@ -0,0 +1,478 @@ + + + + + + +Msg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class Msg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+
+
+
Direct Known Subclasses:
DataMsg, InformationalMsg
+
+
+
+
public abstract class Msg
extends java.lang.Object
+ +

+The Msg class is the base class for the hierarchy of XML publication messages. + All messages are a subclass of this class. Generally, you need to cast the + object to the correct subclass. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringdbName + +
+           
+protected  javax.jms.MessagejmsMsg + +
+           
+protected static java.lang.StringtopicHeader + +
+           
+  + + + + + + + + + + +
+Constructor Summary
Msg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.lang.StringgetDbName() + +
+          This allows access to the dbName attribute of the xml message
+ javax.jms.MessagegetJMSMessage() + +
+          Access the navite JMS MQ message.
+ java.lang.ObjectgetObjectProperty(java.lang.String propertyName) + +
+          Access a specific property in the native MQ message.
+ java.util.EnumerationgetPropertyNames() + +
+          Access all the property names that are in the native MQ message.
+ java.lang.StringgetTopic(boolean stripHeader) + +
+          Access the name of the topic that was specified during the definition of the xml publication.
+ voidsetDbName(java.lang.String dbName) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetJMSMessage(javax.jms.Message m) + +
+          This method has no effect when used by a PublicationListener.
+ java.lang.StringtoString() + +
+          Override so we can print the values in a nice textual format.
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+topicHeader

+
+protected static final java.lang.String topicHeader
+
+
+
See Also:
Constant Field Values
+
+
+ +

+dbName

+
+protected java.lang.String dbName
+
+
+
+
+
+ +

+jmsMsg

+
+protected javax.jms.Message jmsMsg
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+Msg

+
+public Msg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getDbName

+
+public java.lang.String getDbName()
+
+
This allows access to the dbName attribute of the xml message +

+

+ +
Returns:
String The database name
+
+
+
+ +

+getTopic

+
+public java.lang.String getTopic(boolean stripHeader)
+
+
Access the name of the topic that was specified during the definition of the xml publication. + Note that the topic name in JMS has a header attached. If you want to see the topic string + exactly as it was given when defining the publication, you need to pass "true" so the header + is removed. +

+

+
Parameters:
stripHeader - True: Remove the "topic://" header. False: Return complete JMS topic name +
Returns:
String The name of the topic. Null if not specified.
+
+
+
+ +

+getPropertyNames

+
+public java.util.Enumeration getPropertyNames()
+
+
Access all the property names that are in the native MQ message. +

+

+ +
Returns:
Eumeration A set of all the valid property names.
+
+
+
+ +

+getObjectProperty

+
+public java.lang.Object getObjectProperty(java.lang.String propertyName)
+
+
Access a specific property in the native MQ message. +

+

+ +
Returns:
Object The value of the property, or null if not defined.
+
+
+
+ +

+getJMSMessage

+
+public javax.jms.Message getJMSMessage()
+
+
Access the navite JMS MQ message. +

+

+ +
Returns:
Message The message
+
+
+
+ +

+setDbName

+
+public void setDbName(java.lang.String dbName)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
dbName - The name of the db
+
+
+
+ +

+setJMSMessage

+
+public void setJMSMessage(javax.jms.Message m)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
m - The JMS message
+
+
+
+ +

+toString

+
+public java.lang.String toString()
+
+
Override so we can print the values in a nice textual format. +

+

+
Overrides:
toString in class java.lang.Object
+
+
+ +
Returns:
String Formatted output of all the instance variables.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgListener.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgListener.html new file mode 100644 index 0000000..c578baa --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgListener.html @@ -0,0 +1,206 @@ + + + + + + +PublicationMsgListener + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Interface PublicationMsgListener

+
+
+
public interface PublicationMsgListener
+ +

+A PublicationMsgListener is how a PublicationMsgProvider notifies when a message is received. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ voidpublicationMsg(Msg pubMsg) + +
+          Notify the caller of a publication message.
+  +

+ + + + + + + + + + + + + + +
+Method Detail
+ +

+publicationMsg

+
+public void publicationMsg(Msg pubMsg)
+
+
Notify the caller of a publication message. +

+

+
Parameters:
pubMsg - The message.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgProvider.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgProvider.html new file mode 100644 index 0000000..9dd7505 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgProvider.html @@ -0,0 +1,283 @@ + + + + + + +PublicationMsgProvider + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Interface PublicationMsgProvider

+
+
+
public interface PublicationMsgProvider
+ +

+A PublicationMsgProvider is the interface that defines how messages are created and produced. + The caller creates an instance of a PublicationMsgProvider by using the PublicationMsgProviderFactory + class. Once you have an instance, then add a listener to the provider and call dispatchMsgs. + Note that dispatchMsgs is a synchronous call, so you might want to create a new thread + to call dispatchMsgs. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ voidaddPublicationMsgListener(PublicationMsgListener listener) + +
+          Add a listener to get the messages.
+ voiddispatchMsgs(javax.jms.MessageConsumer messageConsumer, + int timeout, + boolean ignoreErrors) + +
+          This will start the messages to be dispatched to any listeners.
+ voidremovePublicationMsgListener(PublicationMsgListener listener) + +
+          Remove a listener.
+ voidstopMsgDispatching() + +
+          This will stop the dispatching of messages, and cause the thread to return from dispatchMsgs().
+  +

+ + + + + + + + + + + + + + +
+Method Detail
+ +

+dispatchMsgs

+
+public void dispatchMsgs(javax.jms.MessageConsumer messageConsumer,
+                         int timeout,
+                         boolean ignoreErrors)
+                  throws java.lang.Exception
+
+
This will start the messages to be dispatched to any listeners. The thread that calls this + function will not return until some other thread calls stopMsgDispatching() or the timeout value + is reached. +

+

+
Parameters:
messageConsumer - Dispatch messages from this JMS message queue.
timeout - The time in milliseconds before the thread returns and stops dispatching msgs.
ignoreErrors - True: Ingore any errors when dispatching & formatting msgs. Any msg + that contains an error will be thrown away. + False: Throw exception on any msg errors. +
java.lang.Exception
+
+
+
+ +

+stopMsgDispatching

+
+public void stopMsgDispatching()
+
+
This will stop the dispatching of messages, and cause the thread to return from dispatchMsgs(). +

+

+
+
+
+
+ +

+addPublicationMsgListener

+
+public void addPublicationMsgListener(PublicationMsgListener listener)
+
+
Add a listener to get the messages. +

+

+
Parameters:
listener - The listener will be notified of all msgs.
+
+
+
+ +

+removePublicationMsgListener

+
+public void removePublicationMsgListener(PublicationMsgListener listener)
+
+
Remove a listener. +

+

+
Parameters:
listener - The listener to remove.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgProviderFactory.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgProviderFactory.html new file mode 100644 index 0000000..6ea3c80 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/PublicationMsgProviderFactory.html @@ -0,0 +1,252 @@ + + + + + + +PublicationMsgProviderFactory + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class PublicationMsgProviderFactory

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.PublicationMsgProviderFactory
+
+
+
+
public class PublicationMsgProviderFactory
extends java.lang.Object
+ +

+The PublicationMsgProviderFactory class is used to create a default implmenentation of + a PublicationMsgProvider. Once you create a provider, you need to add a PublicationListener + and call "dispatchMsgs" to start the messages. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + +
+Constructor Summary
PublicationMsgProviderFactory() + +
+           
+  + + + + + + + + + + + +
+Method Summary
+static PublicationMsgProvidercreatePublicationMsgProvider() + +
+          This will create a default message provider.
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
+  +

+ + + + + + + + + + + +
+Constructor Detail
+ +

+PublicationMsgProviderFactory

+
+public PublicationMsgProviderFactory()
+
+
+ + + + + + + + +
+Method Detail
+ +

+createPublicationMsgProvider

+
+public static PublicationMsgProvider createPublicationMsgProvider()
+                                                           throws java.lang.Exception
+
+
This will create a default message provider. +

+

+ +
Returns:
PublicationMsgProvider The default provider. +
java.lang.Exception
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Row.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Row.html new file mode 100644 index 0000000..e30af22 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Row.html @@ -0,0 +1,747 @@ + + + + + + +Row + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class Row

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Row
+
+
+
+
public class Row
extends java.lang.Object
+ +

+The Row class reprenents one row that was published. The getOperation() method on the row allows + the caller to find out what happened to the row (Insert, Update, or Delete). The all the + actual data values are stored in the columns, which are retrieved via the "getColumns()" method. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.util.Vectorcolumns + +
+           
+static intDeleteOperation + +
+           
+protected  booleanhasLOBColumns + +
+           
+static intInsertOperation + +
+           
+protected  introwNumber + +
+           
+protected  introwOperation + +
+           
+protected  java.lang.StringsrcName + +
+           
+protected  java.lang.StringsrcOwner + +
+           
+protected  java.lang.StringsubscriptionName + +
+           
+static intUpdateOperation + +
+           
+  + + + + + + + + + + +
+Constructor Summary
Row() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.util.VectorgetColumns() + +
+          Fetch all the columns that are a part of this row.
+ intgetRowNumber() + +
+          Return the row number.
+ intgetRowOperation() + +
+          This is how the row was used in the transaction.
+ java.lang.StringgetSrcName() + +
+          The name of the source table.
+ java.lang.StringgetSrcOwner() + +
+          The owner name of the source table.
+ java.lang.StringgetSubscriptionName() + +
+          The subscription name.
+ booleanhasLOBColumns() + +
+          Does this row have any LOB columns?
+ voidsetColumns(java.util.Vector vector) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetHasLOBColumns(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetRowNumber(int i) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetRowOperation(int i) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcOwner(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSubscriptionName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ java.lang.StringtoString() + +
+          Override so we can print the values in a nice textual format.
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+InsertOperation

+
+public static final int InsertOperation
+
+
+
See Also:
Constant Field Values
+
+
+ +

+DeleteOperation

+
+public static final int DeleteOperation
+
+
+
See Also:
Constant Field Values
+
+
+ +

+UpdateOperation

+
+public static final int UpdateOperation
+
+
+
See Also:
Constant Field Values
+
+
+ +

+srcOwner

+
+protected java.lang.String srcOwner
+
+
+
+
+
+ +

+srcName

+
+protected java.lang.String srcName
+
+
+
+
+
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+
+ +

+rowNumber

+
+protected int rowNumber
+
+
+
+
+
+ +

+hasLOBColumns

+
+protected boolean hasLOBColumns
+
+
+
+
+
+ +

+columns

+
+protected java.util.Vector columns
+
+
+
+
+
+ +

+rowOperation

+
+protected int rowOperation
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+Row

+
+public Row()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getColumns

+
+public java.util.Vector getColumns()
+
+
Fetch all the columns that are a part of this row. +

+

+ +
Returns:
Vector A vector of Column objects.
+
+
+
+ +

+hasLOBColumns

+
+public boolean hasLOBColumns()
+
+
Does this row have any LOB columns? +

+

+ +
Returns:
boolean true: has lob columns. false: does not.
+
+
+
+ +

+getRowNumber

+
+public int getRowNumber()
+
+
Return the row number. +

+

+ +
Returns:
int The row number.
+
+
+
+ +

+getRowOperation

+
+public int getRowOperation()
+
+
This is how the row was used in the transaction. +

+

+ +
Returns:
int One of the following values: InsertOperation, DeleteOperation, UpdateOperation.
+
+
+
+ +

+getSrcName

+
+public java.lang.String getSrcName()
+
+
The name of the source table. +

+

+ +
Returns:
String Source table name
+
+
+
+ +

+getSrcOwner

+
+public java.lang.String getSrcOwner()
+
+
The owner name of the source table. +

+

+ +
Returns:
String Source owner name
+
+
+
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
The subscription name. +

+

+ +
Returns:
String Subscription name
+
+
+
+ +

+setColumns

+
+public void setColumns(java.util.Vector vector)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
vector -
+
+
+
+ +

+setHasLOBColumns

+
+public void setHasLOBColumns(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setRowNumber

+
+public void setRowNumber(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+
+ +

+setRowOperation

+
+public void setRowOperation(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+
+ +

+setSrcName

+
+public void setSrcName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSrcOwner

+
+public void setSrcOwner(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+toString

+
+public java.lang.String toString()
+
+
Override so we can print the values in a nice textual format. +

+

+
Overrides:
toString in class java.lang.Object
+
+
+ +
Returns:
String Formatted output of all the instance variables.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/RowOperationMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/RowOperationMsg.html new file mode 100644 index 0000000..c5e1342 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/RowOperationMsg.html @@ -0,0 +1,692 @@ + + + + + + +RowOperationMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class RowOperationMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.DataMsg
+              |
+              +--com.ibm.db2.tools.repl.publication.RowOperationMsg
+
+
+
+
public class RowOperationMsg
extends DataMsg
+ +

+A RowOperationMsg contains one insert, update, or delete operation from the source table. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringauthID + +
+           
+protected  java.lang.StringcommitLSN + +
+           
+protected  java.lang.StringcommitTime + +
+           
+protected  java.lang.StringcorrelationID + +
+           
+protected  booleanisLast + +
+           
+protected  java.lang.StringplanName + +
+           
+protected  Rowrow + +
+           
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
RowOperationMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.lang.StringgetAuthID() + +
+          Get the authorization id that caused the database modification.
+ java.lang.StringgetCommitLSN() + +
+          The Commit Logical Sequence Number of the transaction.
+ java.lang.StringgetCommitTime() + +
+          The timestamp of the commit statement using GMT.
+ java.lang.StringgetCorrelationID() + +
+          Get the correlation id that caused the database modification (DB2 z/OS only).
+ java.lang.StringgetPlanName() + +
+          Get the plan name that caused the database modification (DB2 z/OS only).
+ RowgetRow() + +
+          Get the updated row.
+ booleanisLast() + +
+          A boolean value that indicates if this message is the last message in the transaction.
+ voidsetAuthID(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetCommitLSN(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetCommitTime(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetCorrelationID(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetLast(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetPlanName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetRow(Row aRow) + +
+          This method has no effect when used by a PublicationListener.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+isLast

+
+protected boolean isLast
+
+
+
+
+
+ +

+commitLSN

+
+protected java.lang.String commitLSN
+
+
+
+
+
+ +

+commitTime

+
+protected java.lang.String commitTime
+
+
+
+
+
+ +

+authID

+
+protected java.lang.String authID
+
+
+
+
+
+ +

+correlationID

+
+protected java.lang.String correlationID
+
+
+
+
+
+ +

+planName

+
+protected java.lang.String planName
+
+
+
+
+
+ +

+row

+
+protected Row row
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+RowOperationMsg

+
+public RowOperationMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getCommitLSN

+
+public java.lang.String getCommitLSN()
+
+
The Commit Logical Sequence Number of the transaction. +

+

+ +
Returns:
String The LSN of the transaction.
+
+
+
+ +

+getCommitTime

+
+public java.lang.String getCommitTime()
+
+
The timestamp of the commit statement using GMT. +

+

+ +
Returns:
String The commit timestamp.
+
+
+
+ +

+getAuthID

+
+public java.lang.String getAuthID()
+
+
Get the authorization id that caused the database modification. This + may be null if not avaiable from the datasource. +

+

+ +
Returns:
String The authorization ID, or null if not available.
+
+
+
+ +

+getCorrelationID

+
+public java.lang.String getCorrelationID()
+
+
Get the correlation id that caused the database modification (DB2 z/OS only). This + may be null if not avaiable from the datasource. +

+

+ +
Returns:
String The correlation ID, or null if not available.
+
+
+
+ +

+getPlanName

+
+public java.lang.String getPlanName()
+
+
Get the plan name that caused the database modification (DB2 z/OS only). This + may be null if not avaiable from the datasource. +

+

+ +
Returns:
String The plan name, or null if not available.
+
+
+
+ +

+isLast

+
+public boolean isLast()
+
+
A boolean value that indicates if this message is the last message in the transaction. If + LOB messages are following, this is false. +

+

+ +
Returns:
boolean True : This is the last message. False : other messages (LOBMsg) are following.
+
+
+
+ +

+getRow

+
+public Row getRow()
+
+
Get the updated row. +

+

+ +
Returns:
Row The updated row.
+
+
+
+ +

+setCommitLSN

+
+public void setCommitLSN(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setAuthID

+
+public void setAuthID(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setCorrelationID

+
+public void setCorrelationID(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setPlanName

+
+public void setPlanName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setCommitTime

+
+public void setCommitTime(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setLast

+
+public void setLast(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setRow

+
+public void setRow(Row aRow)
+
+
This method has no effect when used by a PublicationListener. +

+

+
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/SubscriptionDeactivatedMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/SubscriptionDeactivatedMsg.html new file mode 100644 index 0000000..934b81b --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/SubscriptionDeactivatedMsg.html @@ -0,0 +1,505 @@ + + + + + + +SubscriptionDeactivatedMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class SubscriptionDeactivatedMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.InformationalMsg
+              |
+              +--com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg
+
+
+
+
public class SubscriptionDeactivatedMsg
extends InformationalMsg
+ +

+This message is sent whenever QCapture deactivates an XML Publication. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringsrcName + +
+           
+protected  java.lang.StringsrcOwner + +
+           
+protected  java.lang.StringstateInformation + +
+           
+protected  java.lang.StringsubscriptionName + +
+           
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
SubscriptionDeactivatedMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.lang.StringgetSrcName() + +
+          Returns the name of the source db object (table, view, etc...).
+ java.lang.StringgetSrcOwner() + +
+          Returns the owner of the source db object (table, view, etc...).
+ java.lang.StringgetStateInformation() + +
+          Additional information regarding the state of the XML publication.
+ java.lang.StringgetSubscriptionName() + +
+          Returns the name of the XML Publication.
+ voidsetSrcName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcOwner(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetStateInformation(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSubscriptionName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+
+ +

+srcOwner

+
+protected java.lang.String srcOwner
+
+
+
+
+
+ +

+srcName

+
+protected java.lang.String srcName
+
+
+
+
+
+ +

+stateInformation

+
+protected java.lang.String stateInformation
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+SubscriptionDeactivatedMsg

+
+public SubscriptionDeactivatedMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getSrcName

+
+public java.lang.String getSrcName()
+
+
Returns the name of the source db object (table, view, etc...). +

+

+ +
Returns:
String The source name.
+
+
+
+ +

+getSrcOwner

+
+public java.lang.String getSrcOwner()
+
+
Returns the owner of the source db object (table, view, etc...). +

+

+ +
Returns:
String The owner name.
+
+
+
+ +

+getStateInformation

+
+public java.lang.String getStateInformation()
+
+
Additional information regarding the state of the XML publication. This may contain an ASN message number. +

+

+ +
Returns:
String Additional information.
+
+
+
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
Returns the name of the XML Publication. +

+

+ +
Returns:
String The publication name.
+
+
+
+ +

+setSrcName

+
+public void setSrcName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSrcOwner

+
+public void setSrcOwner(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setStateInformation

+
+public void setStateInformation(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/SubscriptionSchemaMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/SubscriptionSchemaMsg.html new file mode 100644 index 0000000..b80bfda --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/SubscriptionSchemaMsg.html @@ -0,0 +1,1055 @@ + + + + + + +SubscriptionSchemaMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class SubscriptionSchemaMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.InformationalMsg
+              |
+              +--com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg
+
+
+
+
public class SubscriptionSchemaMsg
extends InformationalMsg
+ +

+The SubscriptionSchemaMsg is sent whenever QCapture activates + or reinitializes an XML publication. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  booleanallChangedRows + +
+           
+protected  booleanbeforeValues + +
+           
+protected  java.util.Vectorcolumns + +
+           
+protected  java.lang.Stringdb2InstanceName + +
+           
+protected  java.lang.Stringdb2ReleaseLevel + +
+           
+protected  java.lang.Stringdb2ServerType + +
+           
+protected  java.lang.StringloadPhase + +
+           
+protected  booleanonlyChangedCols + +
+           
+protected  java.lang.StringqCaptureReleaseLevel + +
+           
+protected  java.lang.StringsendQueueName + +
+           
+protected  java.lang.StringsrcName + +
+           
+protected  java.lang.StringsrcOwner + +
+           
+protected  java.lang.StringsubscriptionName + +
+           
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
SubscriptionSchemaMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.util.VectorgetColumns() + +
+          Returns a list of ColumnSchema objects that describe the columns of the source table.
+ java.lang.StringgetDb2InstanceName() + +
+          Returns the name of the DB2 instance.
+ java.lang.StringgetDb2ReleaseLevel() + +
+          Returns the current release level of the DB2 server (8.2, etc..)
+ java.lang.StringgetDb2ServerType() + +
+          Returns the type of the DB2 server (QDB2, QDB2/6000, etc..)
+ java.lang.StringgetLoadPhase() + +
+          Returns the load phase option.
+ java.lang.StringgetQCaptureReleaseLevel() + +
+          Returns the current release level of the QCapture program (8.2, etc..)
+ java.lang.StringgetSendQueueName() + +
+          Returns the name of the send queue (the name of the queue on the capture server).
+ java.lang.StringgetSrcName() + +
+          Returns the name of the source db object (table, view, etc...).
+ java.lang.StringgetSrcOwner() + +
+          Returns the owner of the source db object (table, view, etc...).
+ java.lang.StringgetSubscriptionName() + +
+          Returns the name of the XML Publication.
+ booleanisAllChangedRows() + +
+          Indicates if the ALL_CHANGED_ROWS option was specified in the XML Publication definition.
+ booleanisBeforeValues() + +
+          Indicates if the BEFORE_VALUES option was specified in the XML Publication definition.
+ booleanisOnlyChangedCols() + +
+          Indicates if the CHANGED_COLS_ONLY option was specified in the XML Publication definition.
+ voidsetAllChangedRows(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetBeforeValues(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetColumns(java.util.Vector vector) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetDb2InstanceName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetDb2ReleaseLevel(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetDb2ServerType(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetLoadPhase(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetOnlyChangedCols(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetQCaptureReleaseLevel(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSendQueueName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSrcOwner(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSubscriptionName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+subscriptionName

+
+protected java.lang.String subscriptionName
+
+
+
+
+
+ +

+srcOwner

+
+protected java.lang.String srcOwner
+
+
+
+
+
+ +

+srcName

+
+protected java.lang.String srcName
+
+
+
+
+
+ +

+sendQueueName

+
+protected java.lang.String sendQueueName
+
+
+
+
+
+ +

+allChangedRows

+
+protected boolean allChangedRows
+
+
+
+
+
+ +

+beforeValues

+
+protected boolean beforeValues
+
+
+
+
+
+ +

+onlyChangedCols

+
+protected boolean onlyChangedCols
+
+
+
+
+
+ +

+loadPhase

+
+protected java.lang.String loadPhase
+
+
+
+
+
+ +

+db2ServerType

+
+protected java.lang.String db2ServerType
+
+
+
+
+
+ +

+db2ReleaseLevel

+
+protected java.lang.String db2ReleaseLevel
+
+
+
+
+
+ +

+db2InstanceName

+
+protected java.lang.String db2InstanceName
+
+
+
+
+
+ +

+qCaptureReleaseLevel

+
+protected java.lang.String qCaptureReleaseLevel
+
+
+
+
+
+ +

+columns

+
+protected java.util.Vector columns
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+SubscriptionSchemaMsg

+
+public SubscriptionSchemaMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+isAllChangedRows

+
+public boolean isAllChangedRows()
+
+
Indicates if the ALL_CHANGED_ROWS option was specified in the XML Publication definition. +

+

+ +
Returns:
True : The ALL_CHANGED_ROWS option was specified. False : it was not.
+
+
+
+ +

+isBeforeValues

+
+public boolean isBeforeValues()
+
+
Indicates if the BEFORE_VALUES option was specified in the XML Publication definition. +

+

+ +
Returns:
True : The BEFORE_VALUES option was specified. False : it was not.
+
+
+
+ +

+getColumns

+
+public java.util.Vector getColumns()
+
+
Returns a list of ColumnSchema objects that describe the columns of the source table. +

+

+ +
Returns:
Vector A vector of ColumnSchema objects.
+
+
+
+ +

+getDb2InstanceName

+
+public java.lang.String getDb2InstanceName()
+
+
Returns the name of the DB2 instance. +

+

+ +
Returns:
String The DB2 instance name.
+
+
+
+ +

+getDb2ServerType

+
+public java.lang.String getDb2ServerType()
+
+
Returns the type of the DB2 server (QDB2, QDB2/6000, etc..) +

+

+ +
Returns:
String The DB2 server type.
+
+
+
+ +

+getDb2ReleaseLevel

+
+public java.lang.String getDb2ReleaseLevel()
+
+
Returns the current release level of the DB2 server (8.2, etc..) +

+

+ +
Returns:
String The DB2 server release level.
+
+
+
+ +

+getLoadPhase

+
+public java.lang.String getLoadPhase()
+
+
Returns the load phase option. One of the following ("none", "external") +

+

+ +
Returns:
String The load phase.
+
+
+
+ +

+isOnlyChangedCols

+
+public boolean isOnlyChangedCols()
+
+
Indicates if the CHANGED_COLS_ONLY option was specified in the XML Publication definition. +

+

+ +
Returns:
True : The CHANGED_COLS_ONLY option was specified. False : it was not.
+
+
+
+ +

+getQCaptureReleaseLevel

+
+public java.lang.String getQCaptureReleaseLevel()
+
+
Returns the current release level of the QCapture program (8.2, etc..) +

+

+ +
Returns:
String The QCapture release level.
+
+
+
+ +

+getSendQueueName

+
+public java.lang.String getSendQueueName()
+
+
Returns the name of the send queue (the name of the queue on the capture server). +

+

+ +
Returns:
String The send queue name.
+
+
+
+ +

+getSrcName

+
+public java.lang.String getSrcName()
+
+
Returns the name of the source db object (table, view, etc...). +

+

+ +
Returns:
String The source name.
+
+
+
+ +

+getSrcOwner

+
+public java.lang.String getSrcOwner()
+
+
Returns the owner of the source db object (table, view, etc...). +

+

+ +
Returns:
String The owner name.
+
+
+
+ +

+getSubscriptionName

+
+public java.lang.String getSubscriptionName()
+
+
Returns the name of the XML Publication. +

+

+ +
Returns:
String The publication name.
+
+
+
+ +

+setAllChangedRows

+
+public void setAllChangedRows(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setBeforeValues

+
+public void setBeforeValues(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setColumns

+
+public void setColumns(java.util.Vector vector)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
vector -
+
+
+
+ +

+setDb2InstanceName

+
+public void setDb2InstanceName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setDb2ReleaseLevel

+
+public void setDb2ReleaseLevel(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setDb2ServerType

+
+public void setDb2ServerType(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setLoadPhase

+
+public void setLoadPhase(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setOnlyChangedCols

+
+public void setOnlyChangedCols(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setQCaptureReleaseLevel

+
+public void setQCaptureReleaseLevel(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSendQueueName

+
+public void setSendQueueName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSrcName

+
+public void setSrcName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSrcOwner

+
+public void setSrcOwner(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setSubscriptionName

+
+public void setSubscriptionName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/TransactionMsg.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/TransactionMsg.html new file mode 100644 index 0000000..73f3558 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/TransactionMsg.html @@ -0,0 +1,755 @@ + + + + + + +TransactionMsg + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class TransactionMsg

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Msg
+        |
+        +--com.ibm.db2.tools.repl.publication.DataMsg
+              |
+              +--com.ibm.db2.tools.repl.publication.TransactionMsg
+
+
+
+
public class TransactionMsg
extends DataMsg
+ +

+A TransactionMsg contains one or more insert, update, or delete row operations on the source table. + The TransactionMsg also contains information about the time theat the transaction was committed at the source + database, and a time based log sequence number. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected  java.lang.StringauthID + +
+           
+protected  java.lang.StringcommitLSN + +
+           
+protected  java.lang.StringcommitTime + +
+           
+protected  java.lang.StringcorrelationID + +
+           
+protected  booleanisLast + +
+           
+protected  java.lang.StringplanName + +
+           
+protected  java.util.Vectorrows + +
+           
+protected  intsegmentNumber + +
+           
+ + + + + + + +
Fields inherited from class com.ibm.db2.tools.repl.publication.Msg
dbName, jmsMsg, topicHeader
+  + + + + + + + + + + +
+Constructor Summary
TransactionMsg() + +
+           
+  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Method Summary
+ java.lang.StringgetAuthID() + +
+          Get the authorization id that caused the database modification.
+ java.lang.StringgetCommitLSN() + +
+          The Commit Logical Sequence Number of the transaction.
+ java.lang.StringgetCommitTime() + +
+          The timestamp of the commit statement using GMT.
+ java.lang.StringgetCorrelationID() + +
+          Get the correlation id that caused the database modification (DB2 z/OS only).
+ java.lang.StringgetPlanName() + +
+          Get the plan name that caused the database modification (DB2 z/OS only).
+ java.util.VectorgetRows() + +
+          Get the modified rows.
+ intgetSegmentNumber() + +
+          A positive integer that indicates the message's segment number in a divided transaction message.
+ booleanisLast() + +
+          A boolean value that indicates if this message is the last message in the transaction.
+ voidsetAuthID(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetCommitLSN(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetCommitTime(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetCorrelationID(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetLast(boolean b) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetPlanName(java.lang.String string) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetRows(java.util.Vector vector) + +
+          This method has no effect when used by a PublicationListener.
+ voidsetSegmentNumber(int i) + +
+          This method has no effect when used by a PublicationListener.
+ + + + + + + +
Methods inherited from class com.ibm.db2.tools.repl.publication.Msg
getDbName, getJMSMessage, getObjectProperty, getPropertyNames, getTopic, setDbName, setJMSMessage, toString
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+isLast

+
+protected boolean isLast
+
+
+
+
+
+ +

+segmentNumber

+
+protected int segmentNumber
+
+
+
+
+
+ +

+commitLSN

+
+protected java.lang.String commitLSN
+
+
+
+
+
+ +

+commitTime

+
+protected java.lang.String commitTime
+
+
+
+
+
+ +

+authID

+
+protected java.lang.String authID
+
+
+
+
+
+ +

+correlationID

+
+protected java.lang.String correlationID
+
+
+
+
+
+ +

+planName

+
+protected java.lang.String planName
+
+
+
+
+
+ +

+rows

+
+protected java.util.Vector rows
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+TransactionMsg

+
+public TransactionMsg()
+
+
+ + + + + + + + +
+Method Detail
+ +

+getCommitLSN

+
+public java.lang.String getCommitLSN()
+
+
The Commit Logical Sequence Number of the transaction. +

+

+ +
Returns:
String The LSN of the transaction.
+
+
+
+ +

+getCommitTime

+
+public java.lang.String getCommitTime()
+
+
The timestamp of the commit statement using GMT. +

+

+ +
Returns:
String The commit timestamp.
+
+
+
+ +

+getAuthID

+
+public java.lang.String getAuthID()
+
+
Get the authorization id that caused the database modification. This + may be null if not avaiable from the datasource. +

+

+ +
Returns:
String The authorization ID, or null if not available.
+
+
+
+ +

+getCorrelationID

+
+public java.lang.String getCorrelationID()
+
+
Get the correlation id that caused the database modification (DB2 z/OS only). This + may be null if not avaiable from the datasource. +

+

+ +
Returns:
String The correlation ID, or null if not available.
+
+
+
+ +

+getPlanName

+
+public java.lang.String getPlanName()
+
+
Get the plan name that caused the database modification (DB2 z/OS only). This + may be null if not avaiable from the datasource. +

+

+ +
Returns:
String The plan name, or null if not available.
+
+
+
+ +

+isLast

+
+public boolean isLast()
+
+
A boolean value that indicates if this message is the last message in the transaction. If + any LOB messages or other TransactionMsgs are following, this is false. +

+

+ +
Returns:
boolean True : This is the last message. False : other messages are following.
+
+
+
+ +

+getRows

+
+public java.util.Vector getRows()
+
+
Get the modified rows. +

+

+ +
Returns:
Vector A list of the modified Row objects.
+
+
+
+ +

+getSegmentNumber

+
+public int getSegmentNumber()
+
+
A positive integer that indicates the message's segment number in a divided transaction message. +

+

+ +
Returns:
int The segment number.
+
+
+
+ +

+setCommitLSN

+
+public void setCommitLSN(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setCommitTime

+
+public void setCommitTime(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setAuthID

+
+public void setAuthID(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setCorrelationID

+
+public void setCorrelationID(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setPlanName

+
+public void setPlanName(java.lang.String string)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
string -
+
+
+
+ +

+setLast

+
+public void setLast(boolean b)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
b -
+
+
+
+ +

+setRows

+
+public void setRows(java.util.Vector vector)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
vector -
+
+
+
+ +

+setSegmentNumber

+
+public void setSegmentNumber(int i)
+
+
This method has no effect when used by a PublicationListener. +

+

+
Parameters:
i -
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Utils.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Utils.html new file mode 100644 index 0000000..47cf2da --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/Utils.html @@ -0,0 +1,357 @@ + + + + + + +Utils + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + +

+ +com.ibm.db2.tools.repl.publication +
+Class Utils

+
+java.lang.Object
+  |
+  +--com.ibm.db2.tools.repl.publication.Utils
+
+
+
+
public class Utils
extends java.lang.Object
+ +

+This class contains a bunch of static methods to help format an object as a readable + textual string. +

+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+Field Summary
+protected static java.lang.Stringindent + +
+           
+protected static intlevel + +
+           
+protected static java.lang.Stringnl + +
+           
+protected static java.lang.StringnlIndent + +
+           
+  + + + + + + + + + + +
+Constructor Summary
Utils() + +
+           
+  + + + + + + + + + + + + + + + +
+Method Summary
+static voidfieldsAsString(java.lang.Object obj, + java.lang.StringBuffer sb) + +
+          Format the object as a nice string.
+static java.lang.StringformatAsString(java.lang.Object obj) + +
+          Format the object as a nice string.
+ + + + + + + +
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
+  +

+ + + + + + + + +
+Field Detail
+ +

+indent

+
+protected static final java.lang.String indent
+
+
+
See Also:
Constant Field Values
+
+
+ +

+nl

+
+protected static final java.lang.String nl
+
+
+
See Also:
Constant Field Values
+
+
+ +

+nlIndent

+
+protected static final java.lang.String nlIndent
+
+
+
See Also:
Constant Field Values
+
+
+ +

+level

+
+protected static int level
+
+
+
+
+ + + + + + + + +
+Constructor Detail
+ +

+Utils

+
+public Utils()
+
+
+ + + + + + + + +
+Method Detail
+ +

+formatAsString

+
+public static java.lang.String formatAsString(java.lang.Object obj)
+
+
Format the object as a nice string. +

+

+
Parameters:
obj - The object to format. +
Returns:
String The textual representation.
+
+
+
+ +

+fieldsAsString

+
+public static void fieldsAsString(java.lang.Object obj,
+                                  java.lang.StringBuffer sb)
+
+
Format the object as a nice string. +

+

+
Parameters:
obj - The object to format.
sb - Place the output into this StringBuffer.
+
+
+ +
+ + + + + + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-frame.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-frame.html new file mode 100644 index 0000000..62b3590 --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-frame.html @@ -0,0 +1,88 @@ + + + + + + +com.ibm.db2.tools.repl.publication + + + + + + + +com.ibm.db2.tools.repl.publication + + + + +
+Interfaces  + +
+PublicationMsgListener +
+PublicationMsgProvider
+ + + + + + +
+Classes  + +
+ActivateSubscriptionMsg +
+AddColumnMsg +
+Column +
+ColumnSchema +
+ControlMsg +
+DataMsg +
+DeactivateSubscriptionMsg +
+ErrorReportMsg +
+HeartbeatMsg +
+InformationalMsg +
+InvalidateSendQueueMsg +
+LoadDoneControlMsg +
+LoadDoneReceivedMsg +
+LOBMsg +
+Msg +
+PublicationMsgProviderFactory +
+Row +
+RowOperationMsg +
+SubscriptionDeactivatedMsg +
+SubscriptionSchemaMsg +
+TransactionMsg +
+Utils
+ + + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-summary.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-summary.html new file mode 100644 index 0000000..d1ab9fe --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-summary.html @@ -0,0 +1,247 @@ + + + + + + +com.ibm.db2.tools.repl.publication + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +

+Package com.ibm.db2.tools.repl.publication +

+ + + + + + + + + + + + + +
+Interface Summary
PublicationMsgListenerA PublicationMsgListener is how a PublicationMsgProvider notifies when a message is received.
PublicationMsgProviderA PublicationMsgProvider is the interface that defines how messages are created and produced.
+  + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Class Summary
ActivateSubscriptionMsgThe ActivateSubscriptionMsg sends a message to QCapture asking it to invalidate the send + queue and perform the error action specified in the publication.
AddColumnMsgThe AddColumnMsg is sent when the Q Capture programs add a column to an existing XML Publication.
ColumnThe Column class represents an actual value of a column for a specific row.
ColumnSchemaThe ColumnSchema class reprenents a column defintion in a table.
ControlMsgThe ControlMsg class represents a message that is sent to a QCapture program.
DataMsgA DataMsg is a XML Publication message about modified data, relating to a + transaction that updated, inserted, or deleted rows.
DeactivateSubscriptionMsgThe DeactivateSubscriptionMsg sends a message to QCapture asking it to invalidate the send + queue and perform the error action specified in the publication.
ErrorReportMsgThe QCapture program sends an ErrorReportMsg when it cannot perform the request of + a user application that was made through a control message.
HeartbeatMsgThe HeartbeatMsg is sent by the QCapture program to tell that QCapture is still running.
InformationalMsgAn InformationalMsg is a XML Publication message about the status of the QCapture program.
InvalidateSendQueueMsgThe InvalidateSendQueueMsg sends a message to QCapture asking it to invalidate the send + queue and perform the error action specified in the publication.
LoadDoneControlMsgThe LoadDoneControlMsg sends a message to QCapture informing it that the target table + is loaded.
LoadDoneReceivedMsgThe LoadDoneReceivedMsg is sent when the QCapture program receives a LoadDone signal.
LOBMsg 
MsgThe Msg class is the base class for the hierarchy of XML publication messages.
PublicationMsgProviderFactoryThe PublicationMsgProviderFactory class is used to create a default implmenentation of + a PublicationMsgProvider.
RowThe Row class reprenents one row that was published.
RowOperationMsgA RowOperationMsg contains one insert, update, or delete operation from the source table.
SubscriptionDeactivatedMsgThis message is sent whenever QCapture deactivates an XML Publication.
SubscriptionSchemaMsgThe SubscriptionSchemaMsg is sent whenever QCapture activates + or reinitializes an XML publication.
TransactionMsgA TransactionMsg contains one or more insert, update, or delete row operations on the source table.
UtilsThis class contains a bunch of static methods to help format an object as a readable + textual string.
+  + +

+


+ + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-tree.html b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-tree.html new file mode 100644 index 0000000..0daa02b --- /dev/null +++ b/repl/xmlpubtk/doc/com/ibm/db2/tools/repl/publication/package-tree.html @@ -0,0 +1,143 @@ + + + + + + +com.ibm.db2.tools.repl.publication Class Hierarchy + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +
+

+Hierarchy For Package com.ibm.db2.tools.repl.publication +

+
+

+Class Hierarchy +

+ +

+Interface Hierarchy +

+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/constant-values.html b/repl/xmlpubtk/doc/constant-values.html new file mode 100644 index 0000000..200dddc --- /dev/null +++ b/repl/xmlpubtk/doc/constant-values.html @@ -0,0 +1,211 @@ + + + + + + +Constant Field Values + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+

+Constant Field Values

+
+
+Contents + + + + + + +
+com.ibm.*
+ +

+ + + + + + + + + + + + +
com.ibm.db2.tools.repl.publication.Msg
+protected static final java.lang.StringtopicHeader"topic://"
+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + +
com.ibm.db2.tools.repl.publication.Row
+public static final intDeleteOperation2
+public static final intInsertOperation1
+public static final intUpdateOperation3
+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + +
com.ibm.db2.tools.repl.publication.Utils
+protected static final java.lang.Stringindent" "
+protected static final java.lang.Stringnl"\n"
+protected static final java.lang.StringnlIndent"\n "
+ +

+ +

+


+ + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/deprecated-list.html b/repl/xmlpubtk/doc/deprecated-list.html new file mode 100644 index 0000000..5bd24e5 --- /dev/null +++ b/repl/xmlpubtk/doc/deprecated-list.html @@ -0,0 +1,122 @@ + + + + + + +Deprecated List + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +
+

+Deprecated API

+
+
+ + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/help-doc.html b/repl/xmlpubtk/doc/help-doc.html new file mode 100644 index 0000000..3623722 --- /dev/null +++ b/repl/xmlpubtk/doc/help-doc.html @@ -0,0 +1,171 @@ + + + + + + +API Help + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +
+

+How This API Document Is Organized

+
+This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.

+Package

+
+ +

+Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain four categories:

    +
  • Interfaces (italic)
  • Classes
  • Exceptions
  • Errors
+
+

+Class/Interface

+
+ +

+Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:

    +
  • Class inheritance diagram
  • Direct Subclasses
  • All Known Subinterfaces
  • All Known Implementing Classes
  • Class/interface declaration
  • Class/interface description +

    +

  • Nested Class Summary
  • Field Summary
  • Constructor Summary
  • Method Summary +

    +

  • Field Detail
  • Constructor Detail
  • Method Detail
+Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.
+

+Tree (Class Hierarchy)

+
+There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with java.lang.Object. The interfaces do not inherit from java.lang.Object.
    +
  • When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.
  • When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.
+
+

+Deprecated API

+
+The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.
+

+Index

+
+The Index contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.
+

+Prev/Next

+These links take you to the next or previous class, interface, package, or related page.

+Frames/No Frames

+These links show and hide the HTML frames. All pages are available with or without frames. +

+

+Serialized Form

+Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description. +

+ + +This help file applies to API documentation generated using the standard doclet. + +
+


+ + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/index-all.html b/repl/xmlpubtk/doc/index-all.html new file mode 100644 index 0000000..47a5b3f --- /dev/null +++ b/repl/xmlpubtk/doc/index-all.html @@ -0,0 +1,1147 @@ + + + + + + +Index + + + + + + + + + + + + + + + + + + +
+ +
+ + + +A B C D E F G H I J K L M N O P Q R S T U V
+

+A

+
+
ActivateSubscriptionMsg - class com.ibm.db2.tools.repl.publication.ActivateSubscriptionMsg.
The ActivateSubscriptionMsg sends a message to QCapture asking it to invalidate the send + queue and perform the error action specified in the publication.
ActivateSubscriptionMsg(String) - +Constructor for class com.ibm.db2.tools.repl.publication.ActivateSubscriptionMsg +
Craste a new ActivateSubscriptionMsg. +
AddColumnMsg - class com.ibm.db2.tools.repl.publication.AddColumnMsg.
The AddColumnMsg is sent when the Q Capture programs add a column to an existing XML Publication.
AddColumnMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.AddColumnMsg +
  +
addPublicationMsgListener(PublicationMsgListener) - +Method in interface com.ibm.db2.tools.repl.publication.PublicationMsgProvider +
Add a listener to get the messages. +
allChangedRows - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
authID - +Variable in class com.ibm.db2.tools.repl.publication.TransactionMsg +
  +
authID - +Variable in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
  +
+
+

+B

+
+
beforeValue - +Variable in class com.ibm.db2.tools.repl.publication.Column +
  +
beforeValuePresent - +Variable in class com.ibm.db2.tools.repl.publication.Column +
  +
beforeValues - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
+
+

+C

+
+
codepage - +Variable in class com.ibm.db2.tools.repl.publication.ColumnSchema +
  +
column - +Variable in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
  +
Column - class com.ibm.db2.tools.repl.publication.Column.
The Column class represents an actual value of a column for a specific row.
Column() - +Constructor for class com.ibm.db2.tools.repl.publication.Column +
  +
columnName - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
columns - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
columns - +Variable in class com.ibm.db2.tools.repl.publication.Row +
  +
ColumnSchema - class com.ibm.db2.tools.repl.publication.ColumnSchema.
The ColumnSchema class reprenents a column defintion in a table.
ColumnSchema() - +Constructor for class com.ibm.db2.tools.repl.publication.ColumnSchema +
  +
com.ibm.db2.tools.repl.publication - package com.ibm.db2.tools.repl.publication
 
commitLSN - +Variable in class com.ibm.db2.tools.repl.publication.TransactionMsg +
  +
commitLSN - +Variable in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
  +
commitTime - +Variable in class com.ibm.db2.tools.repl.publication.TransactionMsg +
  +
commitTime - +Variable in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
  +
ControlMsg - class com.ibm.db2.tools.repl.publication.ControlMsg.
The ControlMsg class represents a message that is sent to a QCapture program.
ControlMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.ControlMsg +
  +
correlationID - +Variable in class com.ibm.db2.tools.repl.publication.TransactionMsg +
  +
correlationID - +Variable in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
  +
createPublicationMsgProvider() - +Static method in class com.ibm.db2.tools.repl.publication.PublicationMsgProviderFactory +
This will create a default message provider. +
+
+

+D

+
+
DataMsg - class com.ibm.db2.tools.repl.publication.DataMsg.
A DataMsg is a XML Publication message about modified data, relating to a + transaction that updated, inserted, or deleted rows.
DataMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.DataMsg +
  +
db2InstanceName - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
db2ReleaseLevel - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
db2ServerType - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
dbName - +Variable in class com.ibm.db2.tools.repl.publication.Msg +
  +
DeactivateSubscriptionMsg - class com.ibm.db2.tools.repl.publication.DeactivateSubscriptionMsg.
The DeactivateSubscriptionMsg sends a message to QCapture asking it to invalidate the send + queue and perform the error action specified in the publication.
DeactivateSubscriptionMsg(String) - +Constructor for class com.ibm.db2.tools.repl.publication.DeactivateSubscriptionMsg +
Create a new DeactivateSubscriptionMsg. +
DeleteOperation - +Static variable in class com.ibm.db2.tools.repl.publication.Row +
  +
dispatchMsgs(MessageConsumer, int, boolean) - +Method in interface com.ibm.db2.tools.repl.publication.PublicationMsgProvider +
This will start the messages to be dispatched to any listeners. +
+
+

+E

+
+
ErrorReportMsg - class com.ibm.db2.tools.repl.publication.ErrorReportMsg.
The QCapture program sends an ErrorReportMsg when it cannot perform the request of + a user application that was made through a control message.
ErrorReportMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
  +
+
+

+F

+
+
fieldsAsString(Object, StringBuffer) - +Static method in class com.ibm.db2.tools.repl.publication.Utils +
Format the object as a nice string. +
formatAsString(Object) - +Static method in class com.ibm.db2.tools.repl.publication.Utils +
Format the object as a nice string. +
+
+

+G

+
+
generateXML(StringBuffer) - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneControlMsg +
Actually create the xml. +
generateXML(StringBuffer) - +Method in class com.ibm.db2.tools.repl.publication.InvalidateSendQueueMsg +
Actually create the xml. +
generateXML(StringBuffer) - +Method in class com.ibm.db2.tools.repl.publication.DeactivateSubscriptionMsg +
Actually create the xml. +
generateXML(StringBuffer) - +Method in class com.ibm.db2.tools.repl.publication.ControlMsg +
Actually create the xml. +
generateXML(StringBuffer) - +Method in class com.ibm.db2.tools.repl.publication.ActivateSubscriptionMsg +
Actually create the xml. +
getAuthID() - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
Get the authorization id that caused the database modification. +
getAuthID() - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
Get the authorization id that caused the database modification. +
getBeforeValue() - +Method in class com.ibm.db2.tools.repl.publication.Column +
Returns the original value of the column, before it was updated. +
getCodepage() - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
Returns the codepage of the column. +
getColumn() - +Method in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
Returns the column that was added to the publication. +
getColumnName() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
The name of the LOB column. +
getColumns() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns a list of ColumnSchema objects that describe the columns of the source table. +
getColumns() - +Method in class com.ibm.db2.tools.repl.publication.Row +
Fetch all the columns that are a part of this row. +
getCommitLSN() - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
The Commit Logical Sequence Number of the transaction. +
getCommitLSN() - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
The Commit Logical Sequence Number of the transaction. +
getCommitTime() - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
The timestamp of the commit statement using GMT. +
getCommitTime() - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
The timestamp of the commit statement using GMT. +
getCorrelationID() - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
Get the correlation id that caused the database modification (DB2 z/OS only). +
getCorrelationID() - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
Get the correlation id that caused the database modification (DB2 z/OS only). +
getDb2InstanceName() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns the name of the DB2 instance. +
getDb2ReleaseLevel() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns the current release level of the DB2 server (8.2, etc..) +
getDb2ServerType() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns the type of the DB2 server (QDB2, QDB2/6000, etc..) +
getDbName() - +Method in class com.ibm.db2.tools.repl.publication.Msg +
This allows access to the dbName attribute of the xml message +
getJDBCType() - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
Returns the datatype of the column as a JDBC type. +
getJMSMessage() - +Method in class com.ibm.db2.tools.repl.publication.Msg +
Access the navite JMS MQ message. +
getLastCommitTime() - +Method in class com.ibm.db2.tools.repl.publication.HeartbeatMsg +
The timestamp (in GMT) of the last committed transaction. +
getLength() - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
Returns the length of the column. +
getLoadPhase() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns the load phase option. +
getLobType() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
The datatype of the LOB. +
getMsgText() - +Method in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
Returns the text of the error message. +
getName() - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
Returns the name of the column. +
getName() - +Method in class com.ibm.db2.tools.repl.publication.Column +
Returns the name of the column. +
getObjectProperty(String) - +Method in class com.ibm.db2.tools.repl.publication.Msg +
Access a specific property in the native MQ message. +
getPlanName() - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
Get the plan name that caused the database modification (DB2 z/OS only). +
getPlanName() - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
Get the plan name that caused the database modification (DB2 z/OS only). +
getPrecision() - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
Returns the precision of the column. +
getPropertyNames() - +Method in class com.ibm.db2.tools.repl.publication.Msg +
Access all the property names that are in the native MQ message. +
getQCaptureReleaseLevel() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns the current release level of the QCapture program (8.2, etc..) +
getQueueName() - +Method in class com.ibm.db2.tools.repl.publication.InvalidateSendQueueMsg +
Get the send queue name. +
getRow() - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
Get the updated row. +
getRowNumber() - +Method in class com.ibm.db2.tools.repl.publication.Row +
Return the row number. +
getRowNumber() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
Within the database transaction, the position number of the row operation that contains the LOB value. +
getRowOperation() - +Method in class com.ibm.db2.tools.repl.publication.Row +
This is how the row was used in the transaction. +
getRows() - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
Get the modified rows. +
getScale() - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
Returns the scale of the column. +
getSegmentLength() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
The length of the LOB value contained in a single message, in bytes. +
getSegmentNumber() - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
A positive integer that indicates the message's segment number in a divided transaction message. +
getSendQueueName() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns the name of the send queue (the name of the queue on the capture server). +
getSendQueueName() - +Method in class com.ibm.db2.tools.repl.publication.HeartbeatMsg +
Returns the name of the send queue (the name of the queue on the capture server) that this + msg was placed. +
getSrcName() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns the name of the source db object (table, view, etc...). +
getSrcName() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
Returns the name of the source db object (table, view, etc...). +
getSrcName() - +Method in class com.ibm.db2.tools.repl.publication.Row +
The name of the source table. +
getSrcName() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
Returns the name of the source db object (table, view, etc...). +
getSrcName() - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
Returns the name of the source db object (table, view, etc...). +
getSrcName() - +Method in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
Returns the name of the source db object (table, view, etc...). +
getSrcName() - +Method in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
Returns the name of the source db object (table, view, etc...). +
getSrcOwner() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns the owner of the source db object (table, view, etc...). +
getSrcOwner() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
Returns the owner of the source db object (table, view, etc...). +
getSrcOwner() - +Method in class com.ibm.db2.tools.repl.publication.Row +
The owner name of the source table. +
getSrcOwner() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
Returns the owner of the source db object (table, view, etc...). +
getSrcOwner() - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
Returns the owner of the source db object (table, view, etc...). +
getSrcOwner() - +Method in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
Returns the owner of the source db object (table, view, etc...). +
getSrcOwner() - +Method in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
Returns the owner of the source db object (table, view, etc...). +
getStateInformation() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
Additional information regarding the state of the XML publication. +
getStateInformation() - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
Additional information regarding the state of the XML publication. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Returns the name of the XML Publication. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
Returns the name of the XML Publication. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.Row +
The subscription name. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
Returns the name of the XML Publication. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
Returns the name of the XML Publication. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneControlMsg +
Get the subscription name. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
Returns the name of the XML Publication. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.DeactivateSubscriptionMsg +
Get the subscription name. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
Returns the name of the XML Publication. +
getSubscriptionName() - +Method in class com.ibm.db2.tools.repl.publication.ActivateSubscriptionMsg +
Get the subscription name. +
getTopic(boolean) - +Method in class com.ibm.db2.tools.repl.publication.Msg +
Access the name of the topic that was specified during the definition of the xml publication. +
getTotalDataLength() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
The length of the total LOB value contained in the source table, in bytes. +
getType() - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
Returns the datatype of the column. +
getValue() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
The value of the LOB. +
getValue() - +Method in class com.ibm.db2.tools.repl.publication.Column +
Returns the value of the column. +
getXML() - +Method in class com.ibm.db2.tools.repl.publication.ControlMsg +
This will create the xml document and return it +
+
+

+H

+
+
hasLOBColumns - +Variable in class com.ibm.db2.tools.repl.publication.Row +
  +
hasLOBColumns() - +Method in class com.ibm.db2.tools.repl.publication.Row +
Does this row have any LOB columns? +
HeartbeatMsg - class com.ibm.db2.tools.repl.publication.HeartbeatMsg.
The HeartbeatMsg is sent by the QCapture program to tell that QCapture is still running.
HeartbeatMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.HeartbeatMsg +
  +
+
+

+I

+
+
indent - +Static variable in class com.ibm.db2.tools.repl.publication.Utils +
  +
InformationalMsg - class com.ibm.db2.tools.repl.publication.InformationalMsg.
An InformationalMsg is a XML Publication message about the status of the QCapture program.
InformationalMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.InformationalMsg +
  +
InsertOperation - +Static variable in class com.ibm.db2.tools.repl.publication.Row +
  +
InvalidateSendQueueMsg - class com.ibm.db2.tools.repl.publication.InvalidateSendQueueMsg.
The InvalidateSendQueueMsg sends a message to QCapture asking it to invalidate the send + queue and perform the error action specified in the publication.
InvalidateSendQueueMsg(String) - +Constructor for class com.ibm.db2.tools.repl.publication.InvalidateSendQueueMsg +
Craste a new InvalidateSendQueueMsg. +
isAllChangedRows() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Indicates if the ALL_CHANGED_ROWS option was specified in the XML Publication definition. +
isBeforeValuePresent() - +Method in class com.ibm.db2.tools.repl.publication.Column +
Returns true if the original value of the column is present. +
isBeforeValues() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Indicates if the BEFORE_VALUES option was specified in the XML Publication definition. +
isKey() - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
Returns true if the column is a key column. +
isKey() - +Method in class com.ibm.db2.tools.repl.publication.Column +
Returns true if the column is a key column. +
isLast - +Variable in class com.ibm.db2.tools.repl.publication.TransactionMsg +
  +
isLast - +Variable in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
  +
isLast - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
isLast() - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
A boolean value that indicates if this message is the last message in the transaction. +
isLast() - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
A boolean value that indicates if this message is the last message in the transaction. +
isLast() - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
If this is the last LOB message, then this is true. +
isOnlyChangedCols() - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
Indicates if the CHANGED_COLS_ONLY option was specified in the XML Publication definition. +
+
+

+J

+
+
jmsMsg - +Variable in class com.ibm.db2.tools.repl.publication.Msg +
  +
+
+

+K

+
+
key - +Variable in class com.ibm.db2.tools.repl.publication.ColumnSchema +
  +
key - +Variable in class com.ibm.db2.tools.repl.publication.Column +
  +
+
+

+L

+
+
lastCommitTime - +Variable in class com.ibm.db2.tools.repl.publication.HeartbeatMsg +
  +
length - +Variable in class com.ibm.db2.tools.repl.publication.ColumnSchema +
  +
level - +Static variable in class com.ibm.db2.tools.repl.publication.Utils +
  +
LoadDoneControlMsg - class com.ibm.db2.tools.repl.publication.LoadDoneControlMsg.
The LoadDoneControlMsg sends a message to QCapture informing it that the target table + is loaded.
LoadDoneControlMsg(String) - +Constructor for class com.ibm.db2.tools.repl.publication.LoadDoneControlMsg +
Craste a new LoadDoneControlMsg. +
LoadDoneReceivedMsg - class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg.
The LoadDoneReceivedMsg is sent when the QCapture program receives a LoadDone signal.
LoadDoneReceivedMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
  +
loadPhase - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
LOBMsg - class com.ibm.db2.tools.repl.publication.LOBMsg.
 
LOBMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
lobType - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
+
+

+M

+
+
Msg - class com.ibm.db2.tools.repl.publication.Msg.
The Msg class is the base class for the hierarchy of XML publication messages.
Msg() - +Constructor for class com.ibm.db2.tools.repl.publication.Msg +
  +
msgText - +Variable in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
  +
+
+

+N

+
+
name - +Variable in class com.ibm.db2.tools.repl.publication.ColumnSchema +
  +
name - +Variable in class com.ibm.db2.tools.repl.publication.Column +
  +
nl - +Static variable in class com.ibm.db2.tools.repl.publication.Utils +
  +
nlIndent - +Static variable in class com.ibm.db2.tools.repl.publication.Utils +
  +
+
+

+O

+
+
onlyChangedCols - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
+
+

+P

+
+
planName - +Variable in class com.ibm.db2.tools.repl.publication.TransactionMsg +
  +
planName - +Variable in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
  +
precision - +Variable in class com.ibm.db2.tools.repl.publication.ColumnSchema +
  +
publicationMsg(Msg) - +Method in interface com.ibm.db2.tools.repl.publication.PublicationMsgListener +
Notify the caller of a publication message. +
PublicationMsgListener - interface com.ibm.db2.tools.repl.publication.PublicationMsgListener.
A PublicationMsgListener is how a PublicationMsgProvider notifies when a message is received.
PublicationMsgProvider - interface com.ibm.db2.tools.repl.publication.PublicationMsgProvider.
A PublicationMsgProvider is the interface that defines how messages are created and produced.
PublicationMsgProviderFactory - class com.ibm.db2.tools.repl.publication.PublicationMsgProviderFactory.
The PublicationMsgProviderFactory class is used to create a default implmenentation of + a PublicationMsgProvider.
PublicationMsgProviderFactory() - +Constructor for class com.ibm.db2.tools.repl.publication.PublicationMsgProviderFactory +
  +
+
+

+Q

+
+
qCaptureReleaseLevel - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
qName - +Variable in class com.ibm.db2.tools.repl.publication.InvalidateSendQueueMsg +
  +
+
+

+R

+
+
removePublicationMsgListener(PublicationMsgListener) - +Method in interface com.ibm.db2.tools.repl.publication.PublicationMsgProvider +
Remove a listener. +
row - +Variable in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
  +
Row - class com.ibm.db2.tools.repl.publication.Row.
The Row class reprenents one row that was published.
Row() - +Constructor for class com.ibm.db2.tools.repl.publication.Row +
  +
rowNumber - +Variable in class com.ibm.db2.tools.repl.publication.Row +
  +
rowNumber - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
rowOperation - +Variable in class com.ibm.db2.tools.repl.publication.Row +
  +
RowOperationMsg - class com.ibm.db2.tools.repl.publication.RowOperationMsg.
A RowOperationMsg contains one insert, update, or delete operation from the source table.
RowOperationMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.RowOperationMsg +
  +
rows - +Variable in class com.ibm.db2.tools.repl.publication.TransactionMsg +
  +
+
+

+S

+
+
scale - +Variable in class com.ibm.db2.tools.repl.publication.ColumnSchema +
  +
segmentLength - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
segmentNumber - +Variable in class com.ibm.db2.tools.repl.publication.TransactionMsg +
  +
send(Session, MessageProducer) - +Method in class com.ibm.db2.tools.repl.publication.ControlMsg +
This will send the msg to the + the specified messageProducer (MQ queue). +
send(String, String) - +Method in class com.ibm.db2.tools.repl.publication.ControlMsg +
This will send the msg to the specified queue manager and queue. +
sendQueueName - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
sendQueueName - +Variable in class com.ibm.db2.tools.repl.publication.HeartbeatMsg +
  +
setAllChangedRows(boolean) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setAuthID(String) - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
This method has no effect when used by a PublicationListener. +
setAuthID(String) - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
This method has no effect when used by a PublicationListener. +
setBeforeValue(Object) - +Method in class com.ibm.db2.tools.repl.publication.Column +
This method has no effect when used by a PublicationListener. +
setBeforeValuePresent(boolean) - +Method in class com.ibm.db2.tools.repl.publication.Column +
This method has no effect when used by a PublicationListener. +
setBeforeValues(boolean) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setCodepage(int) - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
This method has no effect when used by a PublicationListener. +
setColumn(ColumnSchema) - +Method in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
This method has no effect when used by a PublicationListener. +
setColumnName(String) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setColumns(Vector) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setColumns(Vector) - +Method in class com.ibm.db2.tools.repl.publication.Row +
This method has no effect when used by a PublicationListener. +
setCommitLSN(String) - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
This method has no effect when used by a PublicationListener. +
setCommitLSN(String) - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
This method has no effect when used by a PublicationListener. +
setCommitTime(String) - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
This method has no effect when used by a PublicationListener. +
setCommitTime(String) - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
This method has no effect when used by a PublicationListener. +
setCorrelationID(String) - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
This method has no effect when used by a PublicationListener. +
setCorrelationID(String) - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
This method has no effect when used by a PublicationListener. +
setDb2InstanceName(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setDb2ReleaseLevel(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setDb2ServerType(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setDbName(String) - +Method in class com.ibm.db2.tools.repl.publication.Msg +
This method has no effect when used by a PublicationListener. +
setHasLOBColumns(boolean) - +Method in class com.ibm.db2.tools.repl.publication.Row +
This method has no effect when used by a PublicationListener. +
setJMSMessage(Message) - +Method in class com.ibm.db2.tools.repl.publication.Msg +
This method has no effect when used by a PublicationListener. +
setKey(boolean) - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
This method has no effect when used by a PublicationListener. +
setKey(boolean) - +Method in class com.ibm.db2.tools.repl.publication.Column +
This method has no effect when used by a PublicationListener. +
setLast(boolean) - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
This method has no effect when used by a PublicationListener. +
setLast(boolean) - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
This method has no effect when used by a PublicationListener. +
setLast(boolean) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setLastCommitTime(String) - +Method in class com.ibm.db2.tools.repl.publication.HeartbeatMsg +
This method has no effect when used by a PublicationListener. +
setLength(int) - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
This method has no effect when used by a PublicationListener. +
setLoadPhase(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setLobType(String) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setMsgText(String) - +Method in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
This method has no effect when used by a PublicationListener. +
setName(String) - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
This method has no effect when used by a PublicationListener. +
setName(String) - +Method in class com.ibm.db2.tools.repl.publication.Column +
This method has no effect when used by a PublicationListener. +
setOnlyChangedCols(boolean) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setPlanName(String) - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
This method has no effect when used by a PublicationListener. +
setPlanName(String) - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
This method has no effect when used by a PublicationListener. +
setPrecision(int) - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
This method has no effect when used by a PublicationListener. +
setQCaptureReleaseLevel(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setQueueName(String) - +Method in class com.ibm.db2.tools.repl.publication.InvalidateSendQueueMsg +
Set the send queue name. +
setRow(Row) - +Method in class com.ibm.db2.tools.repl.publication.RowOperationMsg +
This method has no effect when used by a PublicationListener. +
setRowNumber(int) - +Method in class com.ibm.db2.tools.repl.publication.Row +
This method has no effect when used by a PublicationListener. +
setRowNumber(int) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setRowOperation(int) - +Method in class com.ibm.db2.tools.repl.publication.Row +
This method has no effect when used by a PublicationListener. +
setRows(Vector) - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
This method has no effect when used by a PublicationListener. +
setScale(int) - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
This method has no effect when used by a PublicationListener. +
setSegmentLength(int) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setSegmentNumber(int) - +Method in class com.ibm.db2.tools.repl.publication.TransactionMsg +
This method has no effect when used by a PublicationListener. +
setSendQueueName(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setSendQueueName(String) - +Method in class com.ibm.db2.tools.repl.publication.HeartbeatMsg +
This method has no effect when used by a PublicationListener. +
setSrcName(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setSrcName(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
This method has no effect when used by a PublicationListener. +
setSrcName(String) - +Method in class com.ibm.db2.tools.repl.publication.Row +
This method has no effect when used by a PublicationListener. +
setSrcName(String) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setSrcName(String) - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
This method has no effect when used by a PublicationListener. +
setSrcName(String) - +Method in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
This method has no effect when used by a PublicationListener. +
setSrcName(String) - +Method in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
This method has no effect when used by a PublicationListener. +
setSrcOwner(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setSrcOwner(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
This method has no effect when used by a PublicationListener. +
setSrcOwner(String) - +Method in class com.ibm.db2.tools.repl.publication.Row +
This method has no effect when used by a PublicationListener. +
setSrcOwner(String) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setSrcOwner(String) - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
This method has no effect when used by a PublicationListener. +
setSrcOwner(String) - +Method in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
This method has no effect when used by a PublicationListener. +
setSrcOwner(String) - +Method in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
This method has no effect when used by a PublicationListener. +
setStateInformation(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
This method has no effect when used by a PublicationListener. +
setStateInformation(String) - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
This method has no effect when used by a PublicationListener. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
This method has no effect when used by a PublicationListener. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
This method has no effect when used by a PublicationListener. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.Row +
This method has no effect when used by a PublicationListener. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
This method has no effect when used by a PublicationListener. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneControlMsg +
Set the subscription name. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
This method has no effect when used by a PublicationListener. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.DeactivateSubscriptionMsg +
Set the subscription name. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
This method has no effect when used by a PublicationListener. +
setSubscriptionName(String) - +Method in class com.ibm.db2.tools.repl.publication.ActivateSubscriptionMsg +
Set the subscription name. +
setTotalDataLength(int) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setType(String) - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
This method has no effect when used by a PublicationListener. +
setValue(Object) - +Method in class com.ibm.db2.tools.repl.publication.LOBMsg +
This method has no effect when used by a PublicationListener. +
setValue(Object) - +Method in class com.ibm.db2.tools.repl.publication.Column +
This method has no effect when used by a PublicationListener. +
srcName - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
srcName - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
  +
srcName - +Variable in class com.ibm.db2.tools.repl.publication.Row +
  +
srcName - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
srcName - +Variable in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
  +
srcName - +Variable in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
  +
srcName - +Variable in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
  +
srcOwner - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
srcOwner - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
  +
srcOwner - +Variable in class com.ibm.db2.tools.repl.publication.Row +
  +
srcOwner - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
srcOwner - +Variable in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
  +
srcOwner - +Variable in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
  +
srcOwner - +Variable in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
  +
stateInformation - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
  +
stateInformation - +Variable in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
  +
stopMsgDispatching() - +Method in interface com.ibm.db2.tools.repl.publication.PublicationMsgProvider +
This will stop the dispatching of messages, and cause the thread to return from dispatchMsgs(). +
SubscriptionDeactivatedMsg - class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg.
This message is sent whenever QCapture deactivates an XML Publication.
SubscriptionDeactivatedMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.SubscriptionDeactivatedMsg +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.Row +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.LoadDoneReceivedMsg +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.LoadDoneControlMsg +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.ErrorReportMsg +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.DeactivateSubscriptionMsg +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.AddColumnMsg +
  +
subscriptionName - +Variable in class com.ibm.db2.tools.repl.publication.ActivateSubscriptionMsg +
  +
SubscriptionSchemaMsg - class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg.
The SubscriptionSchemaMsg is sent whenever QCapture activates + or reinitializes an XML publication.
SubscriptionSchemaMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.SubscriptionSchemaMsg +
  +
+
+

+T

+
+
topicHeader - +Static variable in class com.ibm.db2.tools.repl.publication.Msg +
  +
toString() - +Method in class com.ibm.db2.tools.repl.publication.Row +
Override so we can print the values in a nice textual format. +
toString() - +Method in class com.ibm.db2.tools.repl.publication.Msg +
Override so we can print the values in a nice textual format. +
toString() - +Method in class com.ibm.db2.tools.repl.publication.ControlMsg +
Override so we can print the values in a nice textual format. +
toString() - +Method in class com.ibm.db2.tools.repl.publication.ColumnSchema +
Override so we can print the values in a nice textual format. +
toString() - +Method in class com.ibm.db2.tools.repl.publication.Column +
  +
totalDataLength - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
TransactionMsg - class com.ibm.db2.tools.repl.publication.TransactionMsg.
A TransactionMsg contains one or more insert, update, or delete row operations on the source table.
TransactionMsg() - +Constructor for class com.ibm.db2.tools.repl.publication.TransactionMsg +
  +
type - +Variable in class com.ibm.db2.tools.repl.publication.ColumnSchema +
  +
+
+

+U

+
+
UpdateOperation - +Static variable in class com.ibm.db2.tools.repl.publication.Row +
  +
Utils - class com.ibm.db2.tools.repl.publication.Utils.
This class contains a bunch of static methods to help format an object as a readable + textual string.
Utils() - +Constructor for class com.ibm.db2.tools.repl.publication.Utils +
  +
+
+

+V

+
+
validate() - +Method in class com.ibm.db2.tools.repl.publication.LoadDoneControlMsg +
This will valiadate that everything is present for the xml document to be created. +
validate() - +Method in class com.ibm.db2.tools.repl.publication.InvalidateSendQueueMsg +
This will valiadate that everything is present for the xml document to be created. +
validate() - +Method in class com.ibm.db2.tools.repl.publication.DeactivateSubscriptionMsg +
This will valiadate that everything is present for the xml document to be created. +
validate() - +Method in class com.ibm.db2.tools.repl.publication.ControlMsg +
This will valiadate that everything is present for the xml document to be created. +
validate() - +Method in class com.ibm.db2.tools.repl.publication.ActivateSubscriptionMsg +
This will valiadate that everything is present for the xml document to be created. +
value - +Variable in class com.ibm.db2.tools.repl.publication.LOBMsg +
  +
value - +Variable in class com.ibm.db2.tools.repl.publication.Column +
  +
+
+A B C D E F G H I J K L M N O P Q R S T U V + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/index.html b/repl/xmlpubtk/doc/index.html new file mode 100644 index 0000000..dd91875 --- /dev/null +++ b/repl/xmlpubtk/doc/index.html @@ -0,0 +1,22 @@ + + + + + + +Generated Documentation (Untitled) + + + + + + + +<H2> +Frame Alert</H2> + +<P> +This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. +<BR> +Link to <A HREF="com/ibm/db2/tools/repl/publication/package-summary.html">Non-frame version.</A> + diff --git a/repl/xmlpubtk/doc/overview-tree.html b/repl/xmlpubtk/doc/overview-tree.html new file mode 100644 index 0000000..c41629c --- /dev/null +++ b/repl/xmlpubtk/doc/overview-tree.html @@ -0,0 +1,143 @@ + + + + + + +Class Hierarchy + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +
+

+Hierarchy For All Packages

+
+
+
Package Hierarchies:
com.ibm.db2.tools.repl.publication
+
+

+Class Hierarchy +

+ +

+Interface Hierarchy +

+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/package-list b/repl/xmlpubtk/doc/package-list new file mode 100644 index 0000000..af18efe --- /dev/null +++ b/repl/xmlpubtk/doc/package-list @@ -0,0 +1 @@ +com.ibm.db2.tools.repl.publication diff --git a/repl/xmlpubtk/doc/packages.html b/repl/xmlpubtk/doc/packages.html new file mode 100644 index 0000000..2b95618 --- /dev/null +++ b/repl/xmlpubtk/doc/packages.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + +
+ +
+ +
+
+The front page has been relocated.Please see: +
+          Frame version +
+          Non-frame version.
+ + + diff --git a/repl/xmlpubtk/doc/serialized-form.html b/repl/xmlpubtk/doc/serialized-form.html new file mode 100644 index 0000000..4c35b62 --- /dev/null +++ b/repl/xmlpubtk/doc/serialized-form.html @@ -0,0 +1,122 @@ + + + + + + +Serialized Form + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +
+

+Serialized Form

+
+
+ + + + + + + + + + + + + +
+ +
+ + +
+ + + diff --git a/repl/xmlpubtk/doc/stylesheet.css b/repl/xmlpubtk/doc/stylesheet.css new file mode 100644 index 0000000..8c7a8bb --- /dev/null +++ b/repl/xmlpubtk/doc/stylesheet.css @@ -0,0 +1,29 @@ +/* Javadoc style sheet */ + +/* Define colors, fonts and other style attributes here to override the defaults */ + +/* Page background color */ +body { background-color: #FFFFFF } + +/* Table colors */ +.TableHeadingColor { background: #CCCCFF } /* Dark mauve */ +.TableSubHeadingColor { background: #EEEEFF } /* Light mauve */ +.TableRowColor { background: #FFFFFF } /* White */ + +/* Font used in left-hand frame lists */ +.FrameTitleFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } +.FrameHeadingFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } +.FrameItemFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif } + +/* Example of smaller, sans-serif font in frames */ +/* .FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */ + +/* Navigation bar fonts and colors */ +.NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */ +.NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */ +.NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;} +.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;} + +.NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;} +.NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;} + diff --git a/repl/xmlpubtk/loadqueue/LoadQueue.jar b/repl/xmlpubtk/loadqueue/LoadQueue.jar new file mode 100644 index 0000000000000000000000000000000000000000..611753f8c5fd43528100940aecb2256bd59c0e5a GIT binary patch literal 22115 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 O6rMahMEhHMne<;8LsV`6 literal 0 HcmV?d00001 diff --git a/repl/xmlpubtk/loadqueue/LoadQueue.java b/repl/xmlpubtk/loadqueue/LoadQueue.java new file mode 100644 index 0000000..efab84c --- /dev/null +++ b/repl/xmlpubtk/loadqueue/LoadQueue.java @@ -0,0 +1,138 @@ +import com.ibm.db2.tools.repl.publication.*; +import com.ibm.db2.tools.repl.publication.support.*; +import java.util.*; +import javax.jms.*; +import com.ibm.mq.jms.MQQueueConnectionFactory; +import com.ibm.mq.jms.MQTopicConnectionFactory; + + + +/** + * A simple program to put a set of random XML Publication transaction messages on the queue. + * The advantage of this is that you dont need to run replication just to develope & test your + * toolkit application. + * + * @author tjacopi + * + */ +public class LoadQueue { + + public void go(String qMgrName, String qName, String topicName) { + try { + Random rand = new Random(); + + MessageProducer messageProducer = null; + Session session = null; + + if (qName != null) { + System.out.println("Connect to queue " + qName + " in queue manager " + qMgrName); + MQQueueConnectionFactory factory = new MQQueueConnectionFactory(); + factory.setQueueManager( qMgrName ); + QueueConnection connection = factory.createQueueConnection(); + connection.start(); + QueueSession qsession = connection.createQueueSession( false, Session.AUTO_ACKNOWLEDGE); + Queue queue = qsession.createQueue( qName ); + QueueSender queueSender = qsession.createSender( queue ); + messageProducer = queueSender; + session = qsession; + // Create the JMS MQ objects to read from the queue + } else { + System.out.println("Connect to topic " + topicName + " in queue manager " + qMgrName); + MQTopicConnectionFactory factory = new MQTopicConnectionFactory(); + factory.setQueueManager( qMgrName ); + TopicConnection connection = factory.createTopicConnection(); + connection.start(); + TopicSession tsession = connection.createTopicSession( false, Session.AUTO_ACKNOWLEDGE); + Topic topic = tsession.createTopic( topicName ); + TopicPublisher topicPublisher = tsession.createPublisher( topic); + messageProducer = topicPublisher; + session = tsession; + } + + TextMessage[] msg = new TextMessage[27]; + msg[0] = session.createTextMessage(" 1 first 2 3 "); + msg[1] = session.createTextMessage(" 1 first 2 3 "); + msg[2] = session.createTextMessage(" 1 first 2 3 "); + msg[3] = session.createTextMessage(" 1 first 2 3 "); + msg[4] = session.createTextMessage(" 1 first 2 3 "); + msg[5] = session.createTextMessage(" 1 first 2 3 "); + msg[6] = session.createTextMessage(" 1 first 2 3 "); + msg[7] = session.createTextMessage(" 1 first 2 3 "); + msg[8] = session.createTextMessage(" 1 first 2 3 "); + msg[9] = session.createTextMessage(" 1 first 2 3 "); + msg[10] = session.createTextMessage(" 1 first 2 3 "); + msg[11] = session.createTextMessage(" 1 first 2 3 "); + msg[12] = session.createTextMessage(" 1 first 2 3 "); + msg[13] = session.createTextMessage(" 1 first 2 3 "); + msg[14] = session.createTextMessage(" 1 first 2 3 "); + msg[15] = session.createTextMessage(" 1 first 2 3 "); + msg[16] = session.createTextMessage(" 1 first 2 3 "); + msg[17] = session.createTextMessage(" 1 first 2 3 "); + msg[18] = session.createTextMessage(" 1 first 2 3 "); + msg[19] = session.createTextMessage(" 1 first 2 3 "); + msg[20] = session.createTextMessage(" 1 first 2 3 "); + msg[21] = session.createTextMessage(" 1 first 2 3 "); + msg[22] = session.createTextMessage(" 1 first 2 3 "); + msg[23] = session.createTextMessage(" 1 first 2 3 "); + msg[24] = session.createTextMessage(" 1 first 2 3 "); + msg[25] = session.createTextMessage(" 1 first 2 3 "); + msg[26] = session.createTextMessage(" 1 first 2 3 "); + + while (true) { + int numMsgs = rand.nextInt(5); + for (int i=0; i (-queue | -topic ) "); + System.out.println(" example: java LoadQueue -qmgr DefaultQMGR -queue myPubQ"); + System.out.println(" - or - "); + System.out.println(" example: java LoadQueue -qmgr DefaultQMGR -topic myTopic"); + } + + protected static String parseArgsFor(String argName, String[] args) { + String argValue = null; + for (int i =0; i -queue " + + This will put messages on the queue. You need to leave this program running if your queue is + not persistant. + 4. Go to the sample1 directory and run the sample program by: + + "java sample1 -qmgr -queue " + + You should see a count of rows changed. + + + Note in order to use topic in the publish/subscribe style, a MessageBroker must be installed + and running. You can read about that in "WebSphere MQ Using Java" (SC34-6066-02) on page 26 + titled "Additional setup for publish/subscribe mode". diff --git a/repl/xmlpubtk/sample1/sample1.jar b/repl/xmlpubtk/sample1/sample1.jar new file mode 100644 index 0000000000000000000000000000000000000000..2252321123bbaffbf71f6dd568afc2cb5d777f42 GIT binary patch literal 3609 zcmbVP+fy6Y9sU*xRxBGZ!gj3KxEnXNg#;*IlEz>Y8w?HsVK9W&PSbiNE%FjcD|S}| z(x$mINz;4Mv`HQJnqGKqI<11^nM~UU&oq5*|A0=P`VaIi?RR!15J=O;)y$rA^gF-% z?VK|=9SABAzdujEc*fdf}YNyeIlPSK z64at@JH~lC>r7g$kDe^0GmVJIAd;!AQHBYiS-c zO~se-oP@Au7AlauUeL3K&7H5{c^NOLco8qr;Z>jIR}(9FCy|_=7ur-9GW{p@v}@T^ z;j4H_#mjg_#;Yp6CTw{PUzhO>72m|SRD2uXk?~y>uj36F-&64>zOUj3cuPXpj@lFJ zX`?8LiV0G&RvXt#+3T*S@!KkXh#`7{QPNC@up4+s#!VGJ!t)XatGfP|_%bgq6%D^~ zy|jqLV%nm}T+L?6YWYh3YG*x(KbA1?3AirWdcmP1s5zOc_z8Y0<7X;M0HS88P2+Xs3jdhb;gV8Bb zd;zP(KL`8@Fs;O#C??jjq31`K(R#6H6fzQe8&pzHUD^0qOuCS3`Tan`{%AcOG5l28 zEs*Kr)pCwWb)bf7NMu9w%9NDwpaHU2%xE}^?3c-^apJ=@eEB0Sx2lV$C=x=p`? zYj`ghjyP;29Eo0?@@=Z2uI!SpSKIYF6548*NjTofK+mH!v}D)rQ(ZRFhPfs}I_eYF zV$}s=q)xvoJvpAc>wKECtu-@a*p&`K7x+r;&blfV>xi!ZzlBi4yU+L?*%3XH*{#=3 zHPCf;tyY!VJ8RU8=@fN0eVx67ho)8=iX`)cy@CDKDdi1&Wa_G@uU&=XS9B#fwa4am z;dFQfu;A+Hr`f5}JWE1Z!yOm*5!TGEQu2UwR>w}qsNl&YnPo?kaF|72mmJ%|1fGBT zZx?CFHFJq2wjIkRYrlKcz}Pk%^I0=S?XA z2@mpX5@#r{SS?)hNagqt|D7OQ;;h8phZGC^9!>A@pM-}6jC(*cuaGiY@fkc)p-Ce^ z7?21DVp|B#gqy{b?7f3S@jKXm8!cDfhdkRC?=2&=iIy$22DYH=Fg}Km$6iJo+M(hg z?}JCVI*EOVA+=5Nt<8!EZq6K*e~gZw+f`#8k;mC;#7_%^z@ zy`RF%IM7$d!Qo&ecnkNk0|f(I9138#InvyF3y~%aw?vvFEz&LAN2t7o!^5FSD0T}+ znh*&^Y z@uN6HjEm4P&*(gb<47?ED>QwLm&grbzKJ;AMlaq$A32Q>-;dM>^ty=0t2L^8+PD3I zGLCP1ApS?3xPji-mEWN$c#Q$A!9Pi?7~y3^eeE}Kn)p38Fc=f?_#e#h?YFWTzeRom@P}p7n4DJg*JG%vWgu8o)thR^$IhBVKLK-;T@LkG*vuGLU@!; zJV$cg_$uU!mE?;`$-w9)4#wi$gJtyJKx@1^cx^EGazN^ie;CZX3%U2szyHzu8*=gk zavxJ47^nCPOy~)8ViNaqeF9U&ILEyvoS&PPniOWf_%(V=c^liq_It^HTJ0v?`?%Vs nVt^YzwQ7YodNJ*AxXESpmh8Qs=BAs4b#zVuTbyUb3k&}N>8GG( literal 0 HcmV?d00001 diff --git a/repl/xmlpubtk/sample1/sample1.java b/repl/xmlpubtk/sample1/sample1.java new file mode 100644 index 0000000..9ecb2e4 --- /dev/null +++ b/repl/xmlpubtk/sample1/sample1.java @@ -0,0 +1,75 @@ +import com.ibm.db2.tools.repl.publication.*; +import javax.jms.*; +import com.ibm.mq.jms.MQQueueConnectionFactory; + +public class sample1 implements PublicationMsgListener { + + private int totalModifiedRows = 0; + + public static void main( String[] args ) { + String qManager = parseArgsFor("-qmgr", args); + String qName = parseArgsFor("-queue", args); + if (qName != null && qManager != null ) { + sample1 test = new sample1(); // Just create an instance... + test.go(qManager, qName); + } else { + printHelp(); + } + System.exit(0); + } + + + public void go(String qMgrName, String qName) { + try { + System.out.println("Connect to queue " + qName + " in queue manager " + qMgrName); + + // Build the JMS objects requried to listen to a queue + MQQueueConnectionFactory factory = new MQQueueConnectionFactory(); + factory.setQueueManager( qMgrName ); + QueueConnection connection = factory.createQueueConnection(); + connection.start(); + QueueSession session = connection.createQueueSession( false, Session.AUTO_ACKNOWLEDGE); + Queue receiveQueue = session.createQueue( qName ); + QueueReceiver queueReceiver = session.createReceiver( receiveQueue, null ); + + // Create the PublicationMsgProvider which will listen to the queue, parse the xml messages, + // and dispatch them to us. + PublicationMsgProvider msgProvider = PublicationMsgProviderFactory.createPublicationMsgProvider(); + msgProvider.addPublicationMsgListener(this); // Notify us of any messages + msgProvider.dispatchMsgs(queueReceiver, 60000, true); // Start dispatching with a 60 sec timeout + // true = ignore errors. + } catch ( Exception caught ) { + System.out.println("sample1 Caught " + caught); + caught.printStackTrace(); + } + } + + /** + * This is called whenever a msg is received. + */ + public void publicationMsg(Msg pubMsg) { + System.out.println("Msg is " + pubMsg.getClass().getName() ); + if (pubMsg instanceof RowOperationMsg) { + totalModifiedRows++; // RowOperationMsg only have one row changed + System.out.println("** Total rows modified = " + totalModifiedRows ); + } else if (pubMsg instanceof TransactionMsg) { + totalModifiedRows = totalModifiedRows + ((TransactionMsg) pubMsg).getRows().size(); + System.out.println("** Total rows modified = " + totalModifiedRows ); + } + } + + protected static void printHelp() { + System.out.println("Usage: java sample1 -qmgr -queue "); + System.out.println(" example: java sample1 -qmgr DefaultQMGR -queue myPubQ"); + } + + protected static String parseArgsFor(String argName, String[] args) { + String argValue = null; + for (int i =0; i 0) + low = mid + 1; + else + foundIndex = mid; + } + + // If not found, insert a new row where it should have been found. + if (foundIndex == -1) { + if (low >= numRows) { + foundIndex = numRows; + } else if (high < 0) { + foundIndex = 0; + } else { + String strLow = tableModel.getValueAt(low, 0).toString(); + if (key.compareTo(strLow) > 0) { + foundIndex = low+1; + } else { + String strHigh = tableModel.getValueAt(high, 0).toString(); + if (key.compareTo(strHigh) > 0) { + foundIndex = high + 1; + } else { + foundIndex = high; + } + } + } + createRowAt(foundIndex, key); + }; + + return foundIndex; + } + + + /** + * Create a new row at the specified index. The new row has "0" for its values. + * @param index Add the new row at this index. + * @param key The qualified table name which is in the first column of the table. + */ + protected void createRowAt(int index, String key) { + String[] newRow = {key, "0", "0", "0"}; // Make the new row + tableModel.addRow(newRow); // Add it at the bottom + int lastRowIndex = tableModel.getRowCount()-1; // Get the index + tableModel.moveRow(lastRowIndex, lastRowIndex, index); // And move it to the right place + } + + /** + * Update the specified row with the new values in the Count structure. + * @param rowIndex The row in the table model. + * @param count The Count structure with the new updates. + */ + protected void updateRow(int rowIndex, Count count) { + if (count.rowsInserted >0) { + addToCell(rowIndex, 1, count.rowsInserted); + }; + if (count.rowsUpdated >0) { + addToCell(rowIndex, 2, count.rowsUpdated); + }; + if (count.rowsDeleted >0) { + addToCell(rowIndex, 3, count.rowsDeleted); + }; + } + + /** + * Add the specified value to this table cell. + * @param rowIndex The row in the table model. + * @param colIndex The col in the table model. + * @param amount The amount to add to the cell. + */ + protected void addToCell(int rowIndex, int colIndex, int amount) { + try { + String strOldValue = (String) tableModel.getValueAt(rowIndex, colIndex); // The old value as a string + int intOldValue = Integer.parseInt(strOldValue); // Convert to an int + int intNewValue = intOldValue + amount; // Now add to it + String strNewValue = Integer.toString(intNewValue); // Back to a string + tableModel.setValueAt(strNewValue, rowIndex, colIndex); // And set it to the table + } catch(Throwable t) { + System.out.println("Caught " + t + " when adding counts"); + t.printStackTrace(); + } + } + + /** + * Get whatever is selected as a string. + * @return String The selected values. + */ + public String getSelectedContentsAsString() { + StringBuffer strBuffer = new StringBuffer(100); + int[] rows = table.getSelectedRows(); + boolean firstTime = true; + for (int i=0; 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 literal 0 HcmV?d00001 diff --git a/repl/xmlpubtk/sample2/sample2.java b/repl/xmlpubtk/sample2/sample2.java new file mode 100644 index 0000000..ba12986 --- /dev/null +++ b/repl/xmlpubtk/sample2/sample2.java @@ -0,0 +1,58 @@ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + + +/** + * The sample2 class is the small class to create a new frame and make it visible. + * + * @author tjacopi + * + */ +public class sample2 { + + + public static void main(String args[]) { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + e.printStackTrace(); + } + + // Get the arguments the user passed in + String qManager = parseArgsFor("-qmgr", args); + String qName = parseArgsFor("-queue", args); + String topicName = parseArgsFor("-topic", args); + + // Insure qManager and either qName or topicName was specified + if (qManager != null && (qName != null || topicName != null) ) { + MonitorFrame frame = new MonitorFrame(qManager, qName, topicName); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) {System.exit(0);} + }); + frame.pack(); + frame.setVisible(true); + } else { + printHelp(); + System.exit(0); + } + } + + + protected static void printHelp() { + System.out.println("Usage: java sample2 -qmgr (-queue | -topic ) "); + System.out.println(" example: java sample2 -qmgr DefaultQMGR -queue myPubQ"); + System.out.println(" - or - "); + System.out.println(" example: java sample2 -qmgr DefaultQMGR -topic myTopic"); + } + + protected static String parseArgsFor(String argName, String[] args) { + String argValue = null; + for (int i =0; i 0) { + rowsInserted = rowsInserted + c.rowsInserted; + lastInsertInterval = intervalToken; + }; + if (c.rowsDeleted > 0) { + rowsDeleted = rowsDeleted + c.rowsDeleted; + lastDeleteInterval = intervalToken; + }; + if (c.rowsUpdated > 0) { + rowsUpdated = rowsUpdated + c.rowsUpdated; + lastUpdateInterval = intervalToken; + }; + } + +} diff --git a/repl/xmlpubtk/sample3/MonitorFrame.java b/repl/xmlpubtk/sample3/MonitorFrame.java new file mode 100644 index 0000000..f6bfba3 --- /dev/null +++ b/repl/xmlpubtk/sample3/MonitorFrame.java @@ -0,0 +1,165 @@ +import java.awt.*; +import java.awt.datatransfer.*; +import java.awt.event.*; +import javax.swing.*; +import com.ibm.db2.tools.repl.publication.*; + +/** + * The MonitorFrame is the JFrame that holds the MonitorTablePanel. It provides support + * for the menu items. + * + * @author tjacopi + * + */ +public class MonitorFrame extends JFrame implements ActionListener { + protected MonitorTablePanel tablePanel = null; + protected JMenuItem copyMI = null; + protected JMenuItem exitMI = null; + protected JMenuItem aboutMI = null; + protected JMenuItem activateSubMI = null; + protected JMenuItem deactivateSubMI = null; + protected JMenuItem selectAllMI = null; + protected JCheckBoxMenuItem timeShadingMI = null; + protected JCheckBoxMenuItem viewTablesMI = null; + + public MonitorFrame(String qmgrName, String qName, String topicName) { + super("Replication Montior - " + qmgrName + " : " +((qName!=null)?qName:topicName) ); + + getContentPane().setLayout( new BorderLayout() ); + + tablePanel = new MonitorTablePanel(qmgrName, qName, topicName); + getContentPane().add("Center", tablePanel); + + JMenuBar menuBar = buildMenuBar(); + setJMenuBar(menuBar); + } + + + /** + * Create the menubar on the frame. + * @return JMenuBar The menubar. + */ + protected JMenuBar buildMenuBar() { + JMenuBar menuBar = new JMenuBar(); + + JMenu menu; + + // Build the File menu + menu = new JMenu("File"); + exitMI = new JMenuItem("Exit"); + exitMI.addActionListener(this); + menu.add(exitMI); + menuBar.add(menu); + + // Build the Edit menu + menu = new JMenu("Edit"); + copyMI = new JMenuItem("Copy"); + copyMI.addActionListener(this); + menu.add(copyMI); + menuBar.add(menu); + + // Build the Selected menu + menu = new JMenu("Selected"); + selectAllMI = new JMenuItem("Select All"); + selectAllMI.addActionListener(this); + menu.add(selectAllMI); + menuBar.add(menu); + + // Build the View menu + menu = new JMenu("View"); + viewTablesMI = new JCheckBoxMenuItem("Tables"); + viewTablesMI.addActionListener(this); + menu.add(viewTablesMI); + timeShadingMI = new JCheckBoxMenuItem("Time Shading"); + timeShadingMI.addActionListener(this); + menu.add(timeShadingMI); + menuBar.add(menu); + + // Build the Subscription menu + menu = new JMenu("Subscription"); + activateSubMI = new JMenuItem("Activate..."); + activateSubMI.addActionListener(this); + menu.add(activateSubMI); + deactivateSubMI = new JMenuItem("Deactivate..."); + deactivateSubMI.addActionListener(this); + menu.add(deactivateSubMI); + menuBar.add(menu); + + // Build the File menu + menu = new JMenu("Help"); + aboutMI = new JMenuItem("About..."); + aboutMI.addActionListener(this); + menu.add(aboutMI); + menuBar.add(menu); + + return menuBar; + } + + + /** + * This is called whenever a user picks a menu item. + * @param e The event for the action. + */ + public void actionPerformed(ActionEvent e) { + Object source = e.getSource(); + if (source == timeShadingMI) { + tablePanel.setTimeShading( timeShadingMI.isSelected() ); + } else if (source == viewTablesMI) { + tablePanel.setShowTables( viewTablesMI.isSelected() ); + } else if (source == copyMI) { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + StringSelection ss = new StringSelection(tablePanel.getSelectedContentsAsString()); + clipboard.setContents(ss, ss); + } else if (source == selectAllMI) { + tablePanel.selectAll(); + } else if (source == exitMI) { + System.exit(0); + } else if (source == aboutMI) { + JOptionPane.showMessageDialog(this, "DB2 Replication Sample"); + } else if (source == activateSubMI) { + manageSubscriptions(true); + } else if (source == deactivateSubMI) { + manageSubscriptions(false); + } + } + + /** + * This will prompt the user for the subscription name, and then either activate or deactivate it. + * @param isActivate true: the user wants to activate a subscription. False : they want to deactivate it. + */ + protected void manageSubscriptions(boolean isActivate) { + + // Craete and show sub dialog. + SubscriptionDialog subDialog = new SubscriptionDialog(this, + (isActivate? "Activate Subscription" : "Deactivate Subscription") ); + subDialog.pack(); + subDialog.show(); + + if ( subDialog.wasOkPressed() ) { + ControlMsg msg = null; + String subscriptionName = subDialog.getSubscriptionName(); + String qManager = subDialog.getQueueMgrName(); + String qName = subDialog.getQueueName(); + if (subscriptionName != null && qManager != null && qName != null && + subscriptionName.length()>0 && qManager.length()>0 && qName.length()>0 ) { + if (isActivate) { + System.out.println("Attempting to activate subscription " + subscriptionName + " at queue manager " + qManager + " on admin queue " + qName); + msg = new ActivateSubscriptionMsg(subscriptionName); + } else { + System.out.println("Attempting to deactivate subscription " + subscriptionName + " at queue manager " + qManager + " on admin queue " + qName); + msg = new DeactivateSubscriptionMsg(subscriptionName); + } + + try { + msg.send(qManager, qName); // Send the request + } catch (Exception ex) { + System.out.println("Message failed...error " + ex); + } + } else { + System.out.println("Message not sent because either subscription name, queue manager, or queue name was not specified"); + } + } + + } + +} diff --git a/repl/xmlpubtk/sample3/MonitorTablePanel.java b/repl/xmlpubtk/sample3/MonitorTablePanel.java new file mode 100644 index 0000000..a3198b4 --- /dev/null +++ b/repl/xmlpubtk/sample3/MonitorTablePanel.java @@ -0,0 +1,149 @@ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.table.*; +import javax.swing.event.*; +import java.util.*; + + +/** + * The MonitorTablePanel creates a JTable to show the values. It starts a timer, and checks + * the PublicationListener every few seconds to get any recent updates. If there were updates, + * it adds them to the values that are currently showing in the JTable. + * + * @author tjacopi + * + */ +public class MonitorTablePanel extends JPanel implements ActionListener { + + protected JScrollPane tableScrollPane; + protected PublicationTableModel tableModel; + protected PublicationTableCellRenderer cellRenderer; + protected PublicationListener pubListener; + protected JTable table; + protected javax.swing.Timer timer = null; + protected int currentInterval = 0; + protected int lastUpdateInterval = 0; + + public MonitorTablePanel(String qmgrName, String qName, String topicName) { + + setLayout( new BorderLayout() ); + + // The pubListener will listen to the queue + pubListener = new PublicationListener(qmgrName, qName, topicName); + pubListener.start(); // Start listening to the queue + + // Now setup the JTable + PublicationDataModel pdm = new PublicationDataModel(); // Build a new model of the data + tableModel = new PublicationTableModel(pdm); // The model for the table uses the data model + table = new JTable(tableModel); + tableScrollPane = new JScrollPane(table); + + // Tell each column to use our custom cell renderer. This is to paint the DB total lines in + // bold, as well as set the background for recent updates columns. + TableColumnModel colModel = table.getColumnModel(); + cellRenderer = new PublicationTableCellRenderer(); + int colCount = colModel.getColumnCount(); + for (int i=0; i0) { // Was anything updated? + lastUpdateInterval = currentInterval; // ..yes + tableModel.addNewData(pdm, currentInterval); // ..and add the new data to the existing ones + } else { // ..no updates + if (lastUpdateInterval + 2 >= currentInterval && // If we had recent updates, force a + cellRenderer.getTimeShading() ) { // and we are time shading + table.repaint(); // ..then we need to repaint so recent updates fade out + }; + } + } + + /** + * This is called whenever the timer pops. + */ + public void actionPerformed(ActionEvent e) { + // We cannot call checkForDataUpdates() directly here, because we are on + // the timer thread. Instead, post a msg to the event thread. + SwingUtilities.invokeLater( new CheckDataRunnable() ); // Post to event thread + } + + class CheckDataRunnable implements Runnable { + public void run() { + checkForDataUpdates(); // runs on event thread + } + } +} diff --git a/repl/xmlpubtk/sample3/PublicationDataModel.java b/repl/xmlpubtk/sample3/PublicationDataModel.java new file mode 100644 index 0000000..c65e9c4 --- /dev/null +++ b/repl/xmlpubtk/sample3/PublicationDataModel.java @@ -0,0 +1,235 @@ +import java.util.*; +import com.ibm.db2.tools.repl.publication.*; + + +/** + * The PublicationDataModel class holds the actual data that is keeping track of the updates. + * It does this in two hashtables: + * + * data: This is the raw data. + * Key: Database name (String) + * Value: A Hashtable + * Key: Table Name (TableName) + * Value: The count of updates for that table (Count). + * + * dbTotals: This is a cache of all the total counts for a database. + * Key: Database name (String) + * Value: The count of all the updates for this database. + * + * @author tjacopi + * + */ +public class PublicationDataModel { + + protected Hashtable data = new Hashtable(); + protected Hashtable dbTotals = new Hashtable(); + + /** + * All the database names. + * @return Enumeration The list of Strings (database names). + */ + public Enumeration getDbNames() { + return data.keys(); + } + + /** + * Get the number of databases. + * @return int The number of unique dbs. + */ + public int getDbNameCount() { + return data.size(); + } + + /** + * Get all the table names for a specific database. + * @param dbName The database name + * @return Enumeration The list of TableName objects. + */ + public Enumeration getTableNamesForDb(String dbName) { + Enumeration enum = null; + Hashtable ht = (Hashtable) data.get(dbName); + if (ht != null) { + enum = ht.keys(); + } + return enum; + } + + /** + * Gets the Count object for the database & table name. + * @param dbName The database name + * @param tableName The table name. Null if you want the count for all the tables in the database + * @param createIfNotPresent True: create a new entry if dbName & tableName not found. False, just return null. + * @return Count The count for that database/table. + */ + public Count getCountFor(String dbName, TableName tableName, boolean createIfNotPresent) { + Count count = null; + if (tableName == null) { + count = (Count) dbTotals.get(dbName); + } else { + Hashtable dbValues = (Hashtable) data.get(dbName); + if (dbValues == null) { + if (createIfNotPresent) { + dbValues = new Hashtable(); + data.put(dbName, dbValues); + } else { + return null; + } + }; + + count = (Count) dbValues.get(tableName); + if (count == null) { + if (createIfNotPresent) { + count = new Count(); + TableName tn2 = new TableName(tableName.ownerName, tableName.tblName); + dbValues.put(tn2, count); + } else { + return null; + } + }; + } + + return count; + } +/* + public Hashtable getData() { + return data; + } + + public Hashtable getDbTotals() { + return data; + } +*/ + + /** + * Adds the new values to the data. + * @param dbName The database name + * @param tableName The table name. + * @param updateCount The count to add. + * @param currentInterval The updates came from this interval. + * @param recalcDbTotals True: recalc the totals for the db. False, do not recalc. If you have many updates + * for the same DB, only change this flag to true for the last update. + */ + public void add(String dbName, TableName tableName, Count updateCount, int currentInterval, boolean recalcDbTotals) { + Count count = getCountFor(dbName, tableName, true); + + count.add(updateCount, currentInterval); + + if (recalcDbTotals) { + recalcDbTotalsFor(dbName); + }; + + } + + /** + * Adds the new data to the existing data. + * @param newPubModel The new data. + * @param currentInterval The updates came from this interval. + */ + public void add(PublicationDataModel newPubModel, int currentInterval) { + Vector updatedDbs = new Vector(); + + for (Enumeration enum = newPubModel.getDbNames(); enum.hasMoreElements();) { + String dbName = (String) enum.nextElement(); + updatedDbs.add(dbName); + for (Enumeration enum2 = newPubModel.getTableNamesForDb(dbName); enum2.hasMoreElements();) { + TableName tableName = (TableName) enum2.nextElement(); + Count newCount = newPubModel.getCountFor(dbName, tableName, false); + + add(dbName, tableName, newCount, currentInterval, false); + } + } + + for (int i=updatedDbs.size()-1; i>=0; i--) { + String dbName = (String) updatedDbs.elementAt(i); + recalcDbTotalsFor(dbName); + } + + } + + /** + * Adds the new data to the existing data. + * @param pubMsg All data in this Transaction will be added. + */ + public void add(TransactionMsg pubMsg) { + TableName tempName = new TableName(); + String dbName = pubMsg.getDbName(); + + Vector rows = pubMsg.getRows(); + for (int i=rows.size()-1; i>=0; i--) { + Row row = (Row) rows.elementAt(i); + processRow( dbName, row, tempName); + } + } + + + + /** + * Adds the new data to the existing data. + * @param rowMsg All data in this Transaction will be added. + */ + public void add(RowOperationMsg rowMsg) { + TableName tempName = new TableName(); + + String dbName = rowMsg.getDbName(); + processRow( dbName, rowMsg.getRow(), tempName); + } + + /** + * Adds the data from one row to the existing data. + * @param dbName The database name + * @param tempName A temporary tableName object we can use (so we dont need to create a new one each time) + * @param row The row. + */ + private void processRow(String dbName, Row row, TableName tempName) { + + if (row != null) { + Count count = null; + tempName.ownerName = row.getSrcOwner(); // do this so we dont have to reallocate new TableName objects when we find existing ones + tempName.tblName = row.getSrcName(); + Count tempCount = getCountFor(dbName, tempName, true); + + int rowOperation = row.getRowOperation(); + if (rowOperation == Row.InsertOperation) { + tempCount.rowsInserted++; + } if (rowOperation == Row.DeleteOperation) { + tempCount.rowsDeleted++; + } if (rowOperation == Row.UpdateOperation) { + tempCount.rowsUpdated++; + }; + } + + } + + + /** + * Rebuilds the dbTotals hashtable based on all the data. + * @param dbName The database name + */ + private void recalcDbTotalsFor(String dbName) { + Hashtable myDbValues = (Hashtable) data.get(dbName); + if (myDbValues != null) { + Count newCount = new Count(); + int maxInsertInterval = 0; + int maxDeleteInterval = 0; + int maxUpdateInterval = 0; + for (Enumeration enum = myDbValues.elements(); enum.hasMoreElements();) { + Count count = (Count) enum.nextElement(); + if (maxInsertInterval < count.lastInsertInterval) { + maxInsertInterval = count.lastInsertInterval; + }; + if (maxUpdateInterval < count.lastUpdateInterval) { + maxUpdateInterval = count.lastUpdateInterval; + }; + if (maxDeleteInterval < count.lastDeleteInterval) { + maxDeleteInterval = count.lastDeleteInterval; + }; + newCount.add(count, 0); + } + newCount.lastDeleteInterval = maxDeleteInterval; + newCount.lastUpdateInterval = maxUpdateInterval; + newCount.lastInsertInterval = maxInsertInterval; + dbTotals.put(dbName, newCount); + } + } + +} diff --git a/repl/xmlpubtk/sample3/PublicationListener.java b/repl/xmlpubtk/sample3/PublicationListener.java new file mode 100644 index 0000000..85180e9 --- /dev/null +++ b/repl/xmlpubtk/sample3/PublicationListener.java @@ -0,0 +1,132 @@ +import com.ibm.db2.tools.repl.publication.*; +import com.ibm.db2.tools.repl.publication.support.*; +import javax.jms.*; +import java.util.*; +import com.ibm.mq.jms.MQQueueConnectionFactory; +import com.ibm.mq.jms.MQTopicConnectionFactory; + + +/** + * The PublicationListener class sets up access to MQ and listens for messages via the XML Publication toolkit. + * + * @author tjacopi + * + */ +public class PublicationListener implements PublicationMsgListener { + + protected volatile PublicationDataModel updates = new PublicationDataModel(); + protected volatile Object latch = new Object(); + protected volatile boolean bStop = false; + + protected String qMgrName = null; + protected String qName = null; + protected String topicName = null; + + + public PublicationListener(String aQueueMgrName, String aQueueName, String aTopicName) { + qMgrName = aQueueMgrName; + qName = aQueueName; + topicName = aTopicName; + } + + + /** + * Start listening to the queue. This will create a new thread to do + * the listening, and return after the thread starts. + */ + public void start() { + bStop = false; + QListenerThread thread = new QListenerThread(); + thread.start(); + } + + /** + * Stop listening to the queue. This will set a stop flag and just return. The + * listener thread will stop within 10 seconds. + */ + public void stop() { + bStop = true; + } + + + /** + * Get all the current updates. This will retrieve all the updates since the last getUpdates() + * call, and reset the updates. The method is threadsafe, and can be called from any thread. + * @return PublicationDataModel All the updates. + */ + public PublicationDataModel getUpdates() { + PublicationDataModel dm = null; + synchronized(latch) { // Lock to keep out any new publicationMsg notifications + dm = updates; // ..get old updates... + updates = new PublicationDataModel(); // ..and reset for new updates + } + return dm; + } + + /** + * This is called by the publicationListener whenever a new publication msg is received. + * @param pubMsg The publiction message. + */ + public void publicationMsg(Msg pubMsg) { + System.out.println("msg received of type " + pubMsg.getClass().getName()); + + if (pubMsg instanceof TransactionMsg) { + TransactionMsg tm = (TransactionMsg) pubMsg; + synchronized(latch) { // Lock to keep out getUpdates() call + updates.add(tm); // Add the values in the msg to our stored updates + } + + } else if (pubMsg instanceof RowOperationMsg) { + RowOperationMsg rm = (RowOperationMsg) pubMsg; + synchronized(latch) { // Lock to keep out getUpdates() call + updates.add(rm); // Add the values in the msg to our stored updates + } + }; + + } + + + class QListenerThread extends Thread { + public void run() { + try { + MessageConsumer messageConsumer = null; + + if (qName != null) { + System.out.println("Connect to queue " + qName + " in queue manager " + qMgrName); + // Create the JMS MQ objects to read from the queue + MQQueueConnectionFactory factory = new MQQueueConnectionFactory(); + factory.setQueueManager( qMgrName ); + QueueConnection connection = factory.createQueueConnection(); + connection.start(); + QueueSession session = connection.createQueueSession( false, Session.AUTO_ACKNOWLEDGE); + Queue receiveQueue = session.createQueue( qName); + QueueReceiver queueReceiver = session.createReceiver( receiveQueue, null ); + messageConsumer = queueReceiver; + } else { + System.out.println("Connect to topic " + topicName + " in queue manager " + qMgrName); + // Create the JMS MQ objects to read from the queue + MQTopicConnectionFactory factory = new MQTopicConnectionFactory(); + factory.setQueueManager( qMgrName ); + TopicConnection connection = factory.createTopicConnection(); + connection.start(); + TopicSession session = connection.createTopicSession( false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic( topicName ); + TopicSubscriber topicSubscriber = session.createSubscriber( topic); + messageConsumer = topicSubscriber; + } + + // Create the PublicationMsgProvider which will listen to the queue, parse the xml messages, + // and dispatch them to us. + PublicationMsgProvider msgProvider = PublicationMsgProviderFactory.createPublicationMsgProvider(); + msgProvider.addPublicationMsgListener(PublicationListener.this); // Notify us of any messages + while (!bStop) { + msgProvider.dispatchMsgs(messageConsumer, 10000, true); // Dispatch with a 10 sec timeout + } // true = ignore errors. + + } catch ( Exception caught ) { + System.out.println("QListenerThread Caught " + caught); + caught.printStackTrace(); + } + } + } +} diff --git a/repl/xmlpubtk/sample3/PublicationTableCellRenderer.java b/repl/xmlpubtk/sample3/PublicationTableCellRenderer.java new file mode 100644 index 0000000..0aed672 --- /dev/null +++ b/repl/xmlpubtk/sample3/PublicationTableCellRenderer.java @@ -0,0 +1,109 @@ +import java.util.*; +import java.awt.*; +import javax.swing.table.*; +import javax.swing.*; + + +/** + * The PublicationTableCellRenderer will do the following: + * 1. Show the database summary lines in bold + * 2. Right justify the numbers. + * 3. Shade the background of the recently updated cells. + * + * @author tjacopi + * + */ +public class PublicationTableCellRenderer extends DefaultTableCellRenderer { + + protected Font defaultFont = null; + protected Font boldFont = null; + protected Color normalBackground = null; + protected Color recentUpdateBk1Color = new Color(195, 255, 255); + protected Color recentUpdateBk2Color = new Color(190, 255, 255); + protected Color recentUpdateBk3Color = new Color(230, 255, 255); + protected int currentInterval = 0; + protected boolean bShowTimeShading = false; + + + /** + * Set if the cell backgrounds should be different if the values where recently changed. + * @param timeShading true = shade the rows that recently changed. False = use the standard background + */ + public void setTimeShading(boolean timeShading) { + bShowTimeShading = timeShading; + } + + /** + * Get the current value of the time shading. + * @return boolean true = shade the rows that recently changed. False = use the standard background + */ + public boolean getTimeShading() { + return bShowTimeShading; + } + + /** + * This lets the renderer know what the current interval is (for timeshading). Cells that + * are within two intervals of this one have a different background. + * @param newInterval The new interval. + */ + public void setCurrentInterval(int newInterval) { + currentInterval = newInterval; + } + + + /** + * Called when the JTable renders a cell. + */ + public Component getTableCellRendererComponent(JTable table, + Object value, + boolean isSelected, + boolean hasFocus, + int row, + int column) { + JLabel c = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + PublicationTableModel tm = (PublicationTableModel) table.getModel(); + if (defaultFont == null) { // If first time + defaultFont = c.getFont(); // ..then save the current font as the default + boldFont = defaultFont.deriveFont(Font.BOLD); // ..and create a bold version of it + normalBackground = getBackground(); // ..and save the background + }; + + if (tm.isDbRow(row) ) { // If is a database row + c.setFont(boldFont); // ..then use bold + } else { + c.setFont(defaultFont); // ..else just use the default font + } + + if (column == 0) { // If the database name column... + if (!isSelected) // ..and selected... + c.setBackground(normalBackground); // ..then use the default background + c.setHorizontalAlignment(SwingConstants.LEFT); // and left justify + } else { + if (!isSelected) { // Only timeshade unselected rows + if (bShowTimeShading && value instanceof StringWithInterval) { + StringWithInterval intervalString = (StringWithInterval) value; + int cellInterval = intervalString.getInterval(); + int intervalDelta = currentInterval - cellInterval; + switch (intervalDelta) { + case 0: + c.setBackground(recentUpdateBk2Color); + break; + case 1: + c.setBackground(recentUpdateBk3Color); + break; + default: + c.setBackground(normalBackground); + break; + } + } else { + c.setBackground(normalBackground); + } + } + + c.setHorizontalAlignment(SwingConstants.RIGHT); + } + + return c; + } + +} diff --git a/repl/xmlpubtk/sample3/PublicationTableModel.java b/repl/xmlpubtk/sample3/PublicationTableModel.java new file mode 100644 index 0000000..c3720bf --- /dev/null +++ b/repl/xmlpubtk/sample3/PublicationTableModel.java @@ -0,0 +1,254 @@ +import java.util.*; +import javax.swing.table.*; + + +/** + * The PublicationTableModel class supplies the logic that maps from an AbstractTableModel to + * the PublicationDataModel (which actually holds the data). It knows if we are doing things + * like actually showing the detail for tables. + * + * The mapping is done via the dataMapping and rowIndexes variables as follows: + * dataMapping: This is a vector that holds a list of "DataMap" structures, one per database. + * A dataMap has the database name, and a list of tables in that database that + * we are displaying. + * rowIndexes: This is the JTable row index of the database entry for the DataMap. + * If we are not showing the tables, then the rowIndex maps directly to the DataMap + * (ie, the third row index is the thrid DataMap). + * What this does is help us find the correct DataMap via a rowIndex more quickly. + * When the JTable calls getValueAt(row, col), then we can translate the row to the + * correct DataMap more quickly. + * + * @author tjacopi + * + */ +public class PublicationTableModel extends AbstractTableModel { + + protected static final int NUM_COLS = 4; + protected static final String[] colNames = {"Name", "Rows Inserted", "Rows Updated", "Rows Deleted"}; + + protected PublicationDataModel dataModel = null; + protected Vector dataMapping = new Vector(); + protected int[] rowIndexes = null; + protected boolean bShowTables = false; + + public PublicationTableModel(PublicationDataModel model) { + dataModel = model; + buildDataMapping(); + } + + public String getColumnName(int col) { + return colNames[col]; + } + + public int getColumnCount() { + return colNames.length; + } + + public int getRowCount() { + int count = dataMapping.size(); // Add all the Database summary lines + if (bShowTables) { + for (int i=dataMapping.size()-1; i>=0; i--) { // Then for each one.... + DataMap map = (DataMap) dataMapping.elementAt(i); + if (map.tableNames != null) { + count = count + map.tableNames.size(); // add the number of tables in that db + }; + } + } + + return count; + } + + + /** + * The JTable calls this to the the value of a particular cell. + * @param row The row. + * @param col The column. + * @return Object The object to be shown in the cell. + */ + public Object getValueAt(int row, int col) { + Object value = null; + + if (bShowTables) { // Are we showing the tables? + int dbIndex = 0; + boolean bStop = false; + for (int i=1; i= rowIndexes[i]) { + dbIndex = i; // The previous one is the one we want + } else { + bStop = true; // Aaah, past the index, so we can leave + } + } + + DataMap map = (DataMap) dataMapping.elementAt(dbIndex); + int remainingIndex = row - rowIndexes[dbIndex]; // Calc the index into the tables list + if (remainingIndex == 0 ) { // if its a 0, then its a database summary entry + if (col == 0) { + value = map.dbName; + } else { + Count count = dataModel.getCountFor(map.dbName, null, false); + value = getDisplayCol(col, count); // And create a StringWithInterval object to display it + } + + } else { // Its a table entry... + TableName tableName = (TableName) map.tableNames.elementAt(remainingIndex-1); // get the table name + if (col == 0 ) { + value = " " + tableName; // add spaces so name appears indented under db name + } else { + Count count = dataModel.getCountFor(map.dbName, tableName, false); + value = getDisplayCol(col, count); // And create a StringWithInterval object to display it + } + } + + } else { // We are not showing the tables. + DataMap map = (DataMap) dataMapping.elementAt(row); // Just use the row as a direct index to the DataMap + if (col == 0) { + value = map.dbName; + } else { + Count count = dataModel.getCountFor(map.dbName, null, false); // Get the summary count + value = getDisplayCol(col, count); // And create a StringWithInterval object to display it + } + } + + return value; + } + + /** + * Add a new data model to the existing one. + * @param newData The new data. + * @param interval This data was created in this interval (used for timeshading) + */ + public void addNewData(PublicationDataModel newData, int interval) { + dataModel.add(newData, interval); + buildDataMapping(); + fireTableDataChanged(); + } + + /** + * Gets the index of the DataMap object for this JTable row. + * @param row The row in the JTable. + * @returm int The index of the DataMap. + */ + protected int getDataMapIndexForRow(int row) { + int dbIndex = 0; + if (bShowTables) { + boolean bStop = false; + for (int i=1; i= rowIndexes[i]) { + dbIndex = i; // The previous one is the one we want + } else { + bStop = true; + } + } + } else { // Not showing tables, so the indexes map directly + dbIndex = row; + } + + return dbIndex; + } + + + /** + * Crteate the correct object used to display the value for the column. The first + * column uses a string (db name and table names), the others use a StringWithInterval. + * @param col The column being displayed + * @param count The Count for the column. + * @returm Object Either a String or StringWithInterval. + */ + private Object getDisplayCol(int col, Count count) { + int intValue = 0; + int interval = 0; + + if (col == 1) { + intValue = count.rowsInserted; + interval = count.lastInsertInterval; + } else if (col == 2) { + intValue = count.rowsUpdated; + interval = count.lastUpdateInterval; + } else if (col == 3) { + intValue = count.rowsDeleted; + interval = count.lastDeleteInterval; + } + + String text = Integer.toString(intValue); + + return new StringWithInterval(text, interval); + } + + + /** + * This function builds an array that maps every row number to a specific entry + * in the data model. + */ + private void buildDataMapping() { + int numDbs = dataModel.getDbNameCount(); + rowIndexes = new int[numDbs]; + dataMapping = new Vector(numDbs); + int rowNum = 0; + int dbCounter = 0; + + for (Enumeration enum = dataModel.getDbNames(); enum.hasMoreElements();) { + String dbName = (String) enum.nextElement(); + rowIndexes[dbCounter] = rowNum; + rowNum++; // increment for the db line + Vector tableNames = new Vector(); + for (Enumeration enum2 = dataModel.getTableNamesForDb(dbName); enum2.hasMoreElements();) { + TableName tableName = (TableName) enum2.nextElement(); + tableNames.add(tableName); + rowNum++; + } + + dataMapping.add( new DataMap(dbName, tableNames) ); + dbCounter++; + } + + } + + + /** + * Is the row index for a databse summary row? + * @param row The index. + * @return boolean True: the index is a summary row. False : its a table row + */ + public boolean isDbRow(int row) { + boolean dbRow = false; + if (bShowTables) { + for (int i=0; iMv}ph zjf5>BKte)@At69o)a)C`P^W~12HK>rTh_K&`}~Ja){__>Je(XIYulepj}E4WJL7BG&x>@WlZmn9K--p+ z`h7wB+IZ9UEj{tBRC*+pPK=RnRV0$D?9IpDyk_p7{d`BdL`458sjMqCK0MamKa?09 z{n~GS{{>>&Wl2OTBvv6|nXf^E1`9N3)L@|oi(HAjve*$Xow{Xo`|xNoO+y@UwmVX( zQCpKkNfTqf_Kgf^Lmi1y(U{G?eRwRHK9LymBW;#~NDCzwS-xR#cyMf!Bc)BN_B#^l zN)03(sp=jaPWFx;Ka@=GO&l5`rZh1?WtC0crhDtRYv#zF)Ofl-xouE0L~OrrN}Nb| zQX^4MB2wvzr@<@@W@}KTLA6vmQfBfyQmrLc4<&|=tloL(reyz^EM_z+7`AdI85q2U z6pVQS$vgpOp1?CtK=LdRN2?~R|rBHb;|NXg?;*WAog-*42q7El8prG7%G zzLQX@2`(QYKOv;=B!o1fJlB$DIxjMh_SDm|82=h1E(@fMcC3{}axq`q7_1$#l=jRc zZ;90Bqvo>*FZ=i>7z+K1lA$NXT&L38(uw2Ad<=COUAZFyoVSPN9s0a8EO+Vi?uZ_i6BM4erggW0Ik@v~_U3oadxP8E+gyj*9 z{GfiE(%?~79*fYix4ZJ8uzWZo3*{bH9uLb$B6RN_4W7`*CpFVkVfkoSe#blE*bm^47sI&Eh5wrN+(MtVI9V;0cJ#p7BGPQZpGh3Kei=xYoJo^#9;Ck)6!8bkR?SIH<_ZA zDC`+a191IJV$MmxyhG!ILjzj-mPFc-`leO+?ekL@iz@AAYIs*NeK?gqt~7R$-=M@T zW2=)VlEY)GH=8V%>HB)Ew)S{pIB`UWYP3H+IHKi8p{7j-r_jloyhW%(O=|4S?RCk_6$ z#tsaQ@#q4r9SQF-Sg7+9v9ED3lH~nhmm`gNwH9I_ov;YVzPlIvjr$19XK*gr`E$fYr%Ynu1F4z(3H)(c!+W3pFMe1{*NdBBLC{izsXxX`FDAXEC1oi|CL{R z@*6qp$nxyKvzI5v(uv_wW_`6q0oxVu$a6$~;yRA!lsKiH6OtdhPMPPFJ1(fPb<5g# z5Iy!Jj*ko_T_@~06;8yHH_Kb#27+DLI+z$r9bwip9f}82p%J;R<)tv^PNnB~@?+1L zrNL}^=2U@qPPGO#+Q_Kq)H-uKr_Pz{$g<625Es_M@R9gfDz2+a2QWSwSR`>;7f+1E zZyryMC*yVzrHQPLr-tK+f#ZY2ev<3V^PGD5sUw~JspG2$4;^1UaA@u7u~cekbak2q zvU+6vP-c~w<>`~I?0W1OrPnL++ms_|g{|5!gIaPU6&yn9ah;gw%y$}~3ucN9cXQdT z{YgU@7~`Jg=qThOemDW|GyuXR(`gnpOWIlBNFtLwoEnRdvc}?vlKqMC(PTV1ICeCd z&Ts25n|W*g0Jg>fW`|T$l-!aw$ZU8lWicIs;S=LvK62C*0|>F5eIz;71s!B$ zbcH6;Q2ng)XDmgzw@){%0K?Z{Sl zd?Yn&_JLxNP!6gyTdmo5Vis5)ts}uyR|Ai2HeZ&+}BXk*5u*D_|RB3E{iyUoI35=sFR@S@vfo4kwd9O8uVNmM3Ov$ zo6SVg1}*AuC_avjZXV4b>Z0sW6bE2uJ5$b)p1|zomDuYOd*$7H-bTBSmnYk-owq19 zD<=W!`W#nghzx15ePzp2E{;c&5zpr3t?8YH_Sp4OGs;l=L?*KztO_)>E0w|N0Ndry zr#8dSn?+(nFN&~enm06(=s(6otAy-8igq5`m4^N)6{^+I4r~X#P%9WPVz1H-q31~2 z#(0?+`x%fKGc!{@lpH=XcGM6hc*#=sVF-wA{$OhLE||zM@+K3??OLjw9}Vj}qM3$< z9ch~Z@z+UCr-sa~5`sw6o0a|$+BunyZ`DD`BbAwf4UDzzl}{>>e-0yrIdT-SIHU|7 zqFhLMJoALjGfy}@^Mu(mPxw9agyl0&xIXiQ@iR|HnK+={!q<-ww##_FyZMYbeW#@) zS~@AA7XG4T1g$TN+d3hkHr^+t{Is~u&a)EMphAO)29+9k8qCsQwgy!iR5wpb%^8UT zw{}wIP(@u|OKaO{nX51+WnQ!%!8trBu>*X~?+i7^sHMS5!ne|@Eoclx=1UXucN_0( z5%Sj|Ty8)z-;8X$4RLG-Qu!{V;C;x5{RoRUBO$+)k-JNl$bCr2A>~hPZ%b6MfZXmJ zJR=KeRAcuUS=bj{bXwv)G;VQUbjfL1s=a!Kze!ovsxOnW{6I_Vq^vk#a<9zgZZf$m z$W%e@Rhqk^AU7I_4D1$@dp4P7le<-O&o0Q#(3srqebLpYv0`Wz&Q_tO?b*1m@zBNx5`F-lPc?Ps{S>Wb>qK={+M|eOh=@ zww{*DIzw%-kRtWA3E8bVXFts-o8-$URG?NtF{+wJnA#qLj zo@S(huwz21^?TOSw2Vc%BezU;8wJ);x-p2t>LwP!F$RB#K|aoa4l{r$*^d~QU~vqp z5XisVkptfjA$S+0;C+yS$C$K_vQ$37V)-nC6H*DnAEGh7!pv*Aa3Eu<+Iw5RYOmx67uF&|su(G&$S_4lUuHzztq7L8$A^cN&&b#KNn->| ziRzA08==K@uFQ2M=E{6z;<2NHqsz`?qb#aVs@QXK7&&BYus@)*ncGw(uVDbDRVk;( z*=wy3k*7+YJEb%2%F3ulxynNy8g`|@V{ofr>ZW9!+HY9LDPsXAvV9n?s!P@MNmMlf zmcs7G8R5Zf=9wWZrVL?}`c=2JEtS^Mwp#a5l(QkmmjU80s*UEUT5X+6p(mAmd%P{- z+r$_xbqktfyP{{2rey^zfnhePXU)HiFO5~YR5B^0x!e&0=OOBPA8)#4matLQ^HjBA zh&e_{oR39`hySqq5o*#u)gVt9%>tZxDFT_kp#pk+qXr2L4!P2=sB}Ywj{#Sb5&C*q zQ;z7{QC9{d^z;T-Zi>*4W12GL%JB$|8`h7MDX??70)YFlU*ZsYH(Mj+%30+Rhha%?$tc+ zjIcQG(@%mLdAAn6UmN^@w)R2If+oAh*JO9d`y%pwdDxW?xblcAADj_VRTJ$RxW z9t_bA<~b{=29>&=oRUYG#UeQ1!G`sEvQ;kg*oFGQgg_=GY(8Sv1)_6!sii;U!Lx1l z>1GziO&(4Dum=ZnIhdU%mgZJ~=6T$M{kz1IkH`~_EGVogh}a%{VV5gUdh(Qf)RW(l z-*x3_PbTE|Sed~Z42~-7k3oww3hR%{Cp?(N-5y55y&lZx?sF*Nd*qXzd`dp;$!FxV zu6z#qi>B`L@&!+xk!M|*^yIW0@Z@TphUYZ%^YZ(ioY8iDQU1V_7j!shvQud@zvRk` zo_txpQhcw;SJW8`&uc5{X0Gun8y!oek(^Oe1x7zR{YD9~IA3*S2*>IiDwsU;ifR*- z9k9x~q4DFxK0>W1u*3x5b)~ZTpfXE>(^@=N5WH_+W=TSeR83`}0SEO+9vPbgi^}rM z22(Pyno(E<@zIe2jaslwkRaQiMed=#Zm2A%)wJ z0`?g)Yw|0K)D~;D9#Z9!k2MigvAxM#6!B4jPO}({md(ZZfV$ZRheC{Qy5agW+w z_l*q>4UP>e<5@X4d?Ix$*^Om{{WY_0^0-d00ZqomuwD)lvic@KB;nRVN^i{*T4v`%ssx(fFeyuO zO|V?~76!eG%xpJ)kvPu`A5Z_5eUgScC^0fz|CM~PFA*|Hc@Y>t(vI*Hx+EG3st&NXLq$P?L zr1b!qs$1*I+UuBqRDbQAZi`C7tp`ds-C6F`mDh!yJo}A1%bdEh))$^U`x0eVTg8v| zqLaba35duw$UoP@-(SaoU(X=lz~J798Ysa)_JfcE^fJk~+(7E}C^-k|0DGz5ji9_k zWX(sq!w!{bNxVq(B+uVoCjk?y9>a_5OzGMxL$fT_8rnTp9T<|#YnxO7C z^tQ!jx?n;SnL=eZ>i3gI52SN+%IE}X#f7<6ST~(p>E}t*khkHSb36Tf6G-)D`uP^w zC~u>0Z)X(lqDR*-5_U$LXrsz~-WloW1C`f3Cl}?QTCBMrDe(bvT}QqW#%3c=mE}4Z zxebM~+~B8v_3E3E89jm2RzWM+HdUqd~8J?$ltH23NVVTc3N> ziH+QQD-e+OX|P{Kr2`R)T&-z+`gYKjYa%SN9r|%?C2hanRoSpsZq%5B28T2np|Msg zsFeW)L;j>3*5HUMM>Q8><4qcKlN?i5ogod78W*e7SRpA5Ml`rt8<*C%Q4Pj47t^|bHs3<*+*&$oQ z`h%-{pFMOf#)&Uu=?RK4-MRc34?p9&a?Y)$e_)nMHF5i=&*8RHEAsDL;YKQY%t?Go%uOWD2o+cX38dc zXt*y#*3x%7iCM(+*izPd>^=my%EjtCv)+St+@5iZ^dKN_hHK5viU%cms|P6|xIpgk z#iUE+?H)V*6&c>hpvrz+vQlXez52zjyu)K3yDO6(m~oZW?)IP}8;#WFp|QNzlXuFy zT)EFfU3tF;<#`Z?i5bi=F~YtKF)k9hJy4NhtBsCM}= zefy9GAC^a^l{Sm;e4%5>lghu24&H{Xu#}}hD}$I&#Gd9yk$pt%f)^FZZW(ejLgxZd zky2x<=*={jHp}+4)wpUn?sRQUbzTNNEU9RVG7i3~M0B2&KGtlIXl~bXw7J|(pU9h7&*vR{sTJTlIv~< zqth!09nau>ZD3Y(h9)ExsH3wiR`!a-8&Ao6e?X8$vok7{LMZsRamw#9jT!yQ#h1s`!-a_f|OQ@zRE=emfNgY)tY`bW)$i+q=9X4!t)>Cx zZFRiW)RkeCYsSPJ%}uZ!y_=OiqAlY{L?`ehKWQLt@h9VNd>Qb*Gg3<*=kzjkbvkan zvC#7}*TKaZfejPcq|_fU;}q*eSXdD&_ftKU4a#CJ9CmeQxLIFg;RSrn*DMW=JbL!q z3d+2Fnh9PI8c?BQURxb78x?$ca}3Xd=$&O}>&iZK_LsR1Y{K>-3?ejhG+z*iQKGRW^y%eKI{Gr=mCD(;LbaavS zHm(z$ZPxr)$ZywT+SL{-Z#^wb{FePJ*Rmx>zqC0V@5e!0Gp+{Z z+d$XlcwXppg*sofv>D7$G+xi@(W{qgh zwWWg=2s+IWhIbdWW))h^d3dhJB~CVqR* zvH(=c@JL`C_R#is`irW!)JUO-pftFp)18p*F;oBs^C~*Sb)i`J8EJh=BIelx* zHb0_`9+qiDyC2cs0kVcczZ!*NknRg$+OyK$R#*P4w6R*A6*Z%mwSbEeUt^%8YCl4p z$X_6k{3Rx|Z=g5$CadLJXbip${r!$K<8ja-f5mG2Yr6M6R_pf>R)2^&_eTh>e+zSwS&zhD?t6H_8r<{RMZKJeM^aV$cQMi?`0fSb%1XO>-+dE0vw z|D}Nf84kNtlUz`N0^`C8TDGpjGJc(ElDi-*>-D)IEE_d(lYU$hQBvZ{mI(8Dfd*X~ zY^_xE(%|w+H700qWmu)c4(WEKC&HYQd!FW=C%u)>D{}9YU6qW%ZViwR_sYIXhVXy} zS8K^WR}O|%AS{z>BiO>Pb5$HnuuW%7%+nd9iW-^g^E7dpaWOK*wDMZ%bY|xIB7^N4 znp#=et5wreC#-3$1V|7#gbl-btE;nhz4cU=!JZ$_Ix%Pbn>}RO0pq2Q z9aMevQ%G?cUgh}Bt8Y3!y1M5o;{xYHMR?kV43$csR7d`lI`XGo>&8z@apXeSRat^$ zBSr*UGnN_|?2oHRp+0I;s@bc_MXJH^!?iNU9hg%+i0hpml=p5|?(v|y?{wu|9=;9l z_Hb-?0E?--CnM|_jx^}*T!6vxuEh9}qhmDbsJz$14`K}}@gkE^i1~1_1(42V#<#1b zxUma4>*jOt@ByhK<62pIPKUxbs`w7yoON*wsIs%{a6n#zM|~}?#p&c#HC0%5O6%GT zqu+0iITj!oMvtroKryf&nHI#X`oBmb1L|9jq5;@@kkr9kOnFTQvo@D(X+IUX=KRa8 z2JKCy*>aTuV4Rl-ifz6ak+I}tp#pBUEwww@pBy})TJ=q~V4#L#&Z@pmC<`f59*7lY z4Oxuw2d`k+6b@cNa{k~IBtj!>i%opC^M!*JOwAv(U<$HK0N85}nkfsoYFoN@S0KBc3P%kfs*;(i;Hivz6z;A;k#m2!D zT@SN*19Er*5%Um+y?&&j0hrPxUx%@c96@(@6uIdpd=`e_;g7?g56jo^2K{q*iNA)G z_$9esMLhghIEeo%C!KP+&8a{eIfv&$PLM5@w>s;GaJ6YlL$Bi;*#~crv(Oz|7)1Rwf;;tW%YKM+KbsMXp?|&rS{2Yp_8B z*x3fzK_9KDQ~n%OlFq>gSaaByG#gmPoJb+c;cf;g|t) z;f|X__bku3#l0ig1&4GEvy1|&!L0HzxMBl4e=u)WIhNs1f;&&vLUD1CjWAH54`gc0 zIo&Zc8@O-&7&XLY#s>6}oVOYj%osFgKoGNP{oqXk=itj%35PF>IwpAt-tjy=w;gs5 zscnhJs#)e?L|x%Q=m?r*#mrbvl>+v7P(Y4!8b={)1=F0?g{?Y1dL)h^LAj2Bct^_ ztj-m|C6S3YTibsfH;ty&IP}uNJnguNWcRN!wiv@z`}tgoShj8&raQovzfu0%THXH3 zjb$Ky1JnV@~3+=T0 zeA;~xy1tF{K?x{I{R;~i8K3hRIR-!R(GF**=!Y~6w zIT$4AT;xNy{a1Z*l{a6dfA*jC=q10M| z(`gIa>RRchXFW!d-Gd@~HyWWn!UT%!Q`wHHNZ0%V`$Llu7G*Ky?l}K2@91^Sg3r$LfPp0N-zDmR0H^gg|bD1E)8H87RhC< zatdfGUF8#I`Fw&pn4|WpQh$h9$}9K*J`1yar-*u0dd*TVhP;5i!sYCdR1Vnls@pg# z2=%cWvYzwQ2CT~!n_ZhB(2eXcZI_6mjjANb&fAKkS%$o8Mf;kKl>} zAMnmJevkP*F>~;Gy-9WRwb);i*{%bNV^(%}ZJr2f0vId%5zU&agC&3$TtLwv)XWlc z2S>La!k()hu-nxF?xG&c0L`s9jWOJdo)HKFt@U~D?7W*?bIEl@Dm{1`#S%lChX#)f zTQj{HmNU~~Z0_65j<5(?sE(YV6mKELD)Y?k%64}KkxV?eWS*dtd4f?qb(hYG=MVWp z_(8KvvlW-a`EHixhdoS)0yHV?Z%J;ngFCTGqbweXx zj`otRtwV>AmTDMj`Z)!CYCop8`7WPkAP#f#8_0?f| z^j^f1)n$*J{USzPql&;x+^jB-)jF6ev4=1z>6mip71vg*QfelwJtb8!mt+i1b0)+y z@0`u5t1Ew0VmMUV7|PC#x#XWWAt#Adn{?$VxuNyTQh!RWZhcYeJ1b&nL1G=|=y6?S zprf*`@)NXk4Szax`kzYDIxNdgHRws^qd+k46m6K0dh|C!8GLoVu&X=Y$E19~ zxP50+^HuIyE7kPJv5MNM^4;bPakMV<=aj%vQy1-daBs_#?SoxW$a&k^{GzaY1J`U> zs8{NF<~XIt5{|gC2px9OGMSNwR{C>rF1w4}eGRRnNyYaxi8D*e;i{vGo{dzLrV%`& z+AO}*=B%i~J_`#5H^kRPeCslpVxkUCgp0&SfCAsTnNYffjNCa*f=G#WccDnU6yn)33omgdnMJILVgkY0FY`+EP7p zZ_)s_*&+3qT_eM;f66i{H-yz;HmV0LqcW-iM=ghBT(h01;0XAw8l2SNHVtmq;7uBE z(h?^`SC3dO*2@Bi^pIt#9 z)}~e1Rhmp(VZ^D7ED;EnqjA_5H6! zFxCAP5V*f`V%VI$^w>N>>YQWmIn;@vIRB}mEC(we)8mtm%SSvsi*|bKxBFaq%Hw)~ z4n6xw@Vgp3t-*u_99D7VV_F2~;G&X2mwepgng=@4<)3eKiXG0am|81#>r z`EI{6aa*{to_MYE`s4)~1{!c}7Z6L!vD$QGVRD_JpoW<@wOmhA#g=D@N`ef1^#DfVB-YWLX)-tE9;Bm^|s;8 z`?Abx&?otC+;C^f*##du`@@D@J+^D-!K|)%5f~sG9q%(`#%0s`YUU=`p*82I6qbY=2TBb>$tQ2`LYCl$ld?n()F?f@FE>?Dw>d z>e;J}>~w9RQ2RhfxGwytv@9^9C0@u}d~=GdB{7!|2Qjp&v!Z!HtOCU`NpI2US#{yi zfB{s~SwX=D|3
f}0=I2$H>bmf^}UR#xg6ZM0?u$d19>G{gB@TE*9?Z;eh!Q?mT)G7WCJMst)jW+R0!| z*fW7qZD$L!UJq*P919zutee3q7{QzgvM(#)NJt-3S!WX>IAI zkWO7JGcQj{MO_HgDhqA8Gvw5%Pl8UR*Ldpe4~cEqxFCm4_T1o|jK*EmcsHnW4>jtY zLGNT0-N#zFhxPj)Nc9kT;2Qi^JWQL)X+=-zCh(~t^n}#lhdzH3L4!7CMMIg5TA)#l z8dcj+j&Cnt3pHv{N2u{R{GH46sxwa7hHyO2O_Fu?eVi&kLTABFT$roiGwNY88sRdQ zz+|+*W1I(zaUnNyt(Q;29etYout$Cq|APjqv+rX%*c^u4(A@CFh!PDYA`Pcy8C0Zn zW2qiOC3(5}nIBc>aBQ+K%1YymU*5Q2=ba^vPj&FYR`g;eH>qpze0AzInQJ&8j3+R+ zt{ot^MsuF^(X)R`cDm>FsUv#%X+ft$hEhi>F&W;UoAq8J!GR21-B5*>a|0d{jd(dP z!o#_R!@leAa^6I{Hsj@dC0@=~sxAS|*|ET;4Ltu~KDs@XT zEJ}vfWH4rBDVK;T4wg5zH#`BJY@}6<`mJcP;MCclDe?r-#8RDa0qEO|>30xlzsp?w z6+-EEFp7O2>hnXYw8v$&$_{cWLDfp!hL3QI7|J#mL~qS?*&_PS>GCf?^k0H@e-8|_ z%>Mjk39Z7&VXURezoOW+*{Qz3^p7Lf?jOj?zS3yhp1x4DeNSImboHLT^5}Vcz91F3 ziYv!(jGD`h&tJBtKvJF;p%r>zPn9dx zuGG%lYB37|VgSi$C^c#%iK!QTA21orWv52bneDKWpPaqh+Z#!wN0Xb= zNA$=pz7j>))?!eKDJIT^Lkm=Gsg51(qvOK{uiA~Vs2u_OaJxm<(RPb2qur_0vCYE+ z+mdQUy4>6WlyMU_!dun{TWcfy z+a5nUK8(_KQ~XVF+qn1!(?%P+D(S>1@1|PqaQyg5 zw47IQ*M`d1_P;j0FuTqFU~*p%P}{KMC->?gy1uIqYs~L#o;01&jpp5Vzi+!g2BAjcfuW6z)>wGi^_6TI6q za5cn5iPayZnS(BS9{=j;Lky{E0XwMmmQf31FKh7tJmf)Au9uY%RMw{7iS1_75Lx_r zsWsfcKH>iB^f}Le*7LL*h*odU5H?eF3)Qw#X&a-`4pP9L0-j;MdWO!?+b^*lh4kvndHm20TExNZk0`0; zxf~5tP%|9RiQz_&b&i-;i7~CpcdA{Ox?l4~{JfoGUXe~JnbmtTV;=bHdQ4bFQT<<0 zs-%ioa7XX0)FG#ThN+-ohMiYiP43=GmE)8ph#4IL)?wckgHFKw#8KcHOFO@_0bB_n z{UxX>P`H|jssW@m?|6X9Ekw9|%XcbIVHe^YvR0b{g;`6j^peY3PgdnxFwW$2E6s_6 z4UZt1=%2xoz}4gS9`ph%c@Lb2-gmN2?>kv1`!zVA0f*bxNuLG>;ZTf!hTed3U4+%f zWhd+OvXgacwIMAmhcvq1|Iou^dg}=upxABd)NWI&w_|dbB{!bb>n)kJa?I8HP8KLY zKEi6n;pu-2=RUCOL|7ps8Uu`*!)n)Q@?q%PXjtt#rYs-+8|THeF}L`^0=-!?6S#8H zHJ5Da-al@PqkFgE-)VM(%q3P=?&T_iZG*|70aigIbBIavx#nDzzJ*f9w&*WFK}yDhl$e(I(81;k(~E?Z*IC2#VSZ`R8`2sUb9E?K-(Z(1~# z4f888)7==^Wo&+)+~Hp~qG}tA3T3^i^w?2zERYZUxApSzrbu(%t<~J)n@X}XmYq@*^_$I4#h8MyGr^w}h+88?t`XaY zQn%z9aj(xXXQA4e$I!R)n7I!HD%fQ(HFz-!x3D}YJC(9d8TCSVncr717YYU>zRl)F zoE*QExx&QwGwBbs6|wpo#>yH2XY%VO*05&g#8iwG)&4SyF75x)-#{tTJN;lZ^EflR zeHlKoIlye@{PcVSqV=@O{33-imde__da;o>o{q1+Z-tB-8uiEy2mxF!=HSnAjvM1;{ z8KpPzd%XmDA0Mn`w2HIs)%u$XHPNW@nbrO|_ifZ}^?Y;L;Pn>{tJqkp;qq!=kfU&R zwd^VNaANc673XZ&nYY7c?t>K#1(f%ngi%lx!kB++M0bn+v_m<1U)3e^QQsGhoz~m? z8VO zq^xYE$xVIHRi~wyMx%Ue(Hrr~7*Bq+!6flR4VuLDcK zXQSOni#CBVmmrm2ifVTY`a8X#LT_ob?NfJYZQlySi#6s5S=rP4#zV-e^43mp3Qp^L z+GzI9&nejKuUB@{yB{*_Ma#FJtU2v@oG%z_dpvJa zF372iEpK)ssk^ee_F!)2^1{O0N6CFv(cBO6&`GxK>ps@jI)yb8E0D0)8)cWr+#^jT$Ts%QAf~cV&epu5_hInUWb_^pq6? zEWw?Y=b!n7P+@LsI%*jjU?PXSwrKDg(l2aU@Ql^$+-O-Y0oGc7r**c{g4wP*EgLQ7 zG-sVW)>#WU(e9}P%3x)|dEndpqS8e%iTw@zbQsvIQ>rKt(kAm3(pK|Shgd5lDF1&x zITUTHa%N1(r|;RNep^-%K8xbYyz7s>&Ncv4)=&WXGER;X8@nf-VgXQA#!-jZ45%8Y zXcQ`13oypg2N_%(pnJ%QIocSzlr*0T^|k@3&DS0*^pDK4=plb@6pM%NZ;DrEgIc=^Jg_Q;j5nU^hZ7Mx+Qr~cqY zaj=EI^^gO50GHxve)*xWZ-tkP=720+ndjDMJiPR$42n0V@ZOsoobO^13V5Mr805mc zK#GGcJaL=@`z$P15wOL<6dpp#f%(Pdd0@;e1P@3Qhgay|oP+m+om1f%Pp6E}ZE=8w z{-im8Ut+He^wTuZ04xru(8QJl^lBn&&B++t3X!4E_>(Jqsy|z}c)f-Cx?Iu4H%+g- wD{MfaJ|_p|@*$v1kn+a literal 0 HcmV?d00001 diff --git a/repl/xmlpubtk/sample3/sample3.java b/repl/xmlpubtk/sample3/sample3.java new file mode 100644 index 0000000..9b5d276 --- /dev/null +++ b/repl/xmlpubtk/sample3/sample3.java @@ -0,0 +1,57 @@ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + + +/** + * The sample2 class is the small class to create a new frame and make it visible. + * + * @author tjacopi + * + */ +public class sample3 { + + + public static void main(String args[]) { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + e.printStackTrace(); + } + + // Get the arguments the user passed in + String qManager = parseArgsFor("-qmgr", args); // get the -qmgr argument + String qName = parseArgsFor("-queue", args); + String topicName = parseArgsFor("-topic", args); + + // Insure qManager and either qName or topicName was specified + if (qManager != null && (qName != null || topicName != null) ) { + MonitorFrame frame = new MonitorFrame(qManager, qName, topicName); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) {System.exit(0);} + }); + frame.pack(); + frame.setVisible(true); + } else { + printHelp(); + System.exit(0); + } + } + + protected static void printHelp() { + System.out.println("Usage: java sample3 -qmgr (-queue | -topic ) "); + System.out.println(" example: java sample3 -qmgr DefaultQMGR -queue myPubQ"); + System.out.println(" - or - "); + System.out.println(" example: java sample3 -qmgr DefaultQMGR -topic myTopic"); + } + + protected static String parseArgsFor(String argName, String[] args) { + String argValue = null; + for (int i =0; i +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#ifdef WIN +#include // for window platform sdk GetUsername() +// Need Link to Advapi32.lib +#endif +#ifdef SQLUNIX +#include +#endif + +#include +#include "db2secPlugin.h" + +#include "IBMLDAPutils.h" + + +DB2LDAP_EXT_C +db2secLogMessage *db2LogFunc = NULL; + +static pluginConfig_t ConfigData; + +/* db2ldapGetConfigDataPtr + * Return a pointer to the config data for this plugin. + * All plugins (client, server, group) use the same structure, but it is + * important that the helper functions in other files use the right one! + */ +DB2LDAP_EXT_C +pluginConfig_t *db2ldapGetConfigDataPtr(void) +{ + return(&ConfigData); +} + + +#define INFO_BUFFER_SIZE 4096 + +/* WhoAmI + * Figure out what userid we're running as, look them up in LDAP, + * and return the userid and AuthID. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN WhoAmI(char authID[], + db2int32 *authIDLength, + char userID[], + db2int32 *userIDLength, + db2int32 userIDType, + char domain[], /* not used */ + db2int32 *domainLength, /* not used */ + db2int32 *domainType, /* not used */ + const char *databaseName, /* not used */ + db2int32 databaseNameLength, /* not used */ + void **token, /* not used */ + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + char user[INFO_BUFFER_SIZE]; + char szLog[MAX_ERROR_MSG_SIZE]; + int loglen = 0; + char buffer[MAX_ERROR_MSG_SIZE]; + int status = 0; + char *srch_authid = NULL; + int authidLen; + + LDAP *ld = NULL; + +#if defined(SQLWINT) + DWORD userLen; + DWORD en; +#elif defined(SQLUNIX) + int userLen; + int en; + struct passwd pwd, *pw = NULL; + uid_t current_uid = 0; +#else +#error Must define platform +#endif + + *errorMessage = NULL; + *errorMessageLength = 0; + + authID[0] = '\0'; + *authIDLength = 0; + userID[0] = '\0'; + *userIDLength = 0; + domain[0] = '\0'; + *domainLength = 0; + *domainType = DB2SEC_USER_NAMESPACE_UNDEFINED; + + + /* Determine what userid we're running under (platform specific). */ + +#ifdef SQLWINT + /* Windows */ + userLen = INFO_BUFFER_SIZE; + if (!GetUserNameA( user, &userLen )) + { + en = GetLastError(); + snprintf(buffer, sizeof(buffer), + "LDAP WhoAmI: failed to get current user info, error=%d", en); + *errorMessage = strdup(buffer); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } +#else + /* UNIX / Linux */ + if (DB2SEC_PLUGIN_REAL_USER_NAME == userIDType) + { + current_uid = getuid(); + } + else + { + current_uid = geteuid(); + } + + status = getpwuid_r(current_uid, &pwd, buffer, sizeof(buffer), &pw); + + en = errno; /* Error handling is below */ + + if (status == 0) + { + userLen = strlen(pw->pw_name); + strcpy(user, pw->pw_name); + } + else + { + snprintf(buffer, sizeof(buffer), "LDAP WhoAmI: " + "failed to find user info for uid %u, error=%d", + current_uid, en); + *errorMessage = strdup(buffer); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } +#endif + + + /* Check the length */ + if (userLen > DB2SEC_MAX_USERID_LENGTH) + { + snprintf(buffer, sizeof(buffer), + "LDAP WhoAmI: default user name too long (%d bytes): %s", + userLen, user); + *errorMessage = strdup(buffer); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + strcpy(userID, user); + *userIDLength = userLen; + + + /* Now connect to LDAP and search for the associated AuthID. */ + rc = initLDAP(&ld, TRUE, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + rc = db2ldapFindAttrib(ld, + ConfigData.userBase, + ConfigData.userObjClass, + ConfigData.useridAttr, + userID, + ConfigData.authidAttr, + &srch_authid, + FALSE, + NULL); + + if (rc != GET_ATTRIB_OK) + { + const char *msg; + switch (rc) + { + case GET_ATTRIB_NO_OBJECT: + msg = "user not found in LDAP."; + rc = DB2SEC_PLUGIN_NO_CRED; + break; + case GET_ATTRIB_NOTFOUND: + msg = "no AuthID found for user."; + rc = DB2SEC_PLUGIN_BADUSER; + break; + case GET_ATTRIB_TOOMANY: + msg = "more than one AuthID found for user."; + rc = DB2SEC_PLUGIN_BADUSER; + break; + case GET_ATTRIB_LDAPERR: + msg = "LDAP error while searching for AuthID."; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + case GET_ATTRIB_NOMEM: + msg = "out of memory while retreiving AuthID."; + rc = DB2SEC_PLUGIN_NOMEM; + break; + case GET_ATTRIB_BADINPUT: + default: + msg = "internal error while searching for AuthID."; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + } + snprintf(buffer, sizeof(buffer), "LDAP WhoAmI: " + "can't determine LDAP user associated with\nOS user '%s': " + "%s\nUserid attribute='%s' AuthID attribute='%s'\n" + "user objectClass='%s' user base DN='%s'", + userID, msg, ConfigData.useridAttr, ConfigData.authidAttr, + ConfigData.userObjClass, ConfigData.userBase); + *errorMessage = strdup(buffer); + goto exit; + } + + authidLen = strlen(srch_authid); + + if (authidLen <= 0) + { + snprintf(buffer, sizeof(buffer), + "LDAP WhoAmI: bad AuthID length (%d) for user %s", + authidLen, userID); + *errorMessage = strdup(buffer); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + if (authidLen > DB2SEC_MAX_AUTHID_LENGTH) + { + snprintf(buffer, sizeof(buffer), + "LDAP WhoAmI: AuthID too long for user %s: (%d bytes): %s", + userID, authidLen, srch_authid); + *errorMessage = strdup(buffer); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + *authIDLength = authidLen; + strcpy(authID, srch_authid); + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + db2LogFunc(DB2SEC_LOG_ERROR, *errorMessage, *errorMessageLength); + } + + if (srch_authid != NULL) free(srch_authid); + if (ld != NULL) ldap_unbind_s(ld); + return(rc); +} + + + + +/* FreeToken + * The "token" parameter is malloc'd when required. Free it here. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN FreeToken(void *token, + char **errorMessage, + db2int32 *errorMessageLength) +{ + *errorMessage = NULL; + *errorMessageLength = 0; + + if (token != NULL) free(token); + return(DB2SEC_PLUGIN_OK); +} + + + + +/* FreeErrorMessage + * All messages returned from this plugin are strdup'd. Free them here. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN FreeErrorMessage(char *msg) +{ + if (msg != NULL) free(msg); + return(DB2SEC_PLUGIN_OK); +} + + + +/* PluginTerminate + * Terminate & clean up. Nothing to do for this plugin. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN PluginTerminate(char **errorMessage, + db2int32 *errorMessageLength) +{ + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + + + +/* db2secClientAuthPluginInit + * Plugin initialization. Parse the config file and set up function + * pointers. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN +db2secClientAuthPluginInit (db2int32 version, + void *client_fns, + db2secLogMessage *msgFunc, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + db2secUseridPasswordClientAuthFunctions_1 *p; + + *errorMessage = NULL; + *errorMessageLength = 0; + + p = (db2secUseridPasswordClientAuthFunctions_1 *)client_fns; + + p->version = DB2SEC_USERID_PASSWORD_CLIENT_AUTH_FUNCTIONS_VERSION_1; + p->plugintype = DB2SEC_PLUGIN_TYPE_USERID_PASSWORD; + p->db2secRemapUserid = NULL; /* optional */ + p->db2secGetDefaultLoginContext = &WhoAmI; + p->db2secValidatePassword = &CheckPassword; + p->db2secFreeToken = &FreeToken; + p->db2secFreeErrormsg = &FreeErrorMessage; + p->db2secClientAuthPluginTerm = &PluginTerminate; + + db2LogFunc = msgFunc; + + rc = db2ldapReadConfig(&ConfigData, CFG_USERAUTH, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + /* If an SSL connection has been configured, initialize SSL support + * here. This must be done once in every plugin library; if we + * don't do this here we run into problems passing the LDAP handle + * between different libraries. + */ + if (ConfigData.isSSL) + { + rc = db2ldapSetGSKitVar(errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + rc = db2ldapInitSSL(&ConfigData, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + } + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + db2LogFunc(DB2SEC_LOG_ERROR, *errorMessage, *errorMessageLength); + } + return(rc); +} diff --git a/security/plugins/IBMLDAPauthserver.c b/security/plugins/IBMLDAPauthserver.c new file mode 100644 index 0000000..9941c9e --- /dev/null +++ b/security/plugins/IBMLDAPauthserver.c @@ -0,0 +1,449 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 2006 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: IBMLDAPauthserver.C +** +** SAMPLE: server side LDAP based userID/password authentication +** +** This source file implements a server side DB2 securty plugin that +** interacts with an LDAP user registry. +** +** When built, a single loadable object is created that should be copied +** into the appropriate directory under the DB2 instance. Then the +** SRVCON_PW_PLUGIN database manager configuration parameter must be +** updated to the name of the loadable object (minus the library suffix). +** +** For example, on 64-bit UNIX platforms the loadable object should be +** copied to the .../sqllib/security64/plugin/server directory and the +** CLNT_PW_PLUGIN parameter updated to "IBMLDAPauthserver". +** +***************************************************************************** +** +** For more information on developing DB2 security plugins, see the +** "Developing Security Plug-ins" section of the Application Development +** Guide. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "sqlenv.h" +#include "db2secPlugin.h" +#include "IBMLDAPutils.h" + + +DB2LDAP_EXT_C +db2secLogMessage *db2LogFunc = NULL; + +static pluginConfig_t ConfigData; + +/* db2ldapGetConfigDataPtr + * Return a pointer to the config data for this plugin. + * All plugins (client, server, group) use the same structure, but it is + * important that the helper functions in other files use the right one! + */ +DB2LDAP_EXT_C +pluginConfig_t *db2ldapGetConfigDataPtr(void) +{ + return(&ConfigData); +} + + + +/* GetAuthIDs + * Search LDAP for the user that matches the given "userID" and return + * the value of the AuthID attribute associated with the user object. + * + * Note that the AuthID may have been picked up earlier (in CheckPassword) + * and stored in the "token" parameter. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN GetAuthIDs(const char *userID, + db2int32 userIDLength, + const char *domain, /* not used */ + db2int32 domainLength, /* not used */ + db2int32 domainType, /* not used */ + const char *databaseName, /* not used */ + db2int32 databaseNameLength, /* not used */ + void **token, + char systemAuthID[], + db2int32 *systemAuthIDLength, + char sessionAuthID[], + db2int32 *sessionAuthIDLength, + char username[], + db2int32 *usernameLength, + db2int32 *sessionType, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + LDAP *ld = NULL; + int freeLDAP = FALSE; + char *authid = NULL; + int authidLen; + int haveTokenWantAuthID = FALSE; + token_t *pluginToken = NULL; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + char userDN[DB2LDAP_MAX_DN_SIZE + 1]; + char local_userid[DB2SEC_MAX_USERID_LENGTH + 1]; + char local_authid[DB2SEC_MAX_AUTHID_LENGTH + 1]; + + *errorMessage = NULL; + *errorMessageLength = 0; + + if (userID == NULL) + { + *errorMessage = strdup("LDAP GetAuthIDs: userid is NULL"); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + if ( userIDLength > DB2SEC_MAX_USERID_LENGTH ) + { + /* Make a NULL terminated version of known max size */ + strncpy(local_userid, userID, DB2SEC_MAX_USERID_LENGTH); + local_userid[DB2SEC_MAX_USERID_LENGTH] = '\0'; + + snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP GetAuthIDs: userid too long: %d bytes\n[truncated:]%s", + (int)userIDLength, local_userid); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + /* For this plugin the "username" is the same as the */ + /* "userID" supplied by the cient. */ + memcpy(username, userID, userIDLength); + *usernameLength = userIDLength; + + /* Create a local NULL-terminated version of the userid */ + memcpy(local_userid, userID, userIDLength); + local_userid[userIDLength] = '\0'; + + /* The AuthID might already be in the token */ + if (token != NULL && *token != NULL) + { + pluginToken = (token_t *)(*token); + if (memcmp(pluginToken->eyeCatcher, + DB2LDAP_TOKEN_EYECATCHER, + sizeof(DB2LDAP_TOKEN_EYECATCHER)) == 0) + { + authidLen = pluginToken->authidLen; + if (authidLen > 0) + { + authid = pluginToken->authid; + goto check_authid; + } + haveTokenWantAuthID = TRUE; + + /* Even if the AuthID wasn't there, we might have an LDAP + * handle we can use. + */ + if (pluginToken->ld != NULL) + { + ld = pluginToken->ld; + freeLDAP = FALSE; + } + } + } + + + if (ld == NULL) + { + rc = initLDAP(&ld, TRUE, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + freeLDAP = TRUE; + } + + rc = db2ldapGetUserDN(ld, local_userid, userDN, local_authid, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + authid = local_authid; + authidLen = strlen(authid); + + +check_authid: + if (authidLen <= 0) + { + snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP GetAUTHIDs: bad AuthID length (%d)\nuser='%s'", + authidLen, local_userid); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + /* The max authid length is checked in db2ldapGetUserDN */ + + memcpy(systemAuthID, authid, authidLen); + *systemAuthIDLength = authidLen; + memcpy(sessionAuthID, authid, authidLen); + *sessionAuthIDLength = authidLen; + *sessionType = DB2SEC_ID_TYPE_AUTHID; + + /* If we had a token without an AuthID in it, store the one + * we found there now so it's available for FindGroups. + */ + if (haveTokenWantAuthID) + { + strcpy(pluginToken->authid, authid); + pluginToken->authidLen = authidLen; + + if (userDN[0] != '\0' && strlen(userDN) <= DB2LDAP_MAX_DN_SIZE) + { + strcpy(pluginToken->userDN, userDN); + } + } + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + if (freeLDAP && ld != NULL) ldap_unbind_s(ld); + + return(rc); +} + + + +/* DoesAuthIDExist + * Search for a user object where the AuthID attribute matches the + * value provided. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN DoesAuthIDExist(const char *authID, + db2int32 authIDLength, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + int filterLength = 0; + LDAP *ld = NULL; + char *errmsg = NULL; + char localAuthID[DB2SEC_MAX_AUTHID_LENGTH + 1]; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + + *errorMessage = NULL; + *errorMessageLength = 0; + + if (authID == NULL || authIDLength <= 0) + { + snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP DoesAuthIDExist: AUTHID is NULL or bad length (%d)", + (int)authIDLength); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + /* NULL terminate the authID */ + if (authIDLength > DB2SEC_MAX_AUTHID_LENGTH) + { + /* Make a NULL terminated version of known max size */ + strncpy(localAuthID, authID, DB2SEC_MAX_AUTHID_LENGTH); + localAuthID[DB2SEC_MAX_AUTHID_LENGTH] = '\0'; + + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP DoesAuthIDExist: " + "AuthID too long: %d bytes\n[truncated:]%s", + (int)authIDLength, localAuthID); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + memcpy(localAuthID, authID, authIDLength); + localAuthID[authIDLength] = '\0'; + + rc = initLDAP(&ld, TRUE, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + rc = db2ldapFindAttrib(ld, + ConfigData.userBase, + ConfigData.userObjClass, + ConfigData.authidAttr, + localAuthID, + ConfigData.authidAttr, + NULL, + FALSE, + NULL); + + errmsg = NULL; + + switch (rc) + { + case GET_ATTRIB_OK: + case GET_ATTRIB_TOOMANY: /* finding more than one is okay here */ + rc = DB2SEC_PLUGIN_OK; + break; + case GET_ATTRIB_NO_OBJECT: /* search worked, but didn't find a match */ + case GET_ATTRIB_NOTFOUND: + rc = DB2SEC_PLUGIN_INVALIDUSERORGROUP; + break; + case GET_ATTRIB_LDAPERR: + errmsg = (char*)"LDAP error searching for AUTHID"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + case GET_ATTRIB_NOMEM: + errmsg = (char*)"out of memory while searching for AUTHID"; + rc = DB2SEC_PLUGIN_NOMEM; + break; + case GET_ATTRIB_BADINPUT: + default: + errmsg = (char*)"Internal error while searching for AUTHID"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + } + + if (errmsg != NULL) + { + snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP DoesAuthIDExist:\n%s\nAuthID='%s'", + errmsg, localAuthID); + *errorMessage = strdup(dumpMsg); + } + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + if (ld != NULL) ldap_unbind_s(ld); + + return (rc); +} + + + + +/* FreeToken + * The "token" parameter is malloc'd when required. Free it here. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN FreeToken(void *token, + char **errorMessage, + db2int32 *errorMessageLength) +{ + *errorMessage = NULL; + *errorMessageLength = 0; + + if (token != NULL) + { + if (((token_t*)token)->ld != NULL) + ldap_unbind_s(((token_t*)token)->ld); + free(token); + } + return(DB2SEC_PLUGIN_OK); +} + + + + +/* FreeErrorMessage + * All messages returned from this plugin are strdup'd. Free them here. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN FreeErrorMessage(char *msg) +{ + if (msg != NULL) free(msg); + return(DB2SEC_PLUGIN_OK); +} + + + + +/* PluginTerminate + * Terminate & clean up. Nothing to do for this plugin. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN PluginTerminate(char **errorMessage, + db2int32 *errorMessageLength) +{ + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + + + + +/* db2secServerAuthPluginInit + * Plugin initialization. Parse the config file and set up function + * pointers. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN +db2secServerAuthPluginInit(db2int32 version, + void *server_fns, + db2secGetConDetails *getConDetails_fn, + db2secLogMessage *msgFunc, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + db2secUseridPasswordServerAuthFunctions_1 *p; + + *errorMessage = NULL; + *errorMessageLength = 0; + + p = (db2secUseridPasswordServerAuthFunctions_1*)server_fns; + + p->version = DB2SEC_USERID_PASSWORD_SERVER_AUTH_FUNCTIONS_VERSION_1; + p->plugintype = DB2SEC_PLUGIN_TYPE_USERID_PASSWORD; + p->db2secValidatePassword = &CheckPassword; + p->db2secGetAuthIDs = &GetAuthIDs; + p->db2secDoesAuthIDExist = &DoesAuthIDExist; + p->db2secFreeToken = &FreeToken; + p->db2secFreeErrormsg = &FreeErrorMessage; + p->db2secServerAuthPluginTerm = &PluginTerminate; + + db2LogFunc = msgFunc; + + memset(&ConfigData, 0, sizeof(ConfigData)); + + rc = db2ldapReadConfig(&ConfigData, CFG_USERAUTH, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + /* If an SSL connection has been configured, initialize SSL support + * here. This must be done once in every plugin library; if we + * don't do this here we run into problems passing the LDAP handle + * between different libraries. + */ + if (ConfigData.isSSL) + { + rc = db2ldapSetGSKitVar(errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + rc = db2ldapInitSSL(&ConfigData, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + } + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + db2LogFunc(DB2SEC_LOG_ERROR, *errorMessage, *errorMessageLength); + } + return(rc); +} + diff --git a/security/plugins/IBMLDAPconfig.c b/security/plugins/IBMLDAPconfig.c new file mode 100644 index 0000000..70ae422 --- /dev/null +++ b/security/plugins/IBMLDAPconfig.c @@ -0,0 +1,626 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 2006 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: IBMLDAPconfig.c +** +** SAMPLE: Functions related to finding and parsing the configuration +** file for the DB2 LDAP security plugin. +** +***************************************************************************** +** +** For more information on developing DB2 security plugins, see the +** "Developing Security Plug-ins" section of the Application Development +** Guide. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ +#include + +#if defined(SQLUNIX) +#include +#include +#endif + +#include "IBMLDAPutils.h" + +static int db2ldapGetDefaultConfigPath(char *, int, char **); +static int db2ldapGetConfigLine(FILE *, int *, char *, int); +static int db2ldapParseCfgLine(char *, char **, char **); + +#define CFGLINE_OKAY 0 +#define CFGLINE_FGETS_FAILED 1 +#define CFGLINE_TOO_LONG 2 + + + +#define ProcessKeyVal(CURVAL, MAXSZ) \ +{ if (CURVAL[0] != '\0') \ + { \ + snprintf(dumpMsg, sizeof(dumpMsg), \ + "db2ldapReadConfig: duplicate key value for %s on line %d of %s", \ + key, linenum, cfgfn); \ + *errorMessage = strdup(dumpMsg); \ + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; \ + goto exit; \ + } \ + if (strlen(value) > MAXSZ) \ + { \ + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " \ + "line %d of %s\nvalue for key '%s' is too long (%d bytes, max %d)\n" \ + "value='%s'", \ + linenum, cfgfn, key, (int)strlen(value), MAXSZ, value); \ + *errorMessage = strdup(dumpMsg); \ + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; \ + goto exit; \ + } \ + strcpy(CURVAL,value); \ +} + +#define ProcessKeyBool(CURVAL) \ +{ if (CURVAL != -1) \ + { \ + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " \ + "duplicate key value for %s on line %d of %s", \ + key, linenum, cfgfn); \ + *errorMessage = strdup(dumpMsg); \ + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; \ + goto exit; \ + } \ + if (strcasecmp(value, "true") == 0) \ + CURVAL = TRUE; \ + else if (strcasecmp(value, "false") == 0) \ + CURVAL = FALSE; \ + else \ + { \ + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " \ + "bad value '%s' for key '%s' on line %d of %s", \ + value, key, linenum, cfgfn); \ + *errorMessage = strdup(dumpMsg); \ + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; \ + goto exit; \ + } \ +} + +#define VerifyCfg(VAL, KEY) \ +{ if (VAL[0] == '\0') \ + { \ + snprintf(dumpMsg, sizeof(dumpMsg), \ + "db2ldapReadConfig: no value for key '%s' found in %s", \ + KEY, cfgfn); \ + *errorMessage = strdup(dumpMsg); \ + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; \ + goto exit; \ + } \ +} + + +/* db2ldapReadConfig + * + * Find and parse the LDAP plugin configuration file. Store the + * configuration data in the structure pointed to by "cfg". + * + * Returns + * DB2SEC_PLUGIN_OK + * DB2SEC_PLUGIN_FILENOTFOUND -- Can't locate config file + * DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS -- Syntax error parsing config + */ +int db2ldapReadConfig(pluginConfig_t *cfg, + int types, /* Bitmask */ + char **errorMessage) +{ + int rc = DB2SEC_PLUGIN_OK; + FILE *fp = NULL; + int linenum; + char fnbuf[CFG_MAX_FILENAME]; + char *cp = NULL; + char buf[CFG_MAX_LINE_LEN]; + char *key = NULL; + char *value = NULL; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + char *cfgfn = NULL; + + /* Find the config file */ +#ifdef SQLUNIX + /* UNIX / Linux */ + cfgfn = getenv(DB2LDAP_ENV_CFGFILE); +#else + /* Windows */ + DWORD fnlen; + fnlen = GetEnvironmentVariable(DB2LDAP_ENV_CFGFILE, fnbuf, sizeof(fnbuf)); + if (fnlen == 0) + { + cfgfn = NULL; /* fall through to the code below */ + } + else if (fnlen > sizeof(fnbuf)) + { + /* Found the variable, but it's too large. */ + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " + "value for environment variable %s is too long", + DB2LDAP_ENV_CFGFILE); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + else + { + cfgfn = fnbuf; + } +#endif + + if (cfgfn == NULL) + { + rc = db2ldapGetDefaultConfigPath(fnbuf, sizeof(fnbuf), errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + cfgfn = fnbuf; + } + + fp = fopen(cfgfn, "r"); + if (fp == NULL) + { + snprintf(dumpMsg, sizeof(dumpMsg), + "db2ldapReadConfig: can't open config file '%s'", cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_FILENOTFOUND; + goto exit; + } + + + memset(cfg, 0, sizeof(*cfg)); + cfg->groupLookupMethod = -1; /* So we can detect duplicte lines */ + cfg->nestedGroups = -1; + cfg->isSSL = -1; + cfg->debug = -1; + cfg->isFipsOn = -1; + cfg->followReferrals = -1; + cfg->securityProtocol = -1; + + linenum = 0; + while (1) + { + rc = db2ldapGetConfigLine(fp, &linenum, buf, sizeof(buf)); + if (rc == CFGLINE_TOO_LONG) + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig:\n" + "line %d is too long (max %d including trailing NULL and " + "CR/LF)\nconfig file: %s", + linenum, CFG_MAX_LINE_LEN, cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + else if (rc != CFGLINE_OKAY) + { + if (feof(fp)) + { + rc = DB2SEC_PLUGIN_OK; + break; + } + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " + "error reading line %d of config file %s", + linenum, cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + rc = db2ldapParseCfgLine(buf, &key, &value); + if (rc != 0) + { + snprintf(dumpMsg, sizeof(dumpMsg), + "db2ldapReadConfig: error parsing line %d of config file %s", + linenum, cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + + /* Compare the key against the expected values */ + if (strcasecmp(key, CFGKEY_HOST) == 0) + { + ProcessKeyVal(cfg->ldapHost, CFG_MAX_HOST_SIZE); + } + else if (strcasecmp(key, CFGKEY_ENABLE_SSL) == 0) + { + ProcessKeyBool(cfg->isSSL); + } + else if (strcasecmp(key, CFGKEY_SSL_KEYFILE) == 0) + { + ProcessKeyVal(cfg->sslKeyfile, CFG_MAX_FILENAME); + } + else if (strcasecmp(key, CFGKEY_SSL_PW) == 0) + { + ProcessKeyVal(cfg->sslPwd, CFG_MAX_PSWD); + } + else if (strcasecmp(key, CFGKEY_SEARCH_DN) == 0) + { + ProcessKeyVal(cfg->searchDN, CFG_MAX_DN); + } + else if (strcasecmp(key, CFGKEY_SEARCH_PW) == 0) + { + ProcessKeyVal(cfg->searchPWD, CFG_MAX_PSWD); + } + else if (strcasecmp(key, CFGKEY_USER_BASEDN) == 0) + { + ProcessKeyVal(cfg->userBase, CFG_MAX_DN); + } + else if (strcasecmp(key, CFGKEY_USERID_ATTRIBUTE) == 0) + { + ProcessKeyVal(cfg->useridAttr, CFG_MAX_ATTR); + } + else if (strcasecmp(key, CFGKEY_AUTHID_ATTRIBUTE) == 0) + { + ProcessKeyVal(cfg->authidAttr, CFG_MAX_ATTR); + } + else if (strcasecmp(key, CFGKEY_USER_OBJECTCLASS) == 0) + { + ProcessKeyVal(cfg->userObjClass, CFG_MAX_ATTR); + } + else if (strcasecmp(key, CFGKEY_GROUP_BASEDN) == 0) + { + ProcessKeyVal(cfg->groupBase, CFG_MAX_DN); + } + else if (strcasecmp(key, CFGKEY_GROUP_OBJECTCLASS) == 0) + { + ProcessKeyVal(cfg->groupObjClass, CFG_MAX_ATTR); + } + else if (strcasecmp(key, CFGKEY_GROUP_LOOKUP_ATTRIBUTE) == 0) + { + ProcessKeyVal(cfg->groupLookupAttr, CFG_MAX_ATTR); + } + else if (strcasecmp(key, CFGKEY_GROUPNAME_ATTRIBUTE) == 0) + { + ProcessKeyVal(cfg->groupNameAttr, CFG_MAX_ATTR); + } + else if (strcasecmp(key, CFGKEY_NESTED_GROUPS) == 0) + { + ProcessKeyBool(cfg->nestedGroups); + } + else if (strcasecmp(key, CFGKEY_GROUP_LOOKUP_METHOD) == 0) + { + if (cfg->groupLookupMethod != -1) + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " + "duplicate key value for %s on line %d of %s", + key, linenum, cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + if (strcasecmp(value, GROUP_METHOD_STR_USER_ATTR) == 0) + { + cfg->groupLookupMethod = GROUP_METHOD_USER_ATTR; + } + else if (strcasecmp(value, GROUP_METHOD_STR_SEARCH_BY_DN) == 0) + { + cfg->groupLookupMethod = GROUP_METHOD_SEARCH_BY_DN; + } + else + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " + "bad value '%s' for key '%s' on line %d of %s", + value, key, linenum, cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + } + else if (strcasecmp(key, CFGKEY_FOLLOW_REFERRALS) == 0) + { + ProcessKeyBool(cfg->followReferrals); + } + else if (strcasecmp(key, CFGKEY_DEBUG) == 0) + { + ProcessKeyBool(cfg->debug); + } + else if (strcasecmp(key, CFGKEY_FIPS_MODE) == 0) + { + ProcessKeyBool(cfg->isFipsOn); + } + else if (strcasecmp(key, CFGKEY_SECURITY_PROTOCOL) == 0) + { + if (cfg->securityProtocol != -1) + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " + "duplicate key value for %s on line %d of %s", + key, linenum, cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + if (strcasecmp(value, SECURITY_PROTOCOL_STR_ALL) == 0) + { + cfg->securityProtocol = SECURITY_PROTOCOL_ALL; + } + else if (strcasecmp(value, SECURITY_PROTOCOL_STR_TLS12) == 0) + { + cfg->securityProtocol = SECURITY_PROTOCOL_TLS12; + } + else + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " + "bad value '%s' for key '%s' on line %d of %s", + value, key, linenum, cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + } + else if (strcasecmp(key, CFGKEY_SSL_EXTN_SIGALG) == 0) + { + ProcessKeyVal(cfg->sslExtnSigAlg, CFG_MAX_EXTN_SIGALG); + } + else + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " + "unknown key value '%s' on line %d of %s", + key, linenum, cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + } /* end config read loop */ + + + /* Check that we have all mandatory values */ + VerifyCfg(cfg->ldapHost, CFGKEY_HOST); + VerifyCfg(cfg->userObjClass, CFGKEY_USER_OBJECTCLASS); + VerifyCfg(cfg->authidAttr, CFGKEY_AUTHID_ATTRIBUTE); + + if (types & CFG_USERAUTH) + { + VerifyCfg(cfg->useridAttr, CFGKEY_USERID_ATTRIBUTE); + } + + if (types & CFG_GROUPLOOKUP) + { + VerifyCfg(cfg->groupObjClass, CFGKEY_GROUP_OBJECTCLASS); + VerifyCfg(cfg->groupLookupAttr, CFGKEY_GROUP_LOOKUP_ATTRIBUTE); + VerifyCfg(cfg->groupNameAttr, CFGKEY_GROUPNAME_ATTRIBUTE); + + if (cfg->groupLookupMethod == -1) + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapReadConfig: " + "a value must be specified for %s in %s", + CFGKEY_GROUP_LOOKUP_METHOD, cfgfn); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + } + + + /* Do we have a searchDN? + * Note that we don't check for a password... it might be valid + * not to specify one, and we don't want to try to be too clever. + */ + if (cfg->searchDN[0] != '\0') + { + cfg->haveSearchDN = TRUE; + } + + /* Optional boolean defaults. */ + if (-1 == cfg->nestedGroups ) cfg->nestedGroups = FALSE; + if (-1 == cfg->isSSL ) cfg->isSSL = FALSE; + if (-1 == cfg->debug ) cfg->debug = FALSE; + if (-1 == cfg->isFipsOn ) cfg->isFipsOn = TRUE; + if (-1 == cfg->followReferrals) cfg->followReferrals = TRUE; + +exit: + if (fp != NULL) fclose(fp); + + return(rc); +} + + +/* db2ldapGetDefaultConfigPath + * + * Figure out where the instance "cfg" directory is located. + * + * It would be nice if this was available from the ConDetails :-/ + */ +static int db2ldapGetDefaultConfigPath(char *buf, + int bufsz, + char **errorMsg) +{ + int rc = DB2SEC_PLUGIN_OK; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + +#if defined(SQLWINT) + DWORD len; + char instpath[MAX_ERROR_MSG_SIZE]; +#elif defined(SQLUNIX) + char *cp = NULL; + char pwnam_buf[256]; + struct passwd pwd, *pwp = NULL; + int en; +#endif + +#if defined(SQLWINT) + /* On Windows the path to the DB2 instance files is in DB2PATH */ + len = GetEnvironmentVariableA("DB2PATH", instpath, sizeof(instpath)); + if (len == 0) + { + *errorMsg = strdup("db2ldapGetDefaultConfigPath: DB2PATH not set"); + rc = DB2SEC_PLUGIN_FILENOTFOUND; + goto exit; + } + else if (len > sizeof(instpath)) + { + /* Found the variable, but it's too large. */ + *errorMsg = + strdup("db2ldapGetDefaultConfigPath: value for DB2PATH is too long"); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + snprintf(buf, bufsz, "%s%s", instpath, DB2LDAP_CFGDFLT_WIN); + +#elif defined(SQLUNIX) + /* On UNIX, we need to get the home directory for the */ + /* username in the DB2INSTANCE environment variable. */ + cp = getenv("DB2INSTANCE"); + if (cp == NULL || *cp == '\0') + { + *errorMsg = strdup("db2ldapGetDefaultConfigPath: DB2INSTANCE not set"); + rc = DB2SEC_PLUGIN_FILENOTFOUND; + goto exit; + } + + rc = getpwnam_r(cp, &pwd, pwnam_buf, sizeof(pwnam_buf), &pwp); + + en = errno; + + if (rc != 0) + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetDefaultConfigPath: " + "getpwnam_r failed for user %s, errno=%d", cp, en); + *errorMsg = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_FILENOTFOUND; + goto exit; + } + + if (pwp->pw_dir == NULL || pwp->pw_dir[0] == '\0') + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetDefaultConfigPath: " + "no home directory for user %s from getpwnam_r", cp); + *errorMsg = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_FILENOTFOUND; + goto exit; + } + + snprintf(buf, bufsz, "%s%s", pwp->pw_dir, DB2LDAP_CFGDFLT_UNIX); + +#else +#error Must define platform +#endif + +exit: + return(rc); +} + + +static void strip(char *buf) +{ + char *cp = buf; + int len; + + /* Strip leading whitespace */ + while (*cp == ' ' || *cp == '\t') cp++; + if (cp != buf) + { + memmove(buf, cp, strlen(cp) + 1); + } + + /* Strip trailing whitespace */ + len = strlen(buf) - 1; + while ((len >= 0) && + (buf[len] == ' ' || buf[len] == '\t' || + buf[len] == '\r' || buf[len] == '\n')) + { + buf[len--] = '\0'; + } +} + + +/* db2ldapGetConfigLine + * + * Read a single line. Strip leading/trailing whitespace. + */ +static int db2ldapGetConfigLine(FILE *fp, + int *linenum, + char *buf, + int bufsz) +{ + int rc = CFGLINE_OKAY; + int len; + char *cp; + + do { + cp = fgets(buf, bufsz, fp); + if (cp == NULL) + { + rc = CFGLINE_FGETS_FAILED; + goto exit; + } + + (*linenum)++; + + /* If the line filled the buffer, the last character must + * be '\n' (possibly '\r') or the line was too long. + */ + len = strlen(buf); + if ((len + 1) == bufsz) + { + len--; + if (buf[len] != '\n' && buf[len] != '\r') + { + rc = CFGLINE_TOO_LONG; + goto exit; + } + } + + /* Truncate the line at the first ";", if any. */ + cp = strchr(buf, ';'); + if (cp != NULL) + *cp = '\0'; + + + /* Strip whitespace */ + strip(buf); + + } while(buf[0] == '\0'); + +exit: + return(rc); +} + + +/* db2ldapParseCfgLine + * + * Parse the input config line, which should look like "key = value". + * Leading and trailing space are striped from both the key and the + * value. + * + * Returns 0 (success) or -1 (failure). + */ +static int db2ldapParseCfgLine(char *input, + char **key, + char **value) +{ + int rc = 0; + char *cp; + + /* All valid config lines have at least one "=". Find it. */ + cp = strchr(input, '='); + if (cp == NULL) + { + rc = -1; + goto exit; + } + + *cp = '\0'; + *key = input; + *value = cp + 1; + + strip(*key); + strip(*value); + +exit: + return(rc); +} diff --git a/security/plugins/IBMLDAPgroups.c b/security/plugins/IBMLDAPgroups.c new file mode 100644 index 0000000..2f45578 --- /dev/null +++ b/security/plugins/IBMLDAPgroups.c @@ -0,0 +1,1251 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 2006 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: IBMLDAPgroups.c +** +** SAMPLE: DB2 security plugin for LDAP based group lookup +** +** When built, a single loadable object is created. This object +** should be copied into the group plugin directory. Then the +** GROUP_PLUGIN database manager configuration parameter should be +** updated to the name of the plugin object file, minus any extensions. +** +** For example, on 64-bit UNIX platforms the loadable object should be +** copied to the .../sqllib/security64/plugin/group directory and the +** GROUP_PLUGIN parameter updated to "IBMLDAPgroups". +** +***************************************************************************** +** +** For more information on developing DB2 security plugins, see the +** "Developing Security Plug-ins" section of the Application Development +** Guide. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "sqlenv.h" +#include "db2secPlugin.h" +#include "IBMLDAPutils.h" + + +DB2LDAP_EXT_C +db2secLogMessage *db2LogFunc = NULL; + +static pluginConfig_t ConfigData; + +/* db2ldapGetConfigDataPtr + * Return a pointer to the config data for this plugin. + * All plugins (client, server, group) use the same structure, but it is + * important that the helper functions in other files use the right one! + */ +DB2LDAP_EXT_C +pluginConfig_t *db2ldapGetConfigDataPtr(void) +{ + return(&ConfigData); +} + + +/* Types used to manage the linked list of groups that + * is build during the group lookup process. + */ +typedef struct groupElem_s { + struct groupElem_s *next; + char name[1]; /* variable size */ +} groupElem; + +typedef struct { + groupElem *first; + groupElem *last; +} groupListHead; + + + +/* addGroupToList + * + * Add "name" to the list anchored by "head". + * + * Returns: 0 (success) or DB2SEC_PLUGIN_NOMEM. + */ +static int addGroupToList(groupListHead *head, + const char *name) +{ + int rc = DB2SEC_PLUGIN_OK; + groupElem *newgrp; + + newgrp = (groupElem*)malloc(sizeof(groupElem) + strlen(name)); + if (newgrp != NULL) + { + strcpy(newgrp->name, name); + newgrp->next = NULL; + + if (head->last == NULL) + { + head->first = newgrp; + head->last = newgrp; + } + else + { + head->last->next = newgrp; + head->last = newgrp; + } + } + else + { + rc = DB2SEC_PLUGIN_NOMEM; + } + return(rc); +} + +/* isGrpDNinList + * + * Returns TRUE if "name" is found in the group list, otherwise FALSE. + */ +static int isGrpDNinList(groupListHead *head, + const char *name) +{ + int rc = FALSE; + + if (head != NULL) + { + groupElem *cur = head->first; + while (rc == FALSE && cur != NULL) + { + if (strcmp(name, cur->name) == 0) rc = TRUE; + cur = cur->next; + } + } + return(rc); +} + +/* freeList + * + * Free the memory associated with the list anchored by "head". + */ +static void freeList(groupListHead *head) +{ + groupElem *cur, *next; + + if (head != NULL) + { + cur = head->first; + while (cur != NULL) + { + next = cur->next; + free(cur); + cur = next; + } + + head->first = NULL; + } + return; +} + +/* getGroupNameByDN + * + * Look up the groupNameAttr value associated with the input group DN. + * Caller must free the string returned in *res_str. + */ +static int getGroupNameByDN(LDAP *ld, + const char *groupDN, + char **res_str, + char **errorMessage) +{ + int rc = DB2SEC_PLUGIN_OK; + const char *msg = NULL; + int loglevel, len; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + + if (res_str == NULL) /* should never happen */ + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + *res_str = NULL; + + rc = db2ldapFindAttrib(ld, + groupDN, + ConfigData.groupObjClass, + NULL, NULL, + ConfigData.groupNameAttr, + res_str, + TRUE, + NULL); + + if (rc != DB2SEC_PLUGIN_OK) + { + loglevel = DB2SEC_LOG_ERROR; + switch (rc) + { + case GET_ATTRIB_NO_OBJECT: + case GET_ATTRIB_NOTFOUND: + /* No "group name" attribute found for this group, + * or we couldn't find the group DN in LDAP. + * This is not a fatal error: we log a warning and + * continue without processing this group. + */ + msg = "no group name found."; + loglevel = DB2SEC_LOG_WARNING; + rc = DB2SEC_PLUGIN_OK; + break; + + case GET_ATTRIB_TOOMANY: + /* More than one "group name" attribute found for + * this group. This is not a fatal error: we log + * an informational message and process the first + * name only. + */ + msg = "more than one group name found."; + loglevel = DB2SEC_LOG_INFO; + rc = DB2SEC_PLUGIN_OK; + break; + + case GET_ATTRIB_LDAPERR: + msg = "LDAP error while searching for group name."; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + + case GET_ATTRIB_NOMEM: + msg = "out of memory while searching for group name."; + rc = DB2SEC_PLUGIN_NOMEM; + break; + + case GET_ATTRIB_BADINPUT: + default: + msg = "internal error while searching for group name."; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + } + + len = snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP getGroupNameByDN: %s\ngroup DN='%s'", + msg, groupDN); + if (rc == DB2SEC_PLUGIN_OK) + { + db2LogFunc(loglevel, dumpMsg, len); + } + else + { + *errorMessage = strdup(dumpMsg); + goto exit; + } + } + +exit: + return(rc); +} + +/* EscapeDnAsSearchFilter + * + * Takes a DN and converts it so that it can be used as a search filter. + * A DN can contain escape characters like '\,' but when we use it in + * a search filter we have to convert it to '\2C' where 2C is the hex + * representation of the comma. + * + * The caller provides the dn and a buffer dnAsFilter and the length + * of dnAsFilter (less null-terminator). The output buffer + * will be returned in outDnAsFilter. If there is not enough + * space in dnAsFilter this function will malloc a bigger buffer + * and the caller will have to free the buffer. + * So, if the buffer is big enough then *outDnAsFilter = dnAsFilter + * otherwise *outDnAsFilter = malloc(strlen(dn)*2). + */ + +static int EscapeDnAsSearchFilter( const char* dn, + char* dnAsFilter, + int sizeOfFilter, + char** outDnAsFilter ) +{ + int rc = DB2SEC_PLUGIN_OK; + int dnPos = 0; + int filterPos = 0; + int len; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + + const int dnLen = strlen(dn); + + len = snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP EscapeDnAsSearchFilter:\n" + "input dn='%s'", + dn ); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, len); + + *outDnAsFilter = NULL; + + // sizeOfFilter does not include null-terminator. + for( dnPos = 0, filterPos = 0; + dnPos < dnLen && filterPos < sizeOfFilter; + dnPos++, filterPos++ ) + { + dnAsFilter[ filterPos ] = dn[ dnPos ]; + + if( dn[ dnPos ] == DB2LDAP_ESCAPE_CHAR ) + { + // Advance to the character that is being escaped. + // If the escape character is the last character then we end now. + dnPos++; + if( dnPos < dnLen ) + { + // We will convert the escaped-character to hex. + // We need to make sure the filter has the space to hold the two + // characters. + if( (filterPos+2) < sizeOfFilter ) + { + filterPos++; // Advance to next empty space + snprintf( dnAsFilter+filterPos, + sizeOfFilter-filterPos, + "%2.2X", + dn[ dnPos ] ); + filterPos++; // Advance once more because we used up two spaces. + } + else + { + len = snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP EscapeDnAsSearchFilter: out of space in " + "dnAsFilter parameter.\n" ); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, len); + rc = DB2SEC_PLUGIN_NOMEM; + break; + } + } + } + } + + if( rc == DB2SEC_PLUGIN_OK ) + { + // sizeOfFilter is the size of the buffer that can hold the filter without + // the null terminator. We are therefore garantee to have enough space for the + // null terminator. + dnAsFilter[ filterPos ] = '\0'; + + *outDnAsFilter = dnAsFilter; + len = snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP EscapeDnAsSearchFilter:\n" + "dnAsFilter='%s'", + dnAsFilter ); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, len); + } + else if( rc == DB2SEC_PLUGIN_NOMEM ) + { + const int newLen = strlen(dn) * 2; + char* newDnAsFilter = NULL; + + // The following check is to prevent a coding error that would + // have caused an infinite loop. If the dn is nothing but escape + // sequences then the maximum expansion is 3/2. Therefore, + // doubling the output buffer should be sufficient. If there + // was a bug we would come in again and the sizeOfFilter would + // be exactly twice of strlen(dn). If that is the case then we + // will not continue. + if( newLen > sizeOfFilter ) + { + newDnAsFilter = malloc( newLen ); + if( newDnAsFilter != NULL ) + { + // It is impossible for the call to EscapeDnAsSearchFilter + // to allocate another buffer and thus we are not going to + // check and free newDnAsFilter. + rc = EscapeDnAsSearchFilter( dn, + newDnAsFilter, + newLen-1, + outDnAsFilter ); + } + else + { + rc = DB2SEC_PLUGIN_NOMEM; + } + } + } + + return rc; +} + + +/* findGroupsByDnAttr + * + * Looks up group membership information for a DN by retreiving an + * attribute of that DN. The input DN may be either a user or a + * group, as determined by the dnIsGroup flag. + * + * Groups are appended to the linked list passed as "head". + * + * Returns: 0 for success, or a DB2 plugin error code. + */ +DB2LDAP_EXT_C +static int findGroupsByDnAttr(LDAP *ld, + const char *DN, + int dnIsGroup, + groupListHead *head) +{ + int rc = DB2SEC_PLUGIN_OK; + int len, i; + char *objClass = NULL; + char *attrs[2]; + char filter[MAX_FILTER_LENGTH]; + char dnAsFilterBuffer[MAX_FILTER_LENGTH]; + char *dnAsFilter = NULL; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + char **values = NULL; + + LDAPMessage *ldapRes = NULL; + LDAPMessage *ldapEntry = NULL; + + // Convert the DN to a format that can be used + // as a search filter. + rc = EscapeDnAsSearchFilter( DN, + dnAsFilterBuffer, + sizeof(dnAsFilterBuffer)-1, + &dnAsFilter ); + + if( rc != DB2SEC_PLUGIN_OK ) + { + goto exit; + } + + if (dnIsGroup) + { + objClass = ConfigData.groupObjClass; + } + else + { + objClass = ConfigData.userObjClass; + } + + snprintf(filter, sizeof(filter), "(objectClass=%s)", objClass); + + // Dump the filter. We can see the filter if diaglevel is 4. + len = snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP findGroupsByDnAttr:\n" + "dn='%s'\n" + "filter='%s'", + DN, filter); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, len); + + attrs[0] = ConfigData.groupLookupAttr; + attrs[1] = NULL; + + rc = ldap_search_s(ld, dnAsFilter, LDAP_SCOPE_BASE, + filter, attrs, FALSE, &ldapRes); + + if (rc != LDAP_SUCCESS ) + { + if (rc == LDAP_NO_SUCH_ATTRIBUTE) + { + /* No groups associated with this DN. */ + rc = DB2SEC_PLUGIN_OK; + goto exit; + } + else if (rc == LDAP_NO_SUCH_OBJECT) + { + goto error_DN_not_found; + } + else if( rc == LDAP_REFERRAL ) + { + rc = LDAP_SUCCESS; + } + else + { + len = snprintf(dumpMsg, sizeof(dumpMsg), "LDAP findGroupsByDnAttr: " + "group search failed with ldap rc=%d (%s)\n" + "dn='%s'\n" + "dnAsFilter='%s'\n" + "filter='%s'", + rc, ldap_err2string(rc), DN, dnAsFilter, filter); + db2LogFunc(DB2SEC_LOG_ERROR, dumpMsg, len); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + } + + ldapEntry = ldap_first_entry(ld, ldapRes); + if (ldapEntry == NULL) goto error_DN_not_found; + + /* values might be NULL here if this DN does not belong to any groups. */ + values = ldap_get_values(ld, ldapEntry, attrs[0]); + if (values != NULL) + { + i = 0; + while(values[i] != NULL) + { + /* If this group DN is already in the list then skip it. */ + if (!isGrpDNinList(head, values[i])) + { + rc = addGroupToList(head, values[i]); + if (rc != DB2SEC_PLUGIN_OK) + { + len = snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP findGroupsByDnAttr: addGroupToList " + "rc=%d for group DN '%s'\n", rc, values[i]); + db2LogFunc(DB2SEC_LOG_ERROR, dumpMsg, len); + goto exit; + } + } + + i++; + } + + ldap_value_free(values); + } + +exit: + if (ldapRes != NULL) ldap_msgfree(ldapRes); + if (dnAsFilter != dnAsFilterBuffer ) free( dnAsFilter ); + + return(rc); + +error_DN_not_found: + len = snprintf(dumpMsg, sizeof(dumpMsg), "LDAP findGroupsByDnAttr: " + "DN not found in LDAP (isGroup=%d)\n" + "DN='%s'\n" + "dnAsFilter='%s'\n" + "filter='%s'", + dnIsGroup, DN, dnAsFilter, filter ); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, len); + /* This is not a severe error: may be a config problem or there + * may be no LDAP object of the correct object class. + */ + rc = DB2SEC_PLUGIN_OK; + goto exit; +} + + + +/* findGroupsByMember + * + * Searches for LDAP group entries that list the input DN as a + * member (via the group lookup attribute). + * + * Groups are appended to the linked list passed as "head". + * + * Returns: 0 for success, or a DB2 plugin error code. + */ +DB2LDAP_EXT_C +static int findGroupsByMember(LDAP *ld, + const char *DN, + int dnIsGroup, /* not used */ + groupListHead *head) +{ + int rc = DB2SEC_PLUGIN_OK; + int len; + char *objClass = NULL; + char *grpDN = NULL; + char filter[MAX_FILTER_LENGTH]; + char dnAsFilterBuffer[MAX_FILTER_LENGTH]; + char *dnAsFilter = NULL; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + const char *msg = NULL; + + LDAPMessage *ldapRes = NULL; + LDAPMessage *ldapEntry = NULL; + + // Convert the DN to a format that can be used + // as a search filter. + rc = EscapeDnAsSearchFilter( DN, + dnAsFilterBuffer, + sizeof(dnAsFilterBuffer)-1, + &dnAsFilter ); + + if( rc != DB2SEC_PLUGIN_OK ) + { + goto exit; + } + + snprintf(filter, sizeof(filter), + "(&(objectClass=%s)(%s=%s))", + ConfigData.groupObjClass, ConfigData.groupLookupAttr, dnAsFilter); + + // Dump the filter. We can see the filter if diaglevel is 4. + len = snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP findGroupsByMember:\n" + "dn='%s'\n" + "filter='%s'", + DN, filter); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, len); + + rc = ldap_search_s(ld, ConfigData.groupBase, LDAP_SCOPE_SUBTREE, + filter, NULL, TRUE, &ldapRes); + + if (rc != LDAP_SUCCESS ) + { + if( rc == LDAP_REFERRAL ) + { + rc = LDAP_SUCCESS; + } + else if ((rc == LDAP_NO_SUCH_OBJECT) || (LDAP_INVALID_DN_SYNTAX == rc)) /// the return error code from Lotus LDAP Server is LDAP_INVALID_DN_SYNTAX + { + /* No groups found that list this DN as a member. */ + rc = DB2SEC_PLUGIN_OK; + goto exit; + } + else + { + len = snprintf(dumpMsg, sizeof(dumpMsg), "LDAP findGroupsByMember: " + "group search failed with ldap rc=%d (%s)\n" + "dn='%s'\n" + "filter='%s'", + rc, ldap_err2string(rc), DN, filter); + db2LogFunc(DB2SEC_LOG_ERROR, dumpMsg, len); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + } + + ldapEntry = ldap_first_entry(ld, ldapRes); + while (ldapEntry != NULL) + { + grpDN = ldap_get_dn(ld, ldapEntry); + + if (grpDN == NULL) + { + rc = ldap_get_errno(ld); + len = snprintf(dumpMsg, sizeof(dumpMsg), "LDAP findGroupsByMember:\n" + "ldap rc=%d (%s) trying to get DN for search result\n" + "search DN='%s'\n" + "filter='%s'", + rc, ldap_err2string(rc), DN, filter); + db2LogFunc(DB2SEC_LOG_ERROR, dumpMsg, len); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + /* If this group DN is already in the list then skip it. */ + if (!isGrpDNinList(head, grpDN)) + { + rc = addGroupToList(head, grpDN); + if (rc != DB2SEC_PLUGIN_OK) + { + len = snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP findGroupsByMember: addGroupToList " + "rc=%d for group DN '%s'\n", rc, grpDN); + db2LogFunc(DB2SEC_LOG_ERROR, dumpMsg, len); + ldap_memfree(grpDN); + goto exit; + } + + } + + ldap_memfree(grpDN); + grpDN = NULL; + + ldapEntry = ldap_next_entry(ld, ldapEntry); + } + +exit: + if (grpDN != NULL) ldap_memfree(grpDN); + if (ldapRes != NULL) ldap_msgfree(ldapRes); + if (dnAsFilter != dnAsFilterBuffer ) free( dnAsFilter ); + + return(rc); +} + + + +/* FindGroups + * + * Find the groups memberships associated with the input AuthID. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN FindGroups(const char *authID, + db2int32 authIDLength, + const char *userID, /* ignored */ + db2int32 userIDLength, /* ignored */ + const char *domain, /* ignored */ + db2int32 domainLength, /* ignored */ + db2int32 domainType, /* ignored */ + const char *databaseName, /* ignored */ + db2int32 databaseNameLength, /* ignored */ + void *token, + db2int32 tokenType, + db2int32 location, + const char *authPluginName, /* ignored */ + db2int32 authPluginNameLength, /* ignored */ + void **groupList, + db2int32 *groupCount, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + LDAP *ld = NULL; + int freeLDAP = FALSE; + int totalLen, len, num; + char local_authid[DB2SEC_MAX_AUTHID_LENGTH + 1]; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + token_t *pToken = NULL; + char *userDN = NULL; + int freeUserDN = FALSE; + char *gname = NULL; + + groupElem *cur = NULL; + groupListHead grpList, grpList2; + unsigned char *ucp = NULL; + + LDAPMessage *ldapRes = NULL; + LDAPMessage *ldapEntry = NULL; + + int (*lookupFnc)(LDAP *, const char *, int, groupListHead *); + + *errorMessage = NULL; + *errorMessageLength = 0; + + memset(&grpList, 0, sizeof(grpList)); + memset(&grpList2, 0, sizeof(grpList2)); + + if (authID == NULL || groupList == NULL || groupCount == NULL) + { + *errorMessage = strdup("LDAP FindGroups: invalid arguments"); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + if (authIDLength > DB2SEC_MAX_AUTHID_LENGTH) + { + strncpy(local_authid, authID, DB2SEC_MAX_AUTHID_LENGTH); + local_authid[DB2SEC_MAX_AUTHID_LENGTH] = '\0'; + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups: " + "AuthID too long (%d bytes)\n[Truncated]:%s", + (int)authIDLength, local_authid); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + memcpy(local_authid, authID, authIDLength); + local_authid[authIDLength] = '\0'; + + if ((location == DB2SEC_SERVER_SIDE) && + (tokenType == DB2SEC_GENERIC) && + (token != NULL)) + { + pToken = (token_t *)token; + + if (memcmp(pToken->eyeCatcher, + DB2LDAP_TOKEN_EYECATCHER, + sizeof(DB2LDAP_TOKEN_EYECATCHER)) == 0) + { + if (pToken->ld != NULL) + { + ld = pToken->ld; + freeLDAP = FALSE; + } + + /* If the authid matches the one stored in the token + * (which it should if we a token at all), we may be + * able to grab the user DN from the token as well. + */ + if ((pToken->userDN[0] != '\0') && + (pToken->authidLen == authIDLength) && + (strcasecmp(pToken->authid, local_authid) == 0)) + { + userDN = pToken->userDN; + } + } + } + + if (ld == NULL) + { + rc = initLDAP(&ld, TRUE, errorMessage); + if (rc != LDAP_SUCCESS) goto exit; + freeLDAP = TRUE; + } + + /* Get the user DN if we don't have it yet. */ + if (userDN == NULL) + { + char filter[MAX_FILTER_LENGTH]; + + snprintf(filter, sizeof(filter), + "(&(objectClass=%s)(%s=%s))", + ConfigData.userObjClass, ConfigData.authidAttr, local_authid); + + rc = ldap_search_s(ld, ConfigData.userBase, LDAP_SCOPE_SUBTREE, + filter, NULL, TRUE, &ldapRes); + if ( rc != LDAP_SUCCESS ) + { + if ( rc == LDAP_REFERRAL ) // We have chased a referral. + { + size_t msgLength = snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups:\n" + "ldap_search_s chased referral rc=%d (%s)\nfilter=%s", + rc, ldap_err2string(rc), filter); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, msgLength); + rc = LDAP_SUCCESS; + } + else + { + if (rc == LDAP_NO_SUCH_OBJECT) + { + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups:\n" + "can't find user with authid '%s'\nrc=%d (%s)\nfilter=%s", + local_authid, rc, ldap_err2string(rc), filter); + rc = DB2SEC_PLUGIN_BADUSER; + } + else + { + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups:\n" + "unexpected LDAP error searching for authid '%s'\n" + "rc=%d (%s)\nfilter=%s", + local_authid, rc, ldap_err2string(rc), filter); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + } + *errorMessage = strdup(dumpMsg); + goto exit; + } + } + + num = ldap_count_entries(ld, ldapRes); + if (num == 0) + { + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups:\n" + "can't find user with authid '%s'\nfilter=%s", + local_authid, filter); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + if (num > 1) + { + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups:\n" + "too many users (%d) found searching for authid '%s'", + num, local_authid); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + ldapEntry = ldap_first_entry(ld, ldapRes); + if (ldapEntry != NULL) + { + userDN = ldap_get_dn(ld, ldapEntry); + freeUserDN = TRUE; + } + if (userDN == NULL) + { + rc = ldap_get_errno(ld); + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups:\n" + "error retreiving user DN after successful authid search\n" + "ldap rc=%d (%s)\nauthid='%s'", + rc, ldap_err2string(rc), local_authid); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + } + + + /* Determine which group lookup function to call. */ + if (ConfigData.groupLookupMethod == GROUP_METHOD_USER_ATTR) + { + lookupFnc = findGroupsByDnAttr; + } + else + { + lookupFnc = findGroupsByMember; + } + + rc = lookupFnc(ld, userDN, FALSE, &grpList); + if (rc != DB2SEC_PLUGIN_OK) + { + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups: " + "rc=%d retrieving groups for authid '%s'\nuserDN='%s'", + rc, local_authid, userDN); + *errorMessage = strdup(dumpMsg); + goto exit; + } + + /* If we found no groups for the user, return now. */ + if (grpList.first == NULL) + { + if (ConfigData.debug) + { + int len; + len = snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups: " + "found no groups for authid '%s'\nuserDN='%s'", + local_authid, userDN); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, len); + } + *groupList = NULL; + *groupCount = 0; + + rc = DB2SEC_PLUGIN_OK; + goto exit; + } + + /* If we want nested group information, walk the linked list of + * groups found above and get the group information for each + * one in turn. The list can grow whlie we're processing it. + */ + if (ConfigData.nestedGroups == TRUE) + { + cur = grpList.first; + while (cur != NULL) + { + rc = lookupFnc(ld, cur->name, TRUE, &grpList); + if (rc != DB2SEC_PLUGIN_OK) + { + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups: " + "rc=%d retrieving nested groups\ngroupDN='%s'", + rc, cur->name); + *errorMessage = strdup(dumpMsg); + goto exit; + } + + cur = cur->next; + } + } + + /* Now we have all the group DNs in a linked list. + * Walk through the list, retreive the group name for each + * group DN and store it in a new list. Keep track of the + * total length we'll need to return the group information. + */ + totalLen = 0; + cur = grpList.first; + while(cur != NULL) + { + gname = NULL; + rc = getGroupNameByDN(ld, cur->name, &gname, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + if (gname != NULL) + { + /* Ignore group names that are too long */ + len = strlen(gname); + if (len <= DB2SEC_MAX_AUTHID_LENGTH) + { + rc = addGroupToList(&grpList2, gname); + if (rc != DB2SEC_PLUGIN_OK) + { + snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP FindGroups: addGroupToList " + "rc=%d for group DN '%s'\n", rc, cur->name); + *errorMessage = strdup(dumpMsg); + goto exit; + } + + totalLen += len + 2; /* length byte + NULL byte */ + } + + free(gname); + gname = NULL; + } + + cur = cur->next; + } + + + /* It's possible that we have no group information here, + * if we couldn't find names for any of the group DNs. + */ + if (totalLen <= 0) + { + if (ConfigData.debug) + { + int len; + len = snprintf(dumpMsg, sizeof(dumpMsg), "LDAP FindGroups: " + "zero length group info\nauthid='%s'\nuserDN='%s'", + local_authid, userDN); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, len); + } + *groupList = NULL; + *groupCount = 0; + + rc = DB2SEC_PLUGIN_OK; + goto exit; + } + + + /* Now malloc & populate the group list that will be returned to DB2. */ + *groupList = malloc(totalLen); + if (*groupList == NULL) + { + *errorMessage = strdup("LDAP FindGroups: malloc failure"); + rc = DB2SEC_PLUGIN_NOMEM; + goto exit; + } + + *groupCount = 0; + ucp = (unsigned char*)(*groupList); + cur = grpList2.first; + while (cur != 0) + { + len = strlen(cur->name); + *ucp = (unsigned char)len; + ucp++; + + memcpy(ucp, cur->name, len); + ucp += len; + + (*groupCount)++; + + cur = cur->next; + } + + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + + /* If DB2 receives a BADUSER returncode from this function it + * assumes the group lookup and authentication plugins are not + * compatible (which could very well be the case). + * + * Since this can be difficult to debug, we want to explicitly + * log the error here, but at INFO level rather than ERROR. + */ + if (rc == DB2SEC_PLUGIN_BADUSER && !ConfigData.debug) + { + db2LogFunc(DB2SEC_LOG_INFO, *errorMessage, *errorMessageLength); + } + else + { + db2LogFunc(DB2SEC_LOG_ERROR, *errorMessage, *errorMessageLength); + } + } + + if (freeUserDN && userDN != NULL) ldap_memfree(userDN); + + if (ldapRes != NULL) ldap_msgfree(ldapRes); + + if (freeLDAP && ld != NULL) ldap_unbind_s(ld); + + if (gname != NULL) free(gname); + + if (grpList.first != NULL) freeList(&grpList); + if (grpList2.first != NULL) freeList(&grpList2); + + return(rc); +} + + + + +/* FreeGroupList + * + * Free the group list information returned from FindGroups. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN FreeGroupList(void *ptr, + char **errorMessage, + db2int32 *errorMessageLength) +{ + if (ptr != NULL) free(ptr); + + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + + + +/* DoesGroupExist + * Search for a user object where the AuthID attribute matches the + * value provided. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN DoesGroupExist(const char *groupID, + db2int32 groupIDlength, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + int filterLength = 0; + LDAP *ld = NULL; + char *errmsg = NULL; + char local_group[DB2SEC_MAX_AUTHID_LENGTH + 1]; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + + *errorMessage = NULL; + *errorMessageLength = 0; + + if (groupID == NULL || groupIDlength <= 0) + { + snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP DoesGroupExist: AUTHID is NULL or bad length (%d)", + (int)groupIDlength); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + /* NULL terminate the groupID */ + if (groupIDlength > DB2SEC_MAX_AUTHID_LENGTH) + { + /* Make a NULL terminated version of known max size */ + strncpy(local_group, groupID, DB2SEC_MAX_AUTHID_LENGTH); + local_group[DB2SEC_MAX_AUTHID_LENGTH] = '\0'; + + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP DoesGroupExist: " + "groupID too long (%d bytes)\n[truncated]:%s", + (int)groupIDlength, local_group); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + memcpy(local_group, groupID, groupIDlength); + local_group[groupIDlength] = '\0'; + + rc = initLDAP(&ld, TRUE, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + rc = db2ldapFindAttrib(ld, + ConfigData.groupBase, + ConfigData.groupObjClass, + ConfigData.groupNameAttr, + local_group, + ConfigData.groupNameAttr, + NULL, + FALSE, + NULL); + + errmsg = NULL; + + switch (rc) + { + case GET_ATTRIB_OK: + case GET_ATTRIB_TOOMANY: /* finding more than one is okay here */ + rc = DB2SEC_PLUGIN_OK; + break; + case GET_ATTRIB_NO_OBJECT: /* search worked, but didn't find a match */ + case GET_ATTRIB_NOTFOUND: + rc = DB2SEC_PLUGIN_INVALIDUSERORGROUP; + break; + case GET_ATTRIB_LDAPERR: + errmsg = (char*)"LDAP error searching for AUTHID"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + case GET_ATTRIB_NOMEM: + errmsg = (char*)"out of memory while searching for AUTHID"; + rc = DB2SEC_PLUGIN_NOMEM; + break; + case GET_ATTRIB_BADINPUT: + default: + errmsg = (char*)"Internal error while searching for AUTHID"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + } + + if (errmsg != NULL) + { + snprintf(dumpMsg, sizeof(dumpMsg), + "LDAP DoesGroupExist: GroupID=%s\n%s", + local_group, errmsg); + *errorMessage = strdup(dumpMsg); + } + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + if (ld != NULL) ldap_unbind_s(ld); + + return (rc); +} + + + + +/* FreeErrorMessage + * All messages returned from this plugin are strdup'd. Free them here. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN FreeErrorMessage(char *msg) +{ + if (msg != NULL) free(msg); + return(DB2SEC_PLUGIN_OK); +} + + + + +/* PluginTerminate + * Terminate & clean up. Nothing to do for this plugin. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN PluginTerminate(char **errorMessage, + db2int32 *errorMessageLength) +{ + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + + + +/* db2secGroupPluginInit + * Plugin initialization. Parse the config file and set up function + * pointers. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN db2secGroupPluginInit(db2int32 version, + void *group_fns, + db2secLogMessage *msgFunc, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + db2secGroupFunction_1 *p; + + *errorMessage = NULL; + *errorMessageLength = 0; + + p = (db2secGroupFunction_1*)group_fns; + + p->version = DB2SEC_GROUP_FUNCTIONS_VERSION_1; + p->plugintype = DB2SEC_PLUGIN_TYPE_GROUP; + p->db2secGetGroupsForUser = FindGroups; + p->db2secDoesGroupExist = DoesGroupExist; + p->db2secFreeGroupListMemory = FreeGroupList; + p->db2secFreeErrormsg = FreeErrorMessage; + p->db2secPluginTerm = PluginTerminate; + + db2LogFunc = msgFunc; + + memset(&ConfigData, 0, sizeof(ConfigData)); + + rc = db2ldapReadConfig(&ConfigData, CFG_GROUPLOOKUP, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + /* If an SSL connection has been configured, initialize SSL support + * here. This must be done once in every plugin library; if we + * don't do this here we run into problems passing the LDAP handle + * between different libraries. + */ + if (ConfigData.isSSL) + { + rc = db2ldapSetGSKitVar(errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + rc = db2ldapInitSSL(&ConfigData, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + } + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + db2LogFunc(DB2SEC_LOG_ERROR, *errorMessage, *errorMessageLength); + } + return(rc); +} diff --git a/security/plugins/IBMLDAPutils.c b/security/plugins/IBMLDAPutils.c new file mode 100644 index 0000000..2937d90 --- /dev/null +++ b/security/plugins/IBMLDAPutils.c @@ -0,0 +1,1030 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 2006 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: IBMLDAPutils.c +** +** SAMPLE: Utility functions used in the DB2 LDAP security plugin +** +***************************************************************************** +** +** For more information on developing DB2 security plugins, see the +** "Developing Security Plug-ins" section of the Application Development +** Guide. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include "IBMLDAPutils.h" + +/* rebindGetCreds + * + * A callback that allows the LDAP client code to obtain bind + * credentials when following referrals. + */ +DB2LDAP_EXT_C static +int rebindGetCreds(LDAP *ld, + char **dn, + char **pw, + int *method, + int dofree) +{ + if ( !dofree ) + { + pluginConfig_t *pCfg = db2ldapGetConfigDataPtr(); + + *method = LDAP_AUTH_SIMPLE; + if (pCfg->haveSearchDN) + { + *dn = pCfg->searchDN; + *pw = pCfg->searchPWD; + } + else + { + *dn = NULL; + *pw = NULL; + } + } + return(LDAP_SUCCESS); +} + + +/* initLDAP + * + * Initialize an LDAP handle, and optionally bind if a searchDN and + * password are defined. + */ +DB2LDAP_EXT_C +int initLDAP(LDAP **ld, + int doBind, + char **errorMsg) +{ + int rc = DB2SEC_PLUGIN_OK; + char *errStr = NULL; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + size_t msgLength = 0 ; + + pluginConfig_t *pCfg = db2ldapGetConfigDataPtr(); + + if (pCfg->isSSL) + { + rc = db2ldapInitSSL(pCfg, errorMsg); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + *ld = ldap_ssl_init(pCfg->ldapHost, LDAPS_PORT, NULL); + if (*ld == NULL) + { + rc = ldap_get_errno(*ld); + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE , + "ldap_ssl_init failed, rc=%d (%s)\nhost list: %s", + rc, ldap_err2string(rc), pCfg->ldapHost); + *errorMsg = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_NETWORKERROR; + goto exit; + } + + if (pCfg->securityProtocol != -1) + { + rc = ldap_set_option(*ld, LDAP_OPT_SSL_SECURITY_PROTOCOL, + pCfg->securityProtocol == SECURITY_PROTOCOL_ALL? + LDAP_SECURITY_PROTOCOL_ALL : LDAP_SECURITY_PROTOCOL_TLSV12); + if (rc != LDAP_SUCCESS) + { + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, + "InitLDAP: failed setting security_protocol opt to %s\nrc=%d (%s)", + pCfg->securityProtocol == SECURITY_PROTOCOL_ALL? + LDAP_SECURITY_PROTOCOL_ALL : LDAP_SECURITY_PROTOCOL_TLSV12, + rc, ldap_err2string(rc)); + *errorMsg = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + } + } + else + { + *ld = ldap_init(pCfg->ldapHost, LDAP_PORT); + if ((*ld) == NULL) + { + rc = ldap_get_errno(*ld); + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE , + "ldap_init failed, rc=%d (%s)\nhost list: %s", + rc, ldap_err2string(rc), pCfg->ldapHost); + *errorMsg = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_NETWORKERROR; + goto exit; + } + } + + rc = ldap_set_option(*ld, LDAP_OPT_REFERRALS, + (void *)(pCfg->followReferrals ? LDAP_OPT_ON: LDAP_OPT_OFF)); + if (rc != LDAP_SUCCESS) + { + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, + "InitLDAP: failed setting referral opt to %d\nrc=%d (%s)", + pCfg->followReferrals, rc, ldap_err2string(rc)); + *errorMsg = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + // Bind to the LDAP server if we can find a bind DN & password. + // If they were not passed in as arguments, check the server data + // to see if they have been configured. + if (doBind && pCfg->haveSearchDN) + { + rc = ldap_simple_bind_s((*ld), pCfg->searchDN, pCfg->searchPWD); + if (rc != LDAP_SUCCESS) + { + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, + "InitLDAP: bind failed rc=%d (%s)\nSearchDN='%s'", + rc, ldap_err2string(rc), pCfg->searchDN); + *errorMsg = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_NETWORKERROR; + goto exit; + } + + // Set up a callback so the LDAP client code can obtain + // credentials when it follows referrals + ldap_set_rebind_proc( *ld, (LDAPRebindProc)rebindGetCreds ); + + } + + rc = DB2SEC_PLUGIN_OK; + +exit: + return rc; +} + +/* db2ldapSetGSKitVar + * + * Set GSKIT_LOCAL_INSTALL_MODE and/or GSKIT_CLIENT_VERSION + */ +DB2LDAP_EXT_C +int db2ldapSetGSKitVar(char **errorMessage) +{ + int rc = DB2SEC_PLUGIN_OK; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + + // set the GSKIT_LOCAL_INSTALL_MODE environment variable if it not set. + // this variable tells ldap to use the version of GSKit which + // DB2 packages. + // Note that these calls are not thread safe on Linux,Windows. + // This is ok because the plugins are only loaded once + // and they are not loaded concurently. + // DB2 on Windows uses global GSKit so not set GSKIT_LOCAL_INSTALL_MODE +#if defined SQLUNIX + if (getenv("GSKIT_LOCAL_INSTALL_MODE") == NULL) + { + rc = setenv( "GSKIT_LOCAL_INSTALL_MODE","1",1) ; + if (rc != 0) + { + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, "db2ldapSetGSKitVar: " + "setenv failed, rc= %d",rc); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + } +#endif + + // Set the GSKIT_CLIENT_VERSION environment variable if it not set. + // As of DB2 V9.7 GA, DB2 packages GSKit 8, and the LDAP client that + // DB2 LDAP Plugins use is TSA LDAP Client 6.2. Without setting this + // variable, the LDAP client will try to load GSKit 7 packages by + // default. Setting it outside the plugins would not work because + // this varialbe may not always available inside the plugins. + if (getenv("GSKIT_CLIENT_VERSION") == NULL) + { +#if defined SQLUNIX + rc = setenv( "GSKIT_CLIENT_VERSION","8",1 ) ; +#elif defined SQLWINT + rc = _putenv( "GSKIT_CLIENT_VERSION=8" ) ; +#endif + if (rc != 0) + { +#if defined SQLUNIX + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, "db2ldapSetGSKitVar: " + "setenv failed, rc= %d",rc); +#elif defined SQLWINT + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, "db2ldapSetGSKitVar: " + "_putenv failed, rc= %d",rc); +#endif + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + } + +exit: + return(rc); +} + +/* db2ldapInitSSL + * + * Initialize the LDAP client SSL support with the configured + * key file and passphrase. + */ +DB2LDAP_EXT_C +int db2ldapInitSSL(pluginConfig_t *cfg, char **errorMessage) +{ + int rc = DB2SEC_PLUGIN_OK; + int sslrc = 0; + char *keyfile=NULL, *sslpass=NULL; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + +#if defined( HPUX ) + int MAX_KEYFILE_SIZE = 396; +#elif defined( SQLSUN ) + int MAX_KEYFILE_SIZE = 1024; +#endif + + if (cfg->isSSL) + { + if (cfg->sslKeyfile[0] != '\0') keyfile = cfg->sslKeyfile; + if (cfg->sslPwd[0] != '\0') sslpass = cfg->sslPwd; + +#if defined( HPUX ) || defined( SQLSUN ) + /* wsdbu01304366 ldapsecp bucket testcase ldap022sb.pl failed on Sun64 + Temporary fix for GSKit V8.0.50.47 problem on Sun64 Ticket no: b7967 + GSKit traps when SSL_KEYFILE has filename size of 1024. + In normal execution, GSKit should return error 102 when SSL_KEYFILE + filename size is 1024 but this does not happened in V8.0.50.47 on + Sun64. The following path is added to workaround the problem while + waiting for the fix from GSKit. + */ + if ( keyfile != NULL && strlen(keyfile) >= MAX_KEYFILE_SIZE ) + { + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, "db2ldapInitSSL: " + "Keyfile name exceeds maximum allowable length"); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } +#endif + + if( cfg->sslExtnSigAlg[0] != '\0' ) + { + rc = ldap_ssl_set_extn_sigalg( cfg->sslExtnSigAlg ); + + if (rc != LDAP_SUCCESS) + { + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, + "ldap_ssl_set_extn_sigalg: failed setting to [%s]\nrc=%d (%s)", + cfg->sslExtnSigAlg, + rc, ldap_err2string(rc)); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + } + + if (cfg->isFipsOn) + { + /* Set FIPS mode ON */ + rc = ldap_ssl_set_fips_mode_np(1); + if ( rc != LDAP_SUCCESS ) + { + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, "db2ldapInitSSL: " + "ldap_ssl_set_fips_mode_np failed, rc=%d (%s)", + rc, ldap_err2string(rc)); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + } + + rc = ldap_ssl_client_init(keyfile, + sslpass, + 0, + &sslrc); + if ( rc != LDAP_SUCCESS && rc != LDAP_SSL_ALREADY_INITIALIZED ) + { + snprintf(dumpMsg, MAX_ERROR_MSG_SIZE, "db2ldapInitSSL: " + "ldap_ssl_client_init failed, rc=%d (%s), sslrc=%d", + rc, ldap_err2string(rc), sslrc); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + rc = DB2SEC_PLUGIN_OK; + } + +exit: + return(rc); +} + + +/* db2ldapFindAttrib + * + * Returns the string value found using the ldap base, object class, + * search attribute name & value, and result attribute provided as input. + * Returns zero if exactly one matching value is found. + * + * Returns: + * GET_ATTRIB_OK - Success + * GET_ATTRIB_NO_OBJECT - Search did not find the requested object + * GET_ATTRIB_NOTFOUND - Search did not return the requested attribute + * GET_ATTRIB_TOOMANY - More than one value returned for attribute + * GET_ATTRIB_LDAPERR - An LDAP error occured + * GET_ATTRIB_BADINPUT - Input parameters inccorect + * GET_ATTRIB_NOMEM - strdup failed + * + * If at least one match is found, the first value is returned in + * *resultString. This string must later be freed by the caller + * using "free". ResultString can be passed as NULL if + * the value is not required by the caller. + * + * If objectOnly is TRUE, the search will be limited to the base + * object itself (LDAP_SCOPE_BASE). Otherwise a subtree search is + * performed. If objectOnly is TRUE, searchAttr and/or searchAttrValue + * may be NULL, in which case they are not used to form the filter. + * + * If objectDN is not NULL, the DN of the first object in the + * search results is returned. String must be free'd by the caller. + */ +int db2ldapFindAttrib(LDAP *ld, + const char *ldapbase, + const char *objectClass, // Used in filter + const char *searchAttr, // Used in filter + const char *searchAttrValue, // Used in filter + const char *resultAttr, // Attribute to return + char **resultString, // Output, can be NULL + int objectOnly, // Search object or subtree? + char **objectDN) // Output, can be NULL +{ + int rc = DB2SEC_PLUGIN_OK; + char *attrs[2]; + char *cp = NULL; + char **values = NULL; + char filter[MAX_FILTER_LENGTH]; + size_t filterLength = 0; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + int entryNum = 0; + int msgLength; + int scope; + + LDAPMessage *searchResult = NULL; + LDAPMessage *ldapEntry = NULL; + + pluginConfig_t *pCfg = db2ldapGetConfigDataPtr(); + + if (objectClass == NULL || resultAttr == NULL || + (!objectOnly && (searchAttr == NULL || searchAttrValue == NULL))) + { + rc = GET_ATTRIB_BADINPUT; + goto exit; + } + + scope = (objectOnly) ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE ; + + if (searchAttr == NULL || searchAttrValue == NULL) + { + filterLength = snprintf(filter, sizeof(filter), + "(objectClass=%s)", + objectClass); + } + else + { + filterLength = snprintf(filter, sizeof(filter), + "(&(objectClass=%s)(%s=%s))", + objectClass, searchAttr, searchAttrValue); + } + + if (filterLength >= sizeof(filter)) + { + filter[sizeof(filter)-1] = '\0'; + msgLength = snprintf(dumpMsg, sizeof(dumpMsg), + "db2ldapFindAttrib: filter too long:%s", + filter); + db2LogFunc(DB2SEC_LOG_ERROR, dumpMsg, msgLength); + rc = GET_ATTRIB_BADINPUT; + goto exit; + } + attrs[0] = (char *)resultAttr; + attrs[1] = NULL; + + rc = ldap_search_s(ld, ldapbase, scope, filter, attrs, FALSE, &searchResult); + if (rc == LDAP_NO_SUCH_OBJECT) + { + rc = GET_ATTRIB_NO_OBJECT; + goto exit; + } + else if ( rc == LDAP_REFERRAL ) // We have chased a referral. + { + msgLength = snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapFindAttrib:\n" + "ldap_search_s chased referral rc=%d (%s)\nfilter=%s", + rc, ldap_err2string(rc), filter); + db2LogFunc(DB2SEC_LOG_INFO, dumpMsg, msgLength); + rc = LDAP_SUCCESS; + } + else if ( rc != LDAP_SUCCESS ) + { + msgLength = snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapFindAttrib:\n" + "ldap_search_s failed rc=%d (%s)\nfilter=%s", + rc, ldap_err2string(rc), filter); + db2LogFunc(DB2SEC_LOG_ERROR, dumpMsg, msgLength); + rc = GET_ATTRIB_LDAPERR; + goto exit; + } + + entryNum = ldap_count_entries(ld, searchResult); + + if (entryNum < 1) + { + rc = GET_ATTRIB_NO_OBJECT; + goto exit; + } + else if (entryNum > 1) + { + /* Not a fatal error... continue. */ + rc = GET_ATTRIB_TOOMANY; + if (pCfg->debug) + { + msgLength = snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapFindAttrib: " + "found %d results (scope=%d)\nfilter=%s", + entryNum, scope, filter); + db2LogFunc(DB2SEC_LOG_WARNING, dumpMsg, msgLength); + } + } + + ldapEntry = ldap_first_entry(ld, searchResult); + if (ldapEntry == NULL) + { + rc = GET_ATTRIB_NOTFOUND; + goto exit; + } + + values = ldap_get_values(ld, ldapEntry, attrs[0]); + if (values == NULL || values[0] == NULL) + { + rc = GET_ATTRIB_NOTFOUND; + goto exit; + } + if (values[1] != NULL) + { + rc = GET_ATTRIB_TOOMANY; + if (pCfg->debug) + { + int num=2; + while (values[num] != NULL) num++; + msgLength = snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapFindAttrib: " + "found %d values for attribyte '%s'\nfilter=%s", + num, attrs[0], filter); + db2LogFunc(DB2SEC_LOG_WARNING, dumpMsg, msgLength); + } + /* Not a fatal error... continue. */ + } + + if (resultString != NULL) + { + *resultString = strdup(values[0]); + if (*resultString == NULL) + { + rc = GET_ATTRIB_NOMEM; + goto exit; + } + } + + /* Return the objectDN if requested. */ + if (objectDN != NULL) + { + cp = ldap_get_dn(ld, ldapEntry); + if (cp == NULL) + { + rc = GET_ATTRIB_LDAPERR; + goto exit; + } + + *objectDN = strdup(cp); + ldap_memfree(cp); + + if (*objectDN == NULL) + { + rc = GET_ATTRIB_NOMEM; + goto exit; + } + } + +exit: + if (rc == GET_ATTRIB_LDAPERR) + { + int ldaprc = ldap_get_errno(ld); + int len; + len = snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapFindAttrib: " + "unexpected LDAP rc=%d (%s)", + ldaprc, ldap_err2string(ldaprc)); + db2LogFunc(DB2SEC_LOG_ERROR, dumpMsg, len); + } + + if (values != NULL) ldap_value_free(values); + if (searchResult != NULL) ldap_msgfree(searchResult); + + return rc; +} + + + +/* db2ldapGetUserDN + * + * Take a user-supplied "userid" and search for the associated user + * DN on the LDAP server. + * + * Three different userid formats are understood: + * user (no "=" in userid) + * - Search for "cfg->useridAttr = user" with a base of "cfg->userBase" + * + * attr=abc (at least one "=") + * - Use the userid string as-is for search, with base of "cfg->userBase" + * + * attr1=a,attr2=b,... (more than one "=" and at least one ",") + * - Use the userid string as the base, search for "(objectClass=*)" + * (to succeed, the userid string must generally be a complete DN) + * + * Note: userid must be NULL terminated. + * + * The user DN is returned in "userDN", which must be a pointer to a + * buffer of at least DB2LDAP_MAX_DN_SIZE + 1 bytes. + * + * If authID is not NULL, it should be a pointer to a buffer of at least + * DB2SEC_MAX_AUTHID_LENGTH + 1 bytes, in which the value of the authid + * attribute will be returned. If no authid attribute is found, or if + * more than one value is returned for the user, the authID will be + * the empty string and an error will be returned. + */ +DB2LDAP_EXT_C +int db2ldapGetUserDN(LDAP *ld, + const char *userid, + char *userDN, + char *authID, /* May be NULL */ + char **errorMessage) +{ + int rc = DB2SEC_PLUGIN_OK; + int numEqual = 0; + int gotComma = FALSE; + char *firstEqual = NULL; + int len; + int cnt = 0; + int scope; + int ldaprc, first_ldaprc; + int retried = FALSE; + char *cp = NULL; + char *attrs[2]; + char filter[MAX_FILTER_LENGTH]; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + char **values = NULL; + const char *ldapbase = NULL; + + LDAPMessage *ldapRes = NULL; + LDAPMessage *ldapEntry = NULL; + + pluginConfig_t *pCfg = db2ldapGetConfigDataPtr(); + + + /* Walk through the provided userid, counting "=" and ",". + * Keep track of the first "=" we find (useful below). + */ + cp = (char*)userid; + while (*cp != '\0' && (numEqual < 2 || !gotComma)) + { + if (*cp == ',') gotComma = TRUE; + if (*cp == '=') + { + numEqual++; + if (firstEqual == NULL) firstEqual = cp; + } + cp++; + } + + if (numEqual > 1 && gotComma) + { + /* userid appears to be a full DN */ + snprintf(filter, sizeof(filter), + "(objectClass=%s)", pCfg->userObjClass); + ldapbase = userid; + scope = LDAP_SCOPE_BASE; + } + else if (numEqual > 0) + { + /* userid is "attr=value" */ + snprintf(filter, sizeof(filter), + "(&(objectClass=%s)(%s))", + pCfg->userObjClass, userid); + ldapbase = pCfg->userBase; + scope = LDAP_SCOPE_SUBTREE; + } + else + { + /* just plain "userid" */ + snprintf(filter, sizeof(filter), + "(&(objectClass=%s)(%s=%s))", + pCfg->userObjClass, pCfg->useridAttr, userid); + ldapbase = pCfg->userBase; + scope = LDAP_SCOPE_SUBTREE; + } + + +retry_search: + if (pCfg->debug) + { + len = snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN: " + "searching (retried=%d scope=%d) with\nbase=%s\nfilter=%s", + retried, scope, ldapbase, filter); + db2LogFunc(DB2SEC_LOG_WARNING, dumpMsg, len); + } + + /* Grab the authid while we're at it. */ + attrs[0] = pCfg->authidAttr; + attrs[1] = NULL; + + ldaprc = ldap_search_s(ld, ldapbase, scope, + filter, attrs, 0, &ldapRes); + if (ldaprc != LDAP_SUCCESS && ldaprc != LDAP_REFERRAL) + { + /* If we didn't find the user fall through, to the retry logic below */ + cnt = 0; + } + else + { + ldaprc = LDAP_SUCCESS; + cnt = ldap_count_entries(ld, ldapRes); + } + + if (cnt == 0) + { + if (!retried) + { + /* It's possible that we parsed the userid incorrectly. + * If the userid is "a=bcd", we did a search for attribute + * "a" with value "bcd". Try again, treating the supplied + * userid as plain userid, qualified by the configured userid + * attribute. + */ + + first_ldaprc = ldaprc; + + /* We only retry if the userid contains at least one "=". */ + if (strchr(userid, '=') != NULL) + { + /* Free a bunch of stuff before we overwrite the pointers. */ + if (ldapRes != NULL) ldap_msgfree(ldapRes); + ldapRes = NULL; + + snprintf(filter, sizeof(filter), "(&(objectClass=%s)(%s=%s))", + pCfg->userObjClass, pCfg->useridAttr, userid); + ldapbase = pCfg->userBase; + scope = LDAP_SCOPE_SUBTREE; + + retried = TRUE; + goto retry_search; + } + } + + /* To reach this point we've either already retried or decided + * not to (because the userid didn't contain a "="). + */ + if (first_ldaprc == LDAP_SUCCESS) + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN:\n" + "LDAP search for user '%s' returned no results", userid); + } + else + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN:\n" + "LDAP search failed with ldap rc=%d (%s)\nuser='%s'", + first_ldaprc, ldap_err2string(first_ldaprc), userid); + } + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + + if (cnt > 1) + { + len = snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN:\n" + "search for user '%s' returned multiple (%d) entries", + userid, cnt); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + ldapEntry = ldap_first_entry(ld, ldapRes); + if (ldapEntry == NULL) + { + /* No user found that matches the search criteria. */ + len = snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN:\n" + "ldap_first_entry returned NULL with %d results\n" + "user '%s'", cnt, userid); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + cp = ldap_get_dn(ld, ldapEntry); + if (cp == NULL) + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN:\n" + "ldap_get_dn failed for user '%s'", userid); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + len = strlen(cp); + if (len > DB2LDAP_MAX_DN_SIZE) + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN:\n" + "DN for user '%s' is too long (%d bytes):\n%s", + userid, len, cp); + *errorMessage = strdup(dumpMsg); + ldap_memfree(cp); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + strcpy(userDN, cp); + ldap_memfree(cp); + + if (authID != NULL) + { + /* Grab the AuthID from the entry */ + values = ldap_get_values(ld, ldapEntry, pCfg->authidAttr); + + authID[0] = '\0'; + + /* If we find exactly only value, store it away. */ + if (values != NULL && values[0] != NULL) + { + if (values[1] != NULL) + { + /* Too many results for this attribute */ + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN: " + "too many AuthID values found for user '%s'", + userid); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + len = strlen(values[0]); + if (len > DB2SEC_MAX_AUTHID_LENGTH) + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN: " + "authID too long (%d bytes)\nuser='%s'\nauthID='%s'", + len, userid, values[0]); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + strcpy(authID, values[0]); + } + else + { + snprintf(dumpMsg, sizeof(dumpMsg), "db2ldapGetUserDN: " + "no AuthID values found for user '%s'", + userid); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + } + +exit: + if (values != NULL) ldap_value_free(values); + if (ldapRes != NULL) ldap_msgfree(ldapRes); + return(rc); +} + + +/* CheckPassword + * + * Parse the input userid, search for it in LDAP, then bind to + * the LDAP server using the supplied password. + */ +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN CheckPassword(const char *userID, + db2int32 userIDLength, + const char *domain, /* ignored */ + db2int32 domainLength, /* ignored */ + db2int32 domainType, /* ignored */ + const char *password, + db2int32 passwordLength, + const char *newPassword, + db2int32 newPasswordLength, + const char *databaseName, /* not used */ + db2int32 databaseNameLength, /* not used */ + db2Uint32 connection_details, + void **token, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + LDAP *ld = NULL; + LDAP *ld_auth = NULL; + token_t *pluginToken = NULL; + char *authIDptr = NULL; + char user[DB2SEC_MAX_USERID_LENGTH + 1]; + char userDN[DB2LDAP_MAX_DN_SIZE + 1] = { '\0' }; + char authID[DB2SEC_MAX_AUTHID_LENGTH + 1] = { '\0' }; + char local_passwd[DB2SEC_MAX_PASSWORD_LENGTH + 1]; + char dumpMsg[MAX_ERROR_MSG_SIZE]; + + pluginConfig_t *pCfg = db2ldapGetConfigDataPtr(); + + *errorMessage = NULL; + *errorMessageLength = 0; + + if (newPassword != NULL && newPasswordLength > 0) + { + *errorMessage = strdup("Change password not supported"); + rc = DB2SEC_PLUGIN_CHANGEPASSWORD_NOTSUPPORTED; + goto exit; + } + + if (userID == NULL || userIDLength <= 0) + { + rc = DB2SEC_PLUGIN_BADUSER; + goto exit ; + } + + /* Check userID length */ + if ( userIDLength > DB2SEC_MAX_USERID_LENGTH ) + { + strncpy(user, userID, sizeof(user)-1); + user[sizeof(user)-1] = '\0'; + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP CheckPassword:\n" + "userid too long: %d bytes\n[truncated]:%s\n", + (int)userIDLength, user); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + memcpy(user, userID, userIDLength); + user[userIDLength] = '\0'; + + + if (passwordLength > DB2SEC_MAX_PASSWORD_LENGTH || passwordLength < 0) + { + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP CheckPassword:\n" + "bad password length (%d) for user '%s'", (int)passwordLength, user); + rc = DB2SEC_PLUGIN_BADPWD; + goto exit; + } + + if (passwordLength <= 0 || password == NULL) + { + passwordLength = 0; + } + else + { + memcpy(local_passwd, password, passwordLength); + local_passwd[passwordLength] = '\0'; + } + + /* Only bother looking up the AuthID if we're on the server. */ + if (connection_details & DB2SEC_VALIDATING_ON_SERVER_SIDE) + { + authIDptr = authID; + } + + + /* Initialize the LDAP handle we'll use for all searches. */ + rc = initLDAP(&ld, TRUE, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + + rc = db2ldapGetUserDN(ld, user, userDN, authIDptr, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + + /* It is acceptable not to supply a password only in the + * following scenario: + * - The username was not supplied by the user, and + * - If we're on the server side, the connection must + * be "local" (originating from the same machine) + * + * APAR JR32272, JR32273 and JR32268. Do extra strlen() + * check on the password as a password with all binary + * zeros could turn the bind into an anonymous bind. + * If an anonymous bind is allowed by the LDAP server + * then this would allow a user with an invalid + * password to pass authentication. + */ + if (passwordLength == 0 || strlen(local_passwd) == 0) + { + if ((connection_details & DB2SEC_USERID_FROM_OS) && + ((connection_details & DB2SEC_CONNECTION_ISLOCAL) || + !(connection_details & DB2SEC_VALIDATING_ON_SERVER_SIDE))) + { + goto skip_bind; + } + rc = DB2SEC_PLUGIN_BADPWD; + goto exit; + } + + + /* Use a seperate LDAP handle for "bind" authentication. */ + rc = initLDAP(&ld_auth, FALSE, errorMessage); + if (rc != DB2SEC_PLUGIN_OK) goto exit; + + rc = ldap_simple_bind_s(ld_auth, userDN, local_passwd); +#ifdef DB2LDAP_DEBUG + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP CheckPassword:\n" + "bind rc=%d with '%s' / '%s'", rc, userDN, local_passwd); + db2LogFunc(DB2SEC_LOG_WARNING, dumpMsg, strlen(dumpMsg)); +#endif + if (rc != LDAP_SUCCESS) + { + if (rc == LDAP_INVALID_DN_SYNTAX) + { + rc = DB2SEC_PLUGIN_BADUSER; + } + else if (rc == LDAP_INVALID_CREDENTIALS) + { + rc = DB2SEC_PLUGIN_BADPWD; + } + else + { + snprintf(dumpMsg, sizeof(dumpMsg), "LDAP CheckPassword:\n" + "unexpected LDAP error binding DN '%s'\nldaprc=%d (%s)", + userDN, rc, ldap_err2string(rc)); + *errorMessage = strdup(dumpMsg); + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + } + goto exit; + } + + /* Unbind the LDAP handle used for authentication. */ + ldap_unbind_s(ld_auth); + ld_auth = NULL; + + +skip_bind: + + /* If we're on the server, set up the plugin token so + * we can pass information into subsequent calls. + * This reduces the number of LDAP queries. + */ + if (token != NULL && connection_details & DB2SEC_VALIDATING_ON_SERVER_SIDE) + { + pluginToken = (token_t *)malloc(sizeof(token_t)); + + /* If the malloc fails we proceed without a token */ + if (pluginToken != NULL) + { + memset(pluginToken,0,sizeof(token_t)); + strcpy(pluginToken->eyeCatcher, DB2LDAP_TOKEN_EYECATCHER); + + /* Copy the user DN into the token. */ + strcpy(pluginToken->userDN, userDN); + + /* Copy the authID as well, if we have it. */ + if (authID[0] != '\0') + { + strcpy(pluginToken->authid, authID); + pluginToken->authidLen = strlen(authID); + } + + /* Store the LDAP handle in the token and prevent it from + * being freed below. We'll reuse this to get the AuthID + * and retreive the groups. It will eventually be cleaned + * up in FreeToken. + */ + pluginToken->ld = ld; + ld = NULL; + + *token = pluginToken; + } + } + + rc = DB2SEC_PLUGIN_OK; + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = (db2int32)strlen(*errorMessage); + if (pCfg->debug) + db2LogFunc(DB2SEC_LOG_WARNING, *errorMessage, *errorMessageLength); + } + + if (ld != NULL) ldap_unbind_s(ld); + if (ld_auth != NULL) ldap_unbind_s(ld_auth); + + return(rc); +} + diff --git a/security/plugins/IBMLDAPutils.h b/security/plugins/IBMLDAPutils.h new file mode 100644 index 0000000..01ef0d8 --- /dev/null +++ b/security/plugins/IBMLDAPutils.h @@ -0,0 +1,286 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 2006 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: IBMLDAPutils.h +** +** SAMPLE : LDAP security plugin header file. +** +***************************************************************************** +** +** For more information on developing DB2 security plugins, see the +** "Developing Security Plug-ins" section of the Application Development +** Guide. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef _H_DB2_IBMLDAPUTILS +#define _H_DB2_IBMLDAPUTILS + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include +#include + +#ifdef SQLUNIX + #include + #include +#else + #define strcasecmp(a,b) stricmp(a,b) + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#ifdef __cplusplus +#define DB2LDAP_EXT_C extern "C" +#else +#define DB2LDAP_EXT_C +#endif + +#define DB2LDAP_ESCAPE_CHAR '\\' + +#define MAX_ERROR_MSG_SIZE 2048 +#define MAX_FILTER_LENGTH 2048 + +#define DB2LDAP_MAX_DN_SIZE 1024 + +/* LDAP Plugin Config File + * + * File syntax: + * - Lines have the format "key = value" + * - Leading and trailing whitespace is stripped from both "key" and "value" + * - "key" may not contain whitespace (other than leading/trailing + * - "value" may contain whitepace + * - ";" begins a comment anywhere on a line + * - blank lines are allowed + * + * File location: + * - May be configured in the DB2LDAP_ENV_CFGFILE environment variable + * - Default values below (under instance home on UNIX, $DB2PATH on Windows) + */ + +#define DB2LDAP_ENV_CFGFILE "DB2LDAPSecurityConfig" + +#define DB2LDAP_CFGDFLT_WIN "\\cfg\\IBMLDAPSecurity.ini" +#define DB2LDAP_CFGDFLT_UNIX "/sqllib/cfg/IBMLDAPSecurity.ini" + +#define CFG_MAX_PARMNAME_LEN 64 +#define CFG_MAX_FILENAME 1024 +#define CFG_MAX_HOST_SIZE 500 +#define CFG_MAX_ATTR 128 +#define CFG_MAX_PSWD 256 +#define CFG_MAX_DN DB2LDAP_MAX_DN_SIZE +#define CFG_MAX_EXTN_SIGALG 512 + +/* Max line length is exactly 1092 visible bytes */ +#ifdef SQLWINT +/* Account for extra "CR" line terminator on Windows */ +#define CFG_MAX_LINE_LEN (CFG_MAX_PARMNAME_LEN + CFG_MAX_FILENAME + 7) +#else +#define CFG_MAX_LINE_LEN (CFG_MAX_PARMNAME_LEN + CFG_MAX_FILENAME + 6) +#endif + +#define CFGKEY_HOST "LDAP_HOST" +#define CFGKEY_ENABLE_SSL "ENABLE_SSL" +#define CFGKEY_SSL_KEYFILE "SSL_KEYFILE" +#define CFGKEY_SSL_PW "SSL_PW" +#define CFGKEY_SEARCH_DN "SEARCH_DN" +#define CFGKEY_SEARCH_PW "SEARCH_PW" +#define CFGKEY_USER_BASEDN "USER_BASEDN" +#define CFGKEY_USERID_ATTRIBUTE "USERID_ATTRIBUTE" +#define CFGKEY_AUTHID_ATTRIBUTE "AUTHID_ATTRIBUTE" +#define CFGKEY_USER_OBJECTCLASS "USER_OBJECTCLASS" +#define CFGKEY_GROUP_BASEDN "GROUP_BASEDN" +#define CFGKEY_GROUP_OBJECTCLASS "GROUP_OBJECTCLASS" +#define CFGKEY_GROUPNAME_ATTRIBUTE "GROUPNAME_ATTRIBUTE" +#define CFGKEY_GROUP_LOOKUP_ATTRIBUTE "GROUP_LOOKUP_ATTRIBUTE" +#define CFGKEY_GROUP_LOOKUP_METHOD "GROUP_LOOKUP_METHOD" +#define CFGKEY_NESTED_GROUPS "NESTED_GROUPS" +#define CFGKEY_FOLLOW_REFERRALS "FOLLOW_REFERRALS" +#define CFGKEY_DEBUG "DEBUG" +#define CFGKEY_FIPS_MODE "FIPS_MODE" +#define CFGKEY_SECURITY_PROTOCOL "SECURITY_PROTOCOL" +#define CFGKEY_SSL_EXTN_SIGALG "SSL_EXTN_SIGALG" + +#define GROUP_METHOD_STR_USER_ATTR "USER_ATTRIBUTE" +#define GROUP_METHOD_STR_SEARCH_BY_DN "SEARCH_BY_DN" +#define GROUP_METHOD_USER_ATTR 1 +#define GROUP_METHOD_SEARCH_BY_DN 2 + +#define SECURITY_PROTOCOL_STR_ALL "ALL" +#define SECURITY_PROTOCOL_STR_TLS12 "TLSV12" +#define SECURITY_PROTOCOL_ALL 1 +#define SECURITY_PROTOCOL_TLS12 2 + +// The Supported signature hash extensions are: +// GSK_TLS_SIGALG_RSA_WITH_SHA224 +// GSK_TLS_SIGALG_RSA_WITH_SHA256 +// GSK_TLS_SIGALG_RSA_WITH_SHA384 +// GSK_TLS_SIGALG_RSA_WITH_SHA512 +// GSK_TLS_SIGALG_ECDSA_WITH_SHA224 +// GSK_TLS_SIGALG_ECDSA_WITH_SHA256 +// GSK_TLS_SIGALG_ECDSA_WITH_SHA384 +// GSK_TLS_SIGALG_ECDSA_WITH_SHA512 + + +/* The "types" parameter to db2ldapReadConfig is a bitmask that + * determines which keys are mandatory. + */ +#define CFG_USERAUTH 0x01 +#define CFG_GROUPLOOKUP 0x02 + +typedef struct +{ + /* LDAP Server Config */ + int haveSearchDN; + int groupLookupMethod; + int nestedGroups; + int isSSL; + int followReferrals; + int debug; + int isFipsOn; + int securityProtocol; + + char ldapHost[CFG_MAX_HOST_SIZE+1]; + + char searchDN[CFG_MAX_DN+1]; + char searchPWD[CFG_MAX_PSWD+1]; + + char sslKeyfile[CFG_MAX_FILENAME+1]; /* SSL keyfile */ + char sslPwd[CFG_MAX_PSWD+1]; /* Passphrase for keyfile */ + char sslExtnSigAlg[CFG_MAX_EXTN_SIGALG+1]; /* TLS signature algorithms extension. */ + + char userBase[CFG_MAX_DN+1]; /* Base for user searches */ + char userObjClass[CFG_MAX_ATTR+1]; /* ObjClass for users */ + char useridAttr[CFG_MAX_ATTR+1]; /* UserID Attribute */ + char authidAttr[CFG_MAX_ATTR+1]; /* AuthID Attribute */ + + char groupBase[CFG_MAX_DN+1]; /* Base for group searches */ + char groupObjClass[CFG_MAX_ATTR+1]; /* ObjClass for groups */ + char groupLookupAttr[CFG_MAX_ATTR+1]; /* Attr used to find group */ + char groupNameAttr[CFG_MAX_ATTR+1]; /* Group name attribute */ +} pluginConfig_t; + +DB2LDAP_EXT_C +int db2ldapReadConfig(pluginConfig_t *cfg, + int types, /* Bitmask (see below) */ + char **errorMessage); + +DB2LDAP_EXT_C +pluginConfig_t *db2ldapGetConfigDataPtr(void); + + + +#define DB2LDAP_TOKEN_EYECATCHER "DB2-LDAP-PLUGIN" + +typedef struct { + char eyeCatcher[sizeof(DB2LDAP_TOKEN_EYECATCHER)]; + LDAP *ld; + char userDN[DB2LDAP_MAX_DN_SIZE+1]; + int authidLen; + char authid[DB2SEC_MAX_AUTHID_LENGTH+1]; +} token_t; + + +DB2LDAP_EXT_C +db2secLogMessage *db2LogFunc; + +DB2LDAP_EXT_C +SQL_API_RC SQL_API_FN CheckPassword(const char *userID, + db2int32 userIDLength, + const char *domain, /* ignored */ + db2int32 domainLength, /* ignored */ + db2int32 domainType, /* ignored */ + const char *password, + db2int32 passwordLength, + const char *newPassword, + db2int32 newPasswordLength, + const char *databaseName, /* not used */ + db2int32 databaseNameLength, /* not used */ + db2Uint32 connection_details, + void **token, /* not used */ + char **errorMessage, + db2int32 *errorMessageLength); + + +DB2LDAP_EXT_C +int initLDAP(LDAP **ld, int doBind, char **errorMessage); + +DB2LDAP_EXT_C +int db2ldapSetGSKitVar(char **errorMessage); + +DB2LDAP_EXT_C +int db2ldapInitSSL(pluginConfig_t *cfg, char **errorMessage); + +DB2LDAP_EXT_C +int db2ldapFindAttrib(LDAP *ld, + const char *ldapbase, + const char *objectClass, + const char *searchAttr, + const char *searchAttrValue, + const char *resultAttr, + char **resultString, + int objectOnly, + char **objectDN); + +/* Return codes for db2ldapFindAttrib */ +#define GET_ATTRIB_OK 0x0000 +#define GET_ATTRIB_NO_OBJECT 0x1001 +#define GET_ATTRIB_NOTFOUND 0x1002 +#define GET_ATTRIB_TOOMANY 0x1003 +#define GET_ATTRIB_LDAPERR 0x1004 +#define GET_ATTRIB_BADINPUT 0x1005 +#define GET_ATTRIB_NOMEM 0x1006 + +DB2LDAP_EXT_C +int db2ldapGetUserDN(LDAP *ld, + const char *userid, + char *userDN, + char *authID, + char **errorMessage); + +DB2LDAP_EXT_C +int getDNByFilter + (LDAP *ld, + const char* ldapbase, + char* filter, + char* retDN); + +DB2LDAP_EXT_C +int DoesEntryExistByFilter + (LDAP *ld, + const char* ldapbase, + const char* filter, + int* rc); + +#endif // _H_DB2_IBMLDAPUTILS diff --git a/security/plugins/IBMkrb5.c b/security/plugins/IBMkrb5.c new file mode 100644 index 0000000..d5fd9d0 --- /dev/null +++ b/security/plugins/IBMkrb5.c @@ -0,0 +1,2292 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 2012 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: IBMkrb5.c +** +** SAMPLE: Kerberos 5 authentication security plugin +** +** GSS-APIs USED: +** gss_accept_sec_context - accept the security context +** gss_acquire_cred - acquire credentials handle +** gss_delete_sec_context - delete security context +** gss_display_name - display test representation of internal name +** gss_display_status - display text message for status code +** gss_import_name - convert text name into internal format +** gss_init_sec_context - initialize the security context +** gss_inquire_context - obtain info about current context +** gss_inquire_cred - obtain info about default credential +** gss_krb5_acquire_cred_ccache - obtain GSS-API cred handle from +** krb5 cred cache +** gss_release_buffer - release storage associated with internal buffer +** gss_release_cred - release storage associated with credential handle +** gss_release_name - releases storage associated with internal name +** +** KRB5 APIs USED: +** krb5_build_principal_ext - build principal from component strings +** krb5_cc_destroy - destroy credentials cache +** krb5_cc_intialize - intialize credentials cache +** krb5_cc_resolve - resolve credentials cache +* krb5_free_context - free storage associated with krb5 context +** krb5_free_principal - free storage assciated with principal +** krb5_free_string - free text string +** krb5_get_in_tkt_with_password - obtain tgt using userid/password +** krb5_init_context - create a new krb5 context +** krb5_parse_name - create a krb5 internal name from a text name +** krb5_sname_to_principal - generate principal name from service name +** krb5_svc_get_msg - get text message from krb5 error code +** krb5_unparse_name - convert principal to text string +** krb5_us_timeofday - returns time in seconds & microseconds +** +** STRUCTURES USED: +** gss_buffer_desc +** gss_cred_id_t +** gss_ctx_id_t +** gss_name_t +** krb5_data +** krb5_context +** krb5_principal +** krb5_creds +** krb5_ccache +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +**************************************************************************** +** +** This file is setup to depend on one of three Kerberos implementations +** 1) NAS - Network Authentication Service, AIX only +** 2) Solaris Kerberos - Implementation of Kerberos on Solaris +** 3) MIT source - platforms that direclty match the MIT source implementation +** +** In order for this file to compile, one of the following must be defined +** by the caller. +** NAS_SUPPORT +** SOLARIS_KERBEROS_SUPPORT +** MIT_KERBEROS_SUPPORT +** +****************************************************************************/ + +#include +#include +#include +#include + + +#if defined SOLARIS_KERBEROS_SUPPORT + +#include +#include + +/* krb5.h is broken in Solaris. It does not properly define 'extern "C"' at the + beginning of the file, so we need to do it ourself. This is on 5.10 */ +#if defined(__cplusplus) +#define KRB5INT_BEGIN_DECLS extern "C" { +#define KRB5INT_END_DECLS } +#endif +#include +#include + +#elif defined MIT_KERBEROS_SUPPORT + +#include +#include +#include + +/* MIT KRB5 1.5 has a new error handling message + Mininum supported version of Linux for DB2 is still at 1.4 */ +#if !defined(__linux) +#define MIT_KERBEROS_HAS_GET_ERROR_MSG +#endif +#elif defined NAS_SUPPORT + +#include +#include + +#else +#error undefined Kerberos implementation +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Since we have included the platform specific GSSAPI header files + we will get colisions if we include gssapiDB2.h. So make sure that + it is not included via db2secPlugin.h */ +#define _GSSAPIDB2_H +#include "db2secPlugin.h" + +static const char getenvError[] = "getenv( DB2INSTANCE ) = NULL"; + +/* Global var to keep track of memory allocated during server init */ +static char *pluginServerPrincipalName = NULL; +static gss_name_t pluginServerName = GSS_C_NO_NAME; +static gss_cred_id_t pluginServerCredHandle = GSS_C_NO_CREDENTIAL; + +/* Client and server message logging functions */ +db2secLogMessage *pServerLogMessage; +db2secLogMessage *pClientLogMessage; + + +/****************************************************************************** +* +* Function Name = plugin_gss_display_status +* +* Descriptive Name = Plugin Wrapper to gss_display_status +* +* Function = This wrapper function needs to exist since the NAS +* libraries implemented this function with a slightly +* different prototype than outlined in IETF RFC2744 +* +* Dependencies = None +* +* Restrictions = None +* +* Input = +* +* Output = +* +* Normal Return = GSS_S_COMPLETE +* +* Error Return = GSS-API status codes returned by gss_display_status +* +*******************************************************************************/ +OM_uint32 SQL_API_FN plugin_gss_display_status( OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 * message_context, + gss_buffer_t status_string ) +{ + OM_uint32 majorStatus; + + majorStatus = gss_display_status( minor_status, + status_value, + status_type, + (gss_OID) mech_type, + message_context, + status_string ); + + return( majorStatus ); +} + +/****************************************************************************** +* +* Function Name = getGSSErrorMsg +* +* Descriptive Name = Get the text GSS-API text error message based on the +* major and minor status codes +* +* Function = +* +* Dependencies = Memory to hold error messages are alloacted and +* db2secFreeErrormsg() is assumed to be called to free +* buffer once it is no longer neede +* +* Restrictions = Only the first message for the major and minor status +* codes are obtained. The messages are then +* concatenating into the ErrorMsg. +* No checks are performed to ascertain if buffer already +* allocated. +* +* Input = +* +* Output = +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = None. No error message will be returned in case of error +* +*******************************************************************************/ +void getGSSErrorMsg( OM_uint32 majorStatus, + OM_uint32 minorStatus, + char **ppErrorMsg, + db2int32 *pErrorMsgLen, + const char *funcName ) +{ + OM_uint32 major = GSS_S_COMPLETE; + OM_uint32 minor = GSS_S_COMPLETE; + OM_uint32 msgContext = 0; + gss_buffer_desc majorBuff = GSS_C_EMPTY_BUFFER; + gss_buffer_desc minorBuff = GSS_C_EMPTY_BUFFER; + size_t length = 0; + + + /* + * Get the first major status message + */ + if( majorStatus != GSS_S_COMPLETE ) + { + major = gss_display_status( &minor, + majorStatus, + GSS_C_GSS_CODE, + GSS_C_NULL_OID, + &msgContext, + &majorBuff ); + if( major != GSS_S_COMPLETE ) + { + /* Nothing to really do here since we're already in an error condition */ + goto exit; + } + } + + /* + * Get the first minor status message + */ + if( minorStatus != GSS_S_COMPLETE ) + { + major = gss_display_status( &minor, + minorStatus, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msgContext, + &minorBuff ); + if( major != GSS_S_COMPLETE ) + { + /* Nothing to really do here since we're already in an error condition */ + goto exit; + } + } + + /* Allocate memory for error msg and copy + * + * Note: the +6 to the length is to account for the punctuation and spacing + * used in concatentating the error messages + * the +30 is to account for the two integers that are printed. + */ + length = majorBuff.length + minorBuff.length + strlen(funcName) + 36; + + *ppErrorMsg = (char *) malloc( length ); + if( *ppErrorMsg == NULL ) + { + goto exit; + } + *pErrorMsgLen = length; + + if( majorBuff.length > 0 ) + { + if( minorBuff.length > 0 ) + { + snprintf( *ppErrorMsg, length, "%s: (%u,%i) %.*s. %.*s", + funcName, majorStatus, (krb5_error_code)minorStatus, + (int)majorBuff.length, (char *)majorBuff.value, + (int)minorBuff.length, (char *)minorBuff.value ); + } + else + { + snprintf( *ppErrorMsg, length, "%s: (%u,%i)%.*s", + funcName, majorStatus, (krb5_error_code)minorStatus, + (int)majorBuff.length, (char *)majorBuff.value ); + } + } + else + { + if( minorBuff.length > 0 ) + { + snprintf( *ppErrorMsg, length, "%s: (%u,%i) %.*s", + funcName, majorStatus, (krb5_error_code)minorStatus, + (int)minorBuff.length, (char *)minorBuff.value ); + } + else + { + snprintf( *ppErrorMsg, length, "%s: (%u,%i)", funcName, + majorStatus, (krb5_error_code)minorStatus ); + } + } + + exit: + /* Free GSS-API allocated memory */ + if( majorBuff.length != 0 ) + { + gss_release_buffer( &minor, &majorBuff ); + } + if( minorBuff.length != 0 ) + { + gss_release_buffer( &minor, &minorBuff ); + } + + return; +} + +/****************************************************************************** +* +* Function Name = mapPrincToAuthid +* +* Descriptive Name = Maps the Kerberos Principal into a DB2 AUTHID +* +* Function = +* +* Dependencies = None +* +* Restrictions = Assumes that the principal name is in the format +* name/instance@REALM +* +* Input = pName - Buffer containing the principal name +* +* Output = authid - preallocated buffer (of size +* DB2SEC_MAX_AUTHID_LENGTH) containing the AUTHID +* authidLen - length of the AUTHID string +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = DB2SEC_PLUGIN_BADUSER +* +*******************************************************************************/ +SQL_API_RC mapPrincToAuthid( gss_buffer_t pName, + char *authid, + db2int32 *authidLen ) +{ + SQL_API_RC rc = DB2SEC_PLUGIN_OK; + int count; + char *pTextName; + + /* The authid will simply be derived from the first part of the fully + * qualified principal name. + * e.g., The authid from 'name/instance@REALM' will be 'name' + * DB2 will uppercase the authids and verify adherance to the naming rules + * so no need to do it here + */ + + pTextName = (char *) (pName->value); + for( count=0; count < pName->length; count++ ) + { + if( (pTextName[count] == '@') || (pTextName[count] == '/') ) + { + break; + } + } + + /* + * ALTERNATE MAPPINGS SUGGESTIONS: + * 1 - Return full principal name + * 2 - Read maping from a file + */ + + if( count > DB2SEC_MAX_AUTHID_LENGTH ) + { + rc = DB2SEC_PLUGIN_BADUSER; + goto error; + } + + memcpy( authid, pName->value, count ); + *authidLen = count; + + exit: + + return( rc ); + + error: + + goto exit; + +} + + +/****************************************************************************** +* +* Function Name = mapGSSAPItoDB2SECerror +* +* Descriptive Name = Map a GSS-API major/minor code into DB2SEC error code +* +* Function = +* +* Dependencies = None +* +* Restrictions = None +* +* Input = major - Major status code +* minor - Minor status code +* +* Output = None +* +* Normal Return = Various DB2SEC error code +* +* Error Return = None +* +*******************************************************************************/ +SQL_API_RC mapGSSAPItoDB2SECerror( OM_uint32 major, OM_uint32 minor ) +{ + SQL_API_RC rc = DB2SEC_PLUGIN_OK; + + krb5_error_code kMinorStatus = (krb5_error_code) minor; + + switch( major ) + { + case GSS_S_COMPLETE: + rc = DB2SEC_PLUGIN_OK; + break; + case GSS_S_BAD_NAME: + rc = DB2SEC_PLUGIN_BAD_PRINCIPAL_NAME; + break; + case GSS_S_NO_CRED: + rc = DB2SEC_PLUGIN_NO_CRED; + break; + case GSS_S_CREDENTIALS_EXPIRED: + rc = DB2SEC_PLUGIN_CRED_EXPIRED; + break; + case GSS_S_FAILURE: + switch( kMinorStatus ) + { + case KRB5_FCC_NOFILE: + rc = DB2SEC_PLUGIN_NO_CRED; + break; + case KRB5KRB_AP_ERR_BAD_INTEGRITY: + rc = DB2SEC_PLUGIN_BADPWD; + break; + case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: + rc = DB2SEC_PLUGIN_BADUSER; + break; + case KRB5KDC_ERR_NAME_EXP: + rc = DB2SEC_PLUGIN_UID_EXPIRED; + break; + case KRB5KDC_ERR_KEY_EXP: + rc = DB2SEC_PLUGIN_PWD_EXPIRED; + break; + case KRB5_CC_NOTFOUND: + rc = DB2SEC_PLUGIN_NO_CRED; + break; + default: + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + } + break; + default: + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + } + + return( rc ); +} + +/****************************************************************************** +* +* Function Name = db2secFreeErrormsg +* +* Descriptive Name = Free error message buffer +* +* Function = +* +* Dependencies = Memory to hold error messages are alloacted and +* db2secFreeErrormsg() is assumed to be called to free +* buffer once it is no longer neede +* +* Restrictions = +* +* Input = ppErrorMsg - Pointer to string holding the error message +* that was previously allocated by one of the +* db2sec* plugin functions +* +* Output = None +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = None +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secFreeErrormsg( char *ppErrorMsg ) +{ + free( ppErrorMsg ); + return( DB2SEC_PLUGIN_OK ); +} + + +/****************************************************************************** +* +* Function Name = getKrb5ErrorMsg +* +* Descriptive Name = Get the text GSS-API text error message based on the +* major and minor status codes +* +* Function = +* +* Dependencies = +* +* Restrictions = Only the first message for the major and minor status +* codes are obtained. The messages are then +* concatenating into the ErrorMsg. +* No checks are performed to ascertain if buffer already +* allocated. +* +* Input = +* +* Output = +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = None. No error message will be returned in case of error +* +*******************************************************************************/ +void getKrb5ErrorMsg( krb5_error_code kStatus, + char **ppErrorMsg, + db2int32 *pErrorMsgLen, + const char *funcName ) +{ + char *message = NULL; + int length = 0; + +#if defined MIT_KERBEROS_SUPPORT && defined MIT_KERBEROS_HAS_GET_ERROR_MSG + + + /* krb5_get_error_message is new to the MIT source in 1.5 */ + krb5_context kContext = NULL; + krb5_error_code kstatus; + static char szErrContext[] = "Failed to create krb5 context"; + + /* Create a new krb5 context */ + kstatus = krb5_init_context( &kContext ); + + if( kstatus ) + { + message = szErrContext; + } + else + { + message = (char *) krb5_get_error_message(kContext, kStatus); + } + +#elif defined MIT_KERBEROS_SUPPORT || defined SOLARIS_KERBEROS_SUPPORT + + message = (char *) error_message(kStatus); + +#elif defined NAS_SUPPORT + + krb5_svc_get_msg( (const krb5_ui_4) kStatus, &message ); + +#endif + + if( message ) + { + /* +16 to account for the punctuation in the string and (0x%x) */ + length = strlen(funcName) + sizeof(kStatus) + strlen(message) + 16; + + *ppErrorMsg = (char *) malloc( length ); + if( *ppErrorMsg == NULL ) + { + goto exit; + } + + snprintf( *ppErrorMsg, length, "%s: (0x%x) %s", funcName, kStatus,message ); + *pErrorMsgLen = length; + } + + exit: + +#if defined MIT_KERBEROS_SUPPORT && defined MIT_KERBEROS_HAS_GET_ERROR_MSG + if(kContext != NULL) + { + krb5_free_error_message(kContext, message); /* This function can be used starting krb5 1.5 */ + krb5_free_context( kContext ); /* destroy context */ + } +#elif defined NAS_SUPPORT + + if(message != NULL) + { + krb5_free_string( NULL, message ); + } + +#endif + + return; +} + + +/** + ** CLIENT FUNCTIONS + **/ + +/****************************************************************************** +* +* Function Name = db2secFreeToken +* +* Descriptive Name = Free token allocated by plug-in +* +* Function = Since no token is allocated by this plug-in, this +* function is a no-op. +* +* Dependencies = None +* +* Restrictions = None +* +* Input = token - Pointer to plug-in allocated token +* +* Output = ppErrorMsg - Pointer to a string that will contain +* an error message +* errorMsgLen - Pointer to the length of the error message +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = None +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secFreeToken( void *token, + char **ppErrorMsg, + db2int32 *errorMsgLen ) +{ + /* This is a no-op since we don't use the plugin token */ + return( DB2SEC_PLUGIN_OK ); +} + +/****************************************************************************** +* +* Function Name = db2secGetDefaultLoginContext +* +* Descriptive Name = +* +* Function = This function will return the userid (principal name) +* and authid from the default login context. +* +* Dependencies = None. This function will clean up all allocated +* resources before returing to the caller +* +* Restrictions = +* +* Input = useridtype (not used) +* dbname (not used) +* +* Output = authid +* userid +* token (not used) +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = DB2SEC_PLUGIN_NOTLOGGEDIN +* DB2SEC_PLUGIN_CRED_EXPIRED +* DB2SEC_PLUGIN_UNSPECIFIEDERROR +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secGetDefaultLoginContext ( + char authid[DB2SEC_MAX_AUTHID_LENGTH], + db2int32 *pAuthIdLen, + char userid[DB2SEC_MAX_USERID_LENGTH], + db2int32 *useridLen, + db2int32 useridType, + char userNamespace[DB2SEC_MAX_USERNAMESPACE_LENGTH], + db2int32 *userNamespaceLen, + db2int32 *userNamespaceType, + const char *dbName, + db2int32 dbNameLen, + void **ppToken, + char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + SQL_API_RC rc = DB2SEC_PLUGIN_OK; + OM_uint32 majorStatus = GSS_S_COMPLETE; + OM_uint32 minorStatus; + gss_name_t gssName = GSS_C_NO_NAME; + gss_buffer_desc name = GSS_C_EMPTY_BUFFER; + gss_cred_id_t credHandle = GSS_C_NO_CREDENTIAL; + db2int32 x = 0; + + *ppErrorMsg = NULL; + *pErrorMsgLen = 0; + + /* Token is not allocated by this plugin */ + if( ppToken ) + { + *ppToken = NULL; + } + + /* Namespace is not used */ + *userNamespaceLen = 0; + *userNamespaceType = DB2SEC_USER_NAMESPACE_UNDEFINED; + +#if defined NAS_SUPPORT + /* There is a bug in the NAS code where if the cred_handle is set to + * GSS_C_NO_CREDENTIAL, NAS has a difficult time retreiving the correct + * credential handle if the application has kinit, kdestroy, and then kinit + * as another principal while the application is still up. The workaround is + * to explicitly grab the credential handle for the default login context and + * pass it in to the problematic function + */ + majorStatus = gss_acquire_cred( &minorStatus, + GSS_C_NO_NAME, + 0, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + &credHandle, + NULL, + NULL ); + if( majorStatus != GSS_S_COMPLETE ) + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_acquire_cred" ); + goto error; + } +#endif + + /* Obtain the name associated with the default credential */ + majorStatus = gss_inquire_cred( &minorStatus, + credHandle, + &gssName, + NULL, /* lifetime */ + NULL, /* cred usage */ + NULL ); /* mechanism */ + if( majorStatus != GSS_S_COMPLETE ) + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_inquire_cred" ); + goto error; + } + + /* Convert internal name into text format */ + majorStatus = gss_display_name( &minorStatus, gssName, &name, NULL ); + if( majorStatus != GSS_S_COMPLETE ) + { + if( majorStatus == GSS_S_BAD_NAME ) + { + rc = DB2SEC_PLUGIN_BADUSER; + } + else + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_display_name"); + goto error; + } + + /* Don't use complete principal name as the user name. + * + * */ + *useridLen = (name.length < DB2SEC_MAX_USERID_LENGTH) ? + name.length : DB2SEC_MAX_USERID_LENGTH; + memcpy( userid, name.value, *useridLen ); + + for ( x = 0; x < *useridLen; x++ ) + { + if ( userid[x] == '/' || userid[x] == '@' ) + { + userid[x] = '\0'; + *useridLen = x ; + break; + } + } + + /* If the logged on userid contains any uppercase characters, + then the userid is automatically considered bad. This is because + all userids on UNIX/Linux are assumed to be completely in lowercase + or else it is impossible to uniquely map an AUTHID back to a userid + as is required for group lookups. + */ + for( x = 0; x < *useridLen; x++ ) + { + if( userid[x] >= 'A' && userid[x] <= 'Z' ) + { + rc = DB2SEC_PLUGIN_BADUSER; + goto error; + } + } + + rc = mapPrincToAuthid( &name, authid, pAuthIdLen ); + if( rc != DB2SEC_PLUGIN_OK ) + { + goto error; + } + + exit: + if( gssName != GSS_C_NO_NAME ) + { + majorStatus = gss_release_name( &minorStatus, &gssName ); + if( majorStatus != GSS_S_COMPLETE ) + { + if( *pErrorMsgLen == 0 ) + { + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_name"); + } + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + } + + if( name.length > 0 ) + { + majorStatus = gss_release_buffer( &minorStatus, &name ); + if( majorStatus != GSS_S_COMPLETE ) + { + if( *pErrorMsgLen == 0 && rc == DB2SEC_PLUGIN_OK ) + { + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_buffer"); + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + } + } + + if( credHandle != GSS_C_NO_CREDENTIAL ) + { + majorStatus = gss_release_cred( &minorStatus, &credHandle ); + if( majorStatus != GSS_S_COMPLETE ) + { + if( *pErrorMsgLen == 0 && rc == DB2SEC_PLUGIN_OK ) + { + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_cred"); + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + } + } + return( rc ); + + error: + + goto exit; +} + + +/****************************************************************************** +* +* Function Name = db2secGenerateInitialCred +* +* Descriptive Name = Generate the intial credentials based on the provided +* username/password pair and return the GSS-API +* credentials handle. +* +* Function = +* +* Dependencies = None +* +* Restrictions = - A forwardable TGT will always be requested +* - No change password functionality provided +* - If a REALM is specified with the username, then it will +* be included in the userid buffer and not parsed into +* the userNamespace field +* - Certain krb5 objects must be created and exist for the +* GSS-API cred handle to be valid. To make sure that +* these krb5 objects are cleaned up properly, their +* handles will be stored in a structure pointed to by +* pInitInfo so that they may be freed during +* db2secFreeInitInfo(). +* +* Input = userid - User name +* useridLen - Length of User name +* userNamespace - (unused) +* userNamespaceLen - (not used) +* userNamespaceType - (not used) +* password - User's password +* passwordLen - Password string length +* newPassword - (not used) +* newPasswordLen - (not used) +* dbName - (not used) +* dbnameLen - (not used) +* +* Output = pGSSCredHandle - Pointer to the GSS-API cred handle +* ppInitInfo - Pointer to a buffer allocated by the +* function to keep track of krb5 objects +* allocated to create the GSS-API cred handle +* ppErrorMsg - Pointer to a string that will contain +* an error message +* errorMsgLen - Pointer to the length of the error message +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = DB2SEC_PLUGIN_CHANGEPASSWORD_NOTSUPPORTED +* DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS +* DB2SEC_PLUGIN_UNKNOWNERROR +* DB2SEC_PLUGIN_BADPWD +* DB2SEC_PLUGIN_BADUSER +* DB2SEC_PLUGIN_PWD_EXPIRED +* DB2SEC_PLUGIN_UID_EXPIRED +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secGenerateInitialCred( const char *userid, + db2int32 useridLen, + const char *userNamespace, + db2int32 userNamespaceLen, + db2int32 userNamespaceType, + const char *password, + db2int32 passwordLen, + const char *newPassword, + db2int32 newPasswordLen, + const char *dbName, + db2int32 dbNameLen, + gss_cred_id_t *pGSSCredHandle, + void **ppInitInfo, + char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + SQL_API_RC rc = DB2SEC_PLUGIN_OK; + OM_uint32 majorStatus=GSS_S_COMPLETE; + OM_uint32 minorStatus; + + int x = 0; + +#if defined NAS_SUPPORT || defined MIT_KERBEROS_SUPPORT + + krb5_data tgtname={ 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; + krb5_context kContext=NULL; + krb5_error_code kStatus=0; + krb5_principal userPrinc=NULL; + krb5_principal server=NULL; + krb5_creds kCreds; + krb5_ccache cCache=NULL; + char cacheName[80]; + char nameSeed[40]; // 10 (seconds) + 7 (useconds) + 19 (address) + krb5_int32 seconds; + krb5_int32 useconds; + int retryGrabTGT = 0; + krb5_get_init_creds_opt options; + const char* cache_old_name = NULL; + +#elif defined SOLARIS_KERBEROS_SUPPORT + + gss_name_t userGSSName; + gss_buffer_desc usernameBufferDesc = {0}; + gss_buffer_desc passwordBufferDesc = {0}; + +#endif + + *ppErrorMsg = NULL; + *pErrorMsgLen = 0; + + if( newPasswordLen > 0 ) + { + rc = DB2SEC_PLUGIN_CHANGEPASSWORD_NOTSUPPORTED; + goto exit; + } + + if( !pGSSCredHandle ) + { + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto exit; + } + + /* If the logged on userid contains any uppercase characters, + then the userid is automatically considered bad. This is because + all userids on UNIX/Linux are assumed to be completely in lowercase + or else it is impossible to uniquely map an AUTHID back to a userid + as is required for group lookups. + */ + for( x = 0; x < useridLen; x++ ) + { + if ( userid[x] == '/' || userid[x] == '@' ) + { + break; + } + + if( userid[x] >= 'A' && userid[x] <= 'Z' ) + { + rc = DB2SEC_PLUGIN_BADUSER; + goto error; + } + } + +#if defined SOLARIS_KERBEROS_SUPPORT + passwordBufferDesc.value = (void *)password; + passwordBufferDesc.length = (size_t)passwordLen; + + usernameBufferDesc.value = (void*)userid; + usernameBufferDesc.length = (size_t)useridLen; + + + majorStatus = gss_import_name( &minorStatus, + &usernameBufferDesc, + GSS_C_NT_USER_NAME, + &userGSSName ); + + if( majorStatus != GSS_S_COMPLETE ) + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_import_name"); + goto error; + } + + majorStatus = gss_acquire_cred_with_password( &minorStatus, + userGSSName, + &passwordBufferDesc, + 0, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + pGSSCredHandle, + NULL, // actual_mechs + NULL ); // time_rec + + + if( majorStatus != GSS_S_COMPLETE ) + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_acquire_cred_with_password"); + goto error; + } + +#elif defined NAS_SUPPORT || defined MIT_KERBEROS_SUPPORT + + /* Create a new krb5 context */ + kStatus = krb5_init_context( &kContext ); + if( kStatus ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, "krb5_init_context" ); + goto error; + } + + /* Create principal name + * + * Note: userid must be in name@REALM format; if no realm is specified, the + * krb5_parse_name API will assume the default realm. + */ + kStatus = krb5_parse_name( kContext, userid, &userPrinc ); + if( kStatus) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, "krb5_parse_name" ); + goto error; + } + + /* Initialise krb5 cred structure */ + memset( (char *)&kCreds, 0, sizeof(kCreds) ); + + kCreds.client = userPrinc; + + /* Build the actual krb5 principal */ + kStatus = krb5_build_principal_ext( + kContext, + &server, + krb5_princ_realm( kContext, userPrinc )->length, + krb5_princ_realm( kContext, userPrinc )->data, + tgtname.length, + tgtname.data, + krb5_princ_realm( kContext, userPrinc )->length, + krb5_princ_realm( kContext, userPrinc )->data, + 0 ); + if( kStatus ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, + "krb5_build_principal_ext" ); + goto error; + } + + /* Create a new credential cache in memory. The cache name must be distinct + * from any other that exist. The composition of the cache name will be: + * CLIENT PRINCIPAL NAME + TIMESTAMP + ADDRESS OF GSS CRED HANDLE + */ + kStatus = krb5_us_timeofday( kContext, &seconds, &useconds ); + if( kStatus) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, "krb5_us_timeofday" ); + goto error; + } + snprintf( nameSeed, sizeof(nameSeed), "%d%d%p", + seconds, useconds, (void *)pGSSCredHandle ); + snprintf( cacheName, sizeof(cacheName), "MEMORY:%s%s", userid, nameSeed ); + + kStatus = krb5_cc_resolve( kContext, cacheName, &cCache ); + if( kStatus ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, "krb5_cc_resolve" ); + goto error; + } + + /* Initalise the new cred cache */ + kStatus = krb5_cc_initialize( kContext, cCache, kCreds.client ); + if( kStatus ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, "krb5_cc_initialize" ); + goto error; + } + + kCreds.server = server; + /* Use default lifetime */ + kCreds.times.starttime = 0; + kCreds.times.endtime = 0; + + grabTGT: + + + krb5_get_init_creds_opt_init(&options); + krb5_get_init_creds_opt_set_forwardable (&options, 1); + + /* Use the password to grab a forwardable TGT */ + + kStatus = krb5_get_init_creds_password( kContext, &kCreds, kCreds.client, (char*)password, + NULL , + NULL , + 0 , + 0 , + &options ); + + + if( kStatus ) + { + + /* Complete krb5 error listing in krb5krb.h */ + switch( kStatus ) + { + case KRB5KDC_ERR_PREAUTH_FAILED: + case KRB5KRB_AP_ERR_BAD_INTEGRITY: + rc = DB2SEC_PLUGIN_BADPWD; + break; + case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: + /* In addition to a bad user, this error occurs if the user exists but + * the KRB5_DISALLOW_ALL_TIX flag is set for the principal */ + rc = DB2SEC_PLUGIN_BADUSER; + break; + case KRB5KDC_ERR_KEY_EXP: + /* Both normal password expiry and admin forced expiry */ + rc = DB2SEC_PLUGIN_PWD_EXPIRED; + break; + case KRB5KDC_ERR_NAME_EXP: + rc = DB2SEC_PLUGIN_UID_EXPIRED; + break; + case KRB5KDC_ERR_POLICY: + /* Likely, local policies prohibit this user from requesting forwardable + * tickets. In this case try grabbing the ticket one more time without + * the forwardable flag + */ + if( !retryGrabTGT ) + { + retryGrabTGT = 1; + goto grabTGT; + } + /* else fall into default: case */ + default: + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + break; + } + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, + "krb5_get_init_creds_password" ); + goto error; + } + + +#ifdef MIT_KERBEROS_SUPPORT + + /* set the new credentials cache name */ + + kStatus = gss_krb5_ccache_name(&minorStatus, cacheName, &cache_old_name); // The data allocated for cache_old_name is free upon next call to gss_krb5_ccache_name(). + + if( kStatus ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getGSSErrorMsg( kStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_krb5_ccache_name"); + goto error; + } + + /* place in the new cred cache */ + + kStatus = krb5_cc_store_cred(kContext, cCache, &kCreds); + + if( kStatus ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, "krb5_cc_store_cred" ); + goto error; + } + + kStatus = gss_acquire_cred( &minorStatus, + GSS_C_NO_NAME, + 0, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + pGSSCredHandle, + NULL, + NULL ); + if( kStatus != GSS_S_COMPLETE ) + { + rc = DB2SEC_PLUGIN_NO_CRED; + getGSSErrorMsg( kStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_acquire_cred"); + goto error; + } + + /* set the original credentials cache name back */ + + kStatus = gss_krb5_ccache_name(&minorStatus, cache_old_name, NULL); + + if( kStatus != GSS_S_COMPLETE ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getGSSErrorMsg( kStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_krb5_ccache_name"); + goto error; + } + +#else + + /* place in the new cred cache */ + + kStatus = krb5_cc_store_cred(kContext, cCache, &kCreds); + + if( kStatus ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, "krb5_cc_store_cred" ); + goto error; + } + + /* + * Acquire a GSS-API credential handle + * + * The following API is only available with IBM NAS. It is able convert a krb5 + * cred cache handle into a GSS-API cred handle very nicely. Notice that + * there is no need to resort to placing the credentials in the default + * cred cache. + */ + + majorStatus = gss_krb5_acquire_cred_ccache( &minorStatus, + cCache, + 0, /* use default lifetime */ + GSS_C_INITIATE, + pGSSCredHandle, + NULL); /* Cred time returned */ + if( majorStatus != GSS_S_COMPLETE ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_krb5_acquire_cred_ccache"); + goto error; + } +#endif + + /* Save the krb5 context so that they can be cleaned up properly after + * authentication is complete. Note, the krb5 cred cache does not need to + * be stored and freed later. This is because it is a memory cache and + * the call to gss_release_cred() will implicitly free it. + */ + *ppInitInfo = (void *) kContext; + + /* no longer need principal objects */ + if ( userPrinc ) + { + krb5_free_principal(kContext, userPrinc); + } + if ( server ) + { + krb5_free_principal(kContext, server); + } + +#endif // defined NAS_SUPORT || defined MIT_KERBEROS_SUPPORT + +#if defined SOLARIS_KERBEROS_SUPPORT + if( userGSSName != GSS_C_NO_NAME ) + { + majorStatus = gss_release_name( &minorStatus, &userGSSName ); + if( majorStatus != GSS_S_COMPLETE ) + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_name"); + goto error; + } + } +#endif + + +exit: + + return( rc ); + +error: + +#if defined NAS_SUPPORT || defined MIT_KERBEROS_SUPPORT + if( kContext ) + { + if (cCache) + { + krb5_cc_destroy(kContext, cCache); /* destroy cred cache */ + } + if ( userPrinc ) + { + krb5_free_principal(kContext, userPrinc ); + } + if ( server ) + { + krb5_free_principal(kContext, server); + } + krb5_free_context( kContext ); /* destroy context */ + } +#endif + +#if defined SOLARIS_KERBEROS_SUPPORT + if( userGSSName != GSS_C_NO_NAME ) + { + gss_release_name( &minorStatus, &userGSSName ); + } +#endif + + if( pGSSCredHandle ) + { + gss_release_cred( &minorStatus, pGSSCredHandle ); + } + + goto exit; + +} + +/****************************************************************************** +* +* Function Name = db2secProcessServerPrincipalName +* +* Descriptive Name = +* +* Function = Convert text service principal name into the GSS-API +* internal format for use with the other APIs +* +* Dependencies = Client-side routine only. +* DB2 will call gss_release_name at the appropriate time +* to clean up the gss_name_t structure +* +* Restrictions = +* +* Input = name - Text service principal name string pointer +* nameLen - Text string length +* +* Output = gssName - Internal GSS-API name structure +* ppErrorMsg - Pointer to a string that will contain +* an error message +* errorMsgLen - Pointer to the length of the error message +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = DB2SEC_PLUGIN_BAD_PRINCIPAL_NAME +* DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secProcessServerPrincipalName( const char *name, + db2int32 nameLen, + gss_name_t *gssName, + char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + gss_buffer_desc nameBuff; + OM_uint32 majorStatus=GSS_S_COMPLETE; + OM_uint32 minorStatus; + SQL_API_RC rc = DB2SEC_PLUGIN_OK; + + *ppErrorMsg = NULL; + *pErrorMsgLen = 0; + + if( gssName == NULL ) + { + rc = DB2SEC_PLUGIN_BAD_INPUT_PARAMETERS; + goto error; + } + + if( nameLen > 0 ) + { + /* + * DRDA stipulates that the Kerberos principal name be sent in the + * GSS_C_NT_USER_NAME format, e.g., name/host@REALM + */ + nameBuff.value = (void *) name; + nameBuff.length = (OM_uint32 ) nameLen; + + majorStatus = gss_import_name( &minorStatus, + &nameBuff, + GSS_C_NT_USER_NAME, + gssName ); + if( majorStatus != GSS_S_COMPLETE ) + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_import_name"); + goto error; + } + } + + exit: + + return( rc ); + + error: + + goto exit; + +} + +/****************************************************************************** +* +* Function Name = db2secFreeInitInfo +* +* Descriptive Name = Free krb5 objects allocated in db2secGenerateInitialCred +* +* Function = Free the krb5 context created in +* db2secGenerateInitialCred. +* +* Dependencies = None +* +* Restrictions = None +* +* Input = initInfo - Pointer to any krb5 objects allocated by +* db2secGenerateInitialCred +* +* Output = ppErrorMsg - Pointer to a string that will contain +* an error message +* errorMsgLen - Pointer to the length of the error message +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = None +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secFreeInitInfo( void *initInfo, + char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + if( initInfo ) + { + krb5_free_context( (krb5_context) initInfo ); + } + + return( DB2SEC_PLUGIN_OK ); +} + + +/****************************************************************************** +* +* Function Name = plugin_gss_init_sec_context +* +* Descriptive Name = +* +* Function = This wrapper function needs to exist since the NAS +* libraries implemented this function with a slightly +* different prototype than outlined in IETF RFC2744 +* +* Dependencies = None +* +* Restrictions = None +* +* Input = +* +* Output = +* +* Normal Return = GSS_S_COMPLETE +* +* Error Return = Various GSS-API errors returned by gss_init_sec_context +* +*******************************************************************************/ +OM_uint32 SQL_API_FN plugin_gss_init_sec_context( + OM_uint32 *minor_status, + const gss_cred_id_t cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec ) +{ + OM_uint32 majorStatus = GSS_S_COMPLETE; + OM_uint32 major = GSS_S_COMPLETE; + OM_uint32 minor = GSS_S_COMPLETE; + + gss_cred_id_t credHandle = GSS_C_NO_CREDENTIAL; + + /* There is a bug in the NAS code where if the cred_handle is set to + * GSS_C_NO_CREDENTIAL, NAS has a difficult time retreiving the correct + * credential handle if the application has kinit, kdestroy, and then kinit + * as another principal while the application is still up. The workaround is + * to explicitly grab the credential handle for the default login context and + * pass it in to the problematic function + */ + + if( cred_handle == GSS_C_NO_CREDENTIAL ) + { + majorStatus = gss_acquire_cred( minor_status, + GSS_C_NO_NAME, + 0, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + &credHandle, + NULL, + NULL ); + if( majorStatus != GSS_S_COMPLETE ) + { + goto error; + } + } + else + { + credHandle = cred_handle; + } + + majorStatus = gss_init_sec_context( + minor_status, + (gss_cred_id_t) credHandle, + context_handle, + (gss_name_t) target_name, + (gss_OID) mech_type, + req_flags, + time_req, + (gss_channel_bindings_t) input_chan_bindings, + (gss_buffer_t) input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec ); + + exit: + + if( cred_handle == GSS_C_NO_CREDENTIAL ) + { + major = gss_release_cred( &minor, &credHandle ); + if( major != GSS_S_COMPLETE && majorStatus == GSS_S_COMPLETE) + { + majorStatus = major; + *minor_status = minor; + } + } + + return( majorStatus ); + + error: + + goto exit; +} + +/****************************************************************************** +* +* Function Name = db2secClientAuthPluginTerm +* +* Descriptive Name = +* +* Function = Client plugin clean-up code called during termination +* of the client-side plugin. Since nothing is required +* to be cleaned up on the client side, this funciton is +* a no-op. +* +* Dependencies = None +* +* Restrictions = None +* +* Input = None +* +* Output = ppErrorMsg - (not used) +* pErrorMsgLen - (not used) +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = None +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secClientAuthPluginTerm( char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + /* Nothing to do */ + return( DB2SEC_PLUGIN_OK ); +} + +/****************************************************************************** +* +* Function Name = db2secClientAuthPluginInit +* +* Descriptive Name = Initialization routine for client plugin startup +* +* Function = +* +* Dependencies = +* +* Restrictions = This function must use C-linkage +* +* Input = version - The plug-in API version supported by DB2 +* logMessage_fn - Function pointer to allow plugin to +* log a message into the db2diag.log +* +* Output = pFunctions - Function pointer structure populated with +* client-side functions +* ppErrorMsg - Pointer to a string that will contain +* an error message +* errorMsgLen - Pointer to the length of the error message +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = DB2SEC_PLUGIN_INCOMPATIBLE_VER +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secClientAuthPluginInit( + db2int32 version, + void *pFunctions, + db2secLogMessage *logMessage_fn, + char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + SQL_API_RC rc = DB2SEC_PLUGIN_OK; + db2secGssapiClientAuthFunctions_1 *pFPs; + + *ppErrorMsg = NULL; + *pErrorMsgLen = 0; + + if( version < DB2SEC_GSSAPI_CLIENT_AUTH_FUNCTIONS_VERSION_1 ) + { + rc = DB2SEC_PLUGIN_INCOMPATIBLE_VER; + goto exit; + } + + pClientLogMessage = logMessage_fn; + + pFPs = (db2secGssapiClientAuthFunctions_1 *) pFunctions; + pFPs->plugintype = DB2SEC_PLUGIN_TYPE_KERBEROS; + pFPs->version = DB2SEC_GSSAPI_CLIENT_AUTH_FUNCTIONS_VERSION_1; + + /* Set up function pointers */ + pFPs->db2secGetDefaultLoginContext = db2secGetDefaultLoginContext; + pFPs->db2secGenerateInitialCred = db2secGenerateInitialCred; + pFPs->db2secProcessServerPrincipalName = db2secProcessServerPrincipalName; + pFPs->db2secFreeToken = db2secFreeToken; + pFPs->db2secFreeErrormsg = db2secFreeErrormsg; + pFPs->db2secFreeInitInfo = db2secFreeInitInfo; + pFPs->db2secClientAuthPluginTerm = db2secClientAuthPluginTerm; + pFPs->gss_init_sec_context = plugin_gss_init_sec_context; + pFPs->gss_delete_sec_context = gss_delete_sec_context; + pFPs->gss_display_status = plugin_gss_display_status; + pFPs->gss_release_buffer = gss_release_buffer; + pFPs->gss_release_cred = gss_release_cred; + pFPs->gss_release_name = gss_release_name; + + exit: + + return( rc ); +} + + +/* + * SERVER FUNCTIONS + */ + +/****************************************************************************** +* +* Function Name = db2secGetAuthIDs +* +* Descriptive Name = +* +* Function = +* +* Dependencies = At this point, the GSS-API context is assumed to have +* been established and the context handle is passed in +* as the token +* +* Restrictions = Server-side routine only +* The token is assumed to be the GSS-API context handle +* +* Input = userid (not used) +* userNameSpace (not used) +* dbName (not used) +* token - GSS-API context handle +* +* Output = systemAuthID / systemAuthIDLen, +* initialSessionAuthID / initialSessionAuthIDLen, +* userName / userNameLen +* initSessionIDType (not used) +* ppErrorMsg - Pointer to a string that will contain +* an error message +* errorMsgLen - Pointer to the length of the error message +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secGetAuthIDs( + const char *userid, + db2int32 useridLen, + const char *userNameSpace, + db2int32 userNameSpaceLen, + db2int32 userNameSpaceType, + const char *dbName, + db2int32 dbNameLen, + void **ppToken, + char systemAuthID[DB2SEC_MAX_AUTHID_LENGTH], + db2int32 *systemAuthIDLen, + char initialSessionAuthID[DB2SEC_MAX_AUTHID_LENGTH], + db2int32 *initialSessionAuthIDLen, + char userName[DB2SEC_MAX_USERID_LENGTH], + db2int32 *userNameLen, + db2int32 *initSessionIDType, + char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + SQL_API_RC rc = DB2SEC_PLUGIN_OK; + OM_uint32 majorStatus = GSS_S_COMPLETE; + OM_uint32 minorStatus; + gss_ctx_id_t ctxHandle; + gss_name_t srcName = GSS_C_NO_NAME; + gss_buffer_desc textName = GSS_C_EMPTY_BUFFER; + + *ppErrorMsg = NULL; + *pErrorMsgLen = 0; + + // If a userid was provided, we've been asked to do userid only + int useridOnlyValidation = (useridLen > 0); + + if (useridOnlyValidation) + { + textName.length = useridLen; + textName.value = (void * )userid; + } + else + { + ctxHandle = (gss_ctx_id_t) (*ppToken); + + majorStatus = gss_inquire_context( &minorStatus, + ctxHandle, + &srcName, + NULL, /* target name */ + NULL, /* cred lifetime */ + NULL, /* mech type */ + NULL, /* flags */ + NULL, /* local context */ + NULL ); /* ctx establishment complete */ + if( majorStatus != GSS_S_COMPLETE ) + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_inquire_context" ); + goto error; + } + + /* Obtain textual representation of the internal name */ + majorStatus = gss_display_name( &minorStatus, + srcName, + &textName, + NULL ); /* name type */ + if( majorStatus != GSS_S_COMPLETE ) + { + if( majorStatus == GSS_S_BAD_NAME ) + { + rc = DB2SEC_PLUGIN_BADUSER; + } + else + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + /* Obtain descriptive text message */ + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_display_name" ); + goto error; + } + } + + /* Use the complete principal name as the user name. + * + * Truncation is okay since the reported username is only informational */ + *userNameLen = (textName.length < DB2SEC_MAX_USERID_LENGTH) ? + textName.length : DB2SEC_MAX_USERID_LENGTH; + memcpy( userName, textName.value, *userNameLen ); + + rc = mapPrincToAuthid( &textName, systemAuthID, systemAuthIDLen ); + if( rc != DB2SEC_PLUGIN_OK ) + { + goto error; + } + + /* Set the initial session authid to be the same as the system authid */ + memcpy( initialSessionAuthID, systemAuthID, *systemAuthIDLen ); + *initialSessionAuthIDLen = *systemAuthIDLen; + + exit: + + if( srcName != GSS_C_NO_NAME ) + { + majorStatus = gss_release_name( &minorStatus, &srcName ); + if( majorStatus != GSS_S_COMPLETE ) + { + if( rc == DB2SEC_PLUGIN_OK && *pErrorMsgLen == 0 ) + { + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_name" ); + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + } + } + + if ( ( textName.length > 0 ) && (!useridOnlyValidation) ) + { + majorStatus = gss_release_buffer( &minorStatus, &textName ); + if( majorStatus != GSS_S_COMPLETE ) + { + if( rc == DB2SEC_PLUGIN_OK && *pErrorMsgLen == 0 ) + { + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_buffer" ); + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + } + } + + return( rc ); + + error: + + goto exit; +} + +/****************************************************************************** +* +* Function Name = db2secDoesAuthIDExist +* +* Descriptive Name = Informs DB2 whether the provided AUTHID corresponds to +* an existing Kerberos principal +* +* Function = There is no way to determine if a particular principal +* exists using GSS-API so this function will always +* return DB2SEC_PLUGIN_USERSTATUSNOTKNOWN +* +* Dependencies = None +* +* Restrictions = +* +* Input = authid - DB2 AUTHID +* authidLen - Length of AUTHID string +* +* Output = ppErrorMsg - Pointer to a string that will contain +* an error message +* errorMsgLen - Pointer to the length of the error message +* +* Normal Return = DB2SEC_PLUGIN_USERSTATUSNOTKNOWN +* +* Error Return = None +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secDoesAuthIDExist( const char *authid, + db2int32 authidLen, + char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + /* This is not possible through GSS-API so for now always return + * DB2SEC_PLUGIN_USERSTATUSNOTKNOWN. + */ + + return( DB2SEC_PLUGIN_USERSTATUSNOTKNOWN ); +} + +/****************************************************************************** +* +* Function Name = plugin_gss_accept_sec_context +* +* Descriptive Name = +* +* Function = This wrapper function needs to exist since the NAS +* libraries implemented this function with a slightly +* different prototype than outlined in IETF RFC2744 +* +* Dependencies = None +* +* Restrictions = None +* +* Input = +* +* Output = +* +* Normal Return = GSS_S_COMPLETE +* +* Error Return = Various GSS-API status codes from gss_accept_sec_context +* +*******************************************************************************/ +OM_uint32 SQL_API_FN plugin_gss_accept_sec_context( + OM_uint32 *minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle ) +{ + OM_uint32 majorStatus; + + majorStatus = gss_accept_sec_context( + minor_status, + context_handle, + (gss_cred_id_t) acceptor_cred_handle, + (gss_buffer_t) input_token, + (gss_channel_bindings_t) input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle ); + + return( majorStatus ); +} + +/****************************************************************************** +* +* Function Name = db2secServerAuthPluginTerm +* +* Descriptive Name = Server plugin termination routine +* +* Function = Clean up memory allocated at plugin init time and also +* reset all the global variables as DB2 may call the +* db2secServerAuthPluginInit function right after this call +* +* Dependencies = None +* +* Restrictions = None +* +* Input = None +* +* Output = ppErrorMsg - Pointer to a string that will contain +* an error message +* errorMsgLen - Pointer to the length of the error message +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = None +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secServerAuthPluginTerm( char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + SQL_API_RC rc = DB2SEC_PLUGIN_OK; + OM_uint32 majorStatus; + OM_uint32 minorStatus; + + *ppErrorMsg = NULL; + *pErrorMsgLen = 0; + + if( pluginServerPrincipalName ) + { + free( pluginServerPrincipalName ); + pluginServerPrincipalName = NULL; + } + + if( pluginServerName ) + { + majorStatus = gss_release_name( &minorStatus, &pluginServerName ); + if( majorStatus!= GSS_S_COMPLETE ) + { + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_name" ); + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + } + + if( pluginServerCredHandle ) + { + majorStatus = gss_release_cred( &minorStatus, &pluginServerCredHandle ); + if( majorStatus != GSS_S_COMPLETE ) + { + /* Don't want to overwrite previous message if there is one */ + if( rc == DB2SEC_PLUGIN_OK && *pErrorMsgLen == 0 ) + { + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_cred" ); + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + } + } + + return( rc ); +} + +/****************************************************************************** +* +* Function Name = db2secServerAuthPluginInit +* +* Descriptive Name = Initialize server-side plugin support +* +* Function = Obtain all initial information required by the server +* plugin and populate the function pointer structure +* +* Dependencies = None +* +* Restrictions = This function must use C linkage +* +* Input = version - The plug-in API version supported by DB2 +* db2secGetConDetailsFP - Function pointer to a DB2 +* function that will return the +* connection details +* logMessage_fn - Function pointer to allow plugin to +* log a message into the db2diag.log +* +* Output = functions - Function pointer structure populated with +* server-side functions +* ppErrorMsg - Pointer to a string that will contain +* an error message +* errorMsgLen - Pointer to the length of the error message +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = DB2SEC_PLUGIN_INCOMPATIBLE_VER +* +*******************************************************************************/ +SQL_API_RC SQL_API_FN db2secServerAuthPluginInit( + db2int32 version, + void *functions, + db2secGetConDetails *db2secGetConDetailsFP, + db2secLogMessage *logMessage_fn, + char **ppErrorMsg, + db2int32 *pErrorMsgLen ) +{ + SQL_API_RC rc = DB2SEC_PLUGIN_OK; + db2secGssapiServerAuthFunctions_1 *pFPs; + char *principalName; + OM_uint32 majorStatus; + OM_uint32 minorStatus; + char *instName = NULL; + char *envVar = NULL; + int length = 0; + krb5_context kContext = NULL; + krb5_error_code kStatus = 0; + krb5_principal kServer = NULL; + + if( ppErrorMsg ) + { + *ppErrorMsg = NULL; + *pErrorMsgLen = 0; + } + + if( version < DB2SEC_GSSAPI_SERVER_AUTH_FUNCTIONS_VERSION_1 ) + { + rc = DB2SEC_PLUGIN_INCOMPATIBLE_VER; + goto exit; + } + + pServerLogMessage = logMessage_fn; + + pFPs = (db2secGssapiServerAuthFunctions_1 *) functions; + pFPs->plugintype = DB2SEC_PLUGIN_TYPE_KERBEROS; + pFPs->version = DB2SEC_GSSAPI_SERVER_AUTH_FUNCTIONS_VERSION_1; + + /* Check if server plugin is being initialized without have previously been + * properly terminated. + * + * If any of the global server-side variables have been set, then it means + * that we're initializing the plugin again before terminating it first. + * DB2 expects the plugin to call the termination routine itself in this case + */ + if( pluginServerPrincipalName + || pluginServerName != GSS_C_NO_NAME + || pluginServerCredHandle != GSS_C_NO_CREDENTIAL ) + { + rc = db2secServerAuthPluginTerm( ppErrorMsg, pErrorMsgLen ); + if( rc != DB2SEC_PLUGIN_OK ) + { + goto error; + } + } + + /* + * Populate the server principal name + * + * If the environment variable DB2_KRB5_PRINCIPAL is set, then use it as it + * should contain the fully qualified service principal name. Otherwise, + * the principal name will be assumed to be + * /@ + */ + + envVar = getenv( "DB2_KRB5_PRINCIPAL" ); + if( envVar ) + { + length = strlen( envVar ); + principalName = (char *) malloc( length + 1 ); + if( !principalName ) + { + rc = DB2SEC_PLUGIN_NOMEM; + goto error; + } + memcpy( principalName, envVar, length + 1 ); + } + else + { + instName = getenv( "DB2INSTANCE" ); + if( !instName ) + { + *pErrorMsgLen = strlen( getenvError ) + 1; + *ppErrorMsg = (char *) malloc( *pErrorMsgLen ); + if( ppErrorMsg ) + { + snprintf( *ppErrorMsg, *pErrorMsgLen, getenvError ); + } + else /* At least write an error message into the db2diag.log */ + { + pServerLogMessage( DB2SEC_LOG_ERROR, (void *)getenvError, + *pErrorMsgLen ); + } + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto error; + } + + /* Create a new krb5 context */ + kStatus = krb5_init_context( &kContext ); + if( kStatus ) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, "krb5_init_context" ); + goto error; + } + + kStatus = krb5_sname_to_principal( kContext, + NULL, /* use local host */ + (const char *) instName, + KRB5_NT_SRV_HST, + &kServer ); + if( kStatus ) + { + rc = DB2SEC_PLUGIN_BAD_PRINCIPAL_NAME; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, + "krb5_sname_to_principal" ); + goto error; + } + + kStatus = krb5_unparse_name( kContext, kServer, &principalName ); + if( kStatus ) + { + rc = DB2SEC_PLUGIN_BAD_PRINCIPAL_NAME; + getKrb5ErrorMsg( kStatus, ppErrorMsg, pErrorMsgLen, "krb5_unparse_name" ); + goto error; + } + } + + pFPs->serverPrincipalName.value = principalName; + pFPs->serverPrincipalName.length = strlen( principalName ); + + /* log the service principal name as informational diagnostics */ + pServerLogMessage( DB2SEC_LOG_INFO, + (void *)"Kerberos service principal name:", + strlen( "Kerberos service principal name:" ) ); + pServerLogMessage( DB2SEC_LOG_INFO, + pFPs->serverPrincipalName.value, + pFPs->serverPrincipalName.length ); + + /* Copy to global var so that we can deallocate during termination */ + pluginServerPrincipalName = principalName; + + /* + * Fill in the server's cred handle + */ + majorStatus = gss_import_name( &minorStatus, + &(pFPs->serverPrincipalName), + GSS_C_NT_USER_NAME, + &pluginServerName ); + if( majorStatus != GSS_S_COMPLETE ) + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_import_name" ); + goto error; + } + + /* Note: Picking up environment variables that alter the default keytab + * location, e.g., KRB5_KTNAME, may not be possible in the plugin as we + * are running within a DB2 agent process + */ + majorStatus = gss_acquire_cred( &minorStatus, + pluginServerName, + 0, /* request default time */ + GSS_C_NO_OID_SET, + GSS_C_ACCEPT, + &(pFPs->serverCredHandle), + NULL, /* actual mech type */ + NULL ); /* actual cred time */ + if( majorStatus != GSS_S_COMPLETE ) + { + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_acquire_cred" ); + goto error; + } + + /* Copy to global var so that we can deallocate during termination */ + pluginServerCredHandle = pFPs->serverCredHandle; + + /* + * Set up function pointers + */ + pFPs->db2secGetAuthIDs = db2secGetAuthIDs; + pFPs->db2secDoesAuthIDExist = db2secDoesAuthIDExist; + pFPs->db2secFreeErrormsg = db2secFreeErrormsg; + pFPs->db2secServerAuthPluginTerm = db2secServerAuthPluginTerm; + pFPs->gss_accept_sec_context = plugin_gss_accept_sec_context; + pFPs->gss_display_name = gss_display_name; + pFPs->gss_delete_sec_context = gss_delete_sec_context; + pFPs->gss_display_status = plugin_gss_display_status; + pFPs->gss_release_buffer = gss_release_buffer; + pFPs->gss_release_cred = gss_release_cred; + pFPs->gss_release_name = gss_release_name; + + exit: + + if( kContext ) + { + if( kServer ) + { + krb5_free_principal( kContext, kServer ); + } + krb5_free_context( kContext ); + } + + return( rc ); + + error: + + /* Clean up any allocated memory */ + if( pluginServerPrincipalName ) + { + free( pluginServerPrincipalName ); + pluginServerPrincipalName = NULL; + } + + if( pluginServerName ) + { + majorStatus = gss_release_name( &minorStatus, &pluginServerName ); + /* Don't want to overwrite previous message if there is one */ + if( majorStatus != GSS_S_COMPLETE + && rc == DB2SEC_PLUGIN_OK && *pErrorMsgLen == 0) + { + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_name" ); + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + } + + if( pluginServerCredHandle ) + { + majorStatus = gss_release_cred( &minorStatus, &pluginServerCredHandle ); + /* Don't want to overwrite previous message if there is one */ + if( majorStatus != GSS_S_COMPLETE + && rc == DB2SEC_PLUGIN_OK && *pErrorMsgLen == 0) + { + getGSSErrorMsg( majorStatus, minorStatus, ppErrorMsg, pErrorMsgLen, + "gss_release_cred" ); + rc = mapGSSAPItoDB2SECerror( majorStatus, minorStatus ); + } + } + + pFPs->serverPrincipalName.value = NULL; + pFPs->serverPrincipalName.length = 0; + pFPs->serverCredHandle = GSS_C_NO_CREDENTIAL; + + goto exit; +} + +#ifdef __cplusplus +} +#endif diff --git a/security/plugins/README b/security/plugins/README new file mode 100644 index 0000000..af1ae09 --- /dev/null +++ b/security/plugins/README @@ -0,0 +1,80 @@ +***************************************************************************** +* +* README for Security Samples (all platforms) +* +* Last Update: May 2004 +* +* These sample security plugins are designed to provide a simple +* implementation that you can customize to meet the specific requirements +* of your installation. Security plugins can be used to replace the +* mechanisms that DB2 uses to authenticate users and obtain their +* group memberships. +* +* For information on developing security plugins, see the Application +* Development Guide. +* +* For the latest information on programming, compiling, and running DB2 +* applications (including security plugins), visit the DB2 application +* development website: +* http://www.software.ibm.com/data/db2/udb/ad +* +***************************************************************************** +* +* QUICKSTART +* +* - Copy sqllib/samples/security/plugins/* to a working directory. +* - Examine the "makefile" and "bldplugin" script and update any +* path information to reflect your specific installation. +* - Execute "make all" (or "nmake all" on Windows) to build the +* three supported samples ("combined", "group_file", and +* "gssapi_simple"). +* - Notes, usage information, and installation instructions are +* contained in the header of each "C" file. +* +***************************************************************************** +* +* Sample files: +* +* makefile +* Platform specific makefile for compiling the three basic samples. +* +* bldplugin (bldplugin.bat on Windows) +* Build script invoked from the makefile to handle compilation and +* linking. +* +* combined.c +* A single C file that implements both a simple userid/password +* based authentication mechanism plus a file based group membership +* lookup. Userids, passwords, and groups are all maintained in an +* instance specific text file. This sample would be suitable as a +* starting point for any userid/password based authentication scheme. +* This sample can be built using the makefile. +* +* group_file.c +* Implements a simple, file based group membership lookup. A user's +* group memberships are recorded in an instance specific text file. +* Similar to the group lookup portion of "combined.c". +* This sample can be built using the makefile. +* +* gssapi_simple.c +* A highly simplified implementation of a GSS-API authentication +* plugin. User credentials consist of an ASCII userid and password, +* which are validated against a simple text file on the server. +* This plugin is suitable as the basis for any GSS-API based +* authentication mechanism. +* This sample can be built using the makefile. +* +* IBMkrb5.c +* This file contains the source code for the IBM supplied Kerberos +* authentication plugin on UNIX. This code is designed to be used +* with the IBM Network Authentication Services (NAS) toolkit, though +* it should be possible to modify it to work with any other Kerberos +* toolkit (such as the base MIT Kerberos 5). +* +* While this plugin cannot be built using the makefile, it is +* supplied as an example of a "production ready" GSS-API based +* security plugin. Although specific to Kerberos, it would be +* an excellent starting point for any authentication scheme +* based on a pre-existing GSS-API toolkit. +* +***************************************************************************** diff --git a/security/plugins/bldplugin b/security/plugins/bldplugin new file mode 100644 index 0000000..7b1802c --- /dev/null +++ b/security/plugins/bldplugin @@ -0,0 +1,80 @@ +#! /bin/sh +############################################################################# +# Licensed Materials - Property of IBM +# +# Governed under the terms of the International +# License Agreement for Non-Warranted Sample Code. +# +# (C) COPYRIGHT International Business Machines Corp. 1995, 2006 +# All Rights Reserved. +# +# US Government Users Restricted Rights - Use, duplication or +# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +############################################################################# +# SCRIPT: bldplugin +# Builds Linux C security plugins +# Usage: bldplugin [ cc options ] +# +# NOTE: this script is intended to be invoked via makefile which will set +# the appropriate compilation flags for the USERFILE defines. + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# The program to compile is $1. Other parameters are passed to cc +prog=$1 +shift + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "HARDWAREPLAT" = "s390x" ] || [ "HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then +BITWIDTH=64 +else +# x86 is the only native 32-bit platform +BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + echo " DB2 does not support 32-bit applications on Linux on IA64" + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Compile the program. +gcc $EXTRA_C_FLAG -fpic -DDB2_PLAT_UNIX -I$DB2PATH/include $* \ + -c ${prog}.c -D_REENTRANT + +# Link the program and create a shared library +if [ $prog = "IBMkrb5" ] + then + if [ $BITWIDTH = "32" ] + then + gcc $EXTRA_C_FLAGS -shared -Bsymbolic -o ${prog}.so ${prog}.o -lc -L/usr/krb5/lib/ -lgssapi_krb5 -lkrb5 -lksvc + else + gcc $EXTRA_C_FLAGS -shared -Bsymbolic -o ${prog}.so ${prog}.o -lc -L/usr/krb5/lib/lib64 -lgssapi_krb5 -lkrb5 -lksvc + fi +else + gcc $EXTRA_C_FLAGS -shared -Bsymbolic -o ${prog}.so ${prog}.o -lc +fi + + diff --git a/security/plugins/combined.c b/security/plugins/combined.c new file mode 100644 index 0000000..3ce8127 --- /dev/null +++ b/security/plugins/combined.c @@ -0,0 +1,1355 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 2004 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: combined.c +** +** SAMPLE: Combined userid/password authentication and group lookup sample +** +** This single source files implements both the client and server pieces +** of a simple, file-based userid/password authentication scheme as well +** as file-based group management. +** +** When built, a single loadable object is created (see the makefile). +** However, because DB2 treats server-side authentication, client-side +** authentication and group management as separate plugins, the single +** loadable object must be copied into three different directories +** and the three related database manager configuration parameters +** updated accordingly. For example, on 32-bit UNIX platforms the +** loadable object should be copied into the following directories: +** .../sqllib/security32/plugin/server +** .../sqllib/security32/plugin/client +** .../sqllib/security32/plugin/group +** +** To enable the plugin the following DBM Configuration parameters must +** also be updated to the name of the loadable object, minus any extension +** (ie, to "combined"): +** SRVCON_PW_PLUGIN, CLNT_PW_PLUGIN, and GROUP_PLUGIN +** +***************************************************************************** +** +** For more information on developing DB2 security plugins, see the +** "Developing Security Plug-ins" section of the Application Development +** Guide. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "sqlenv.h" +#include "db2secPlugin.h" + +#if defined DB2_PLAT_UNIX +#include +#include +#if defined USE_CRYPT +#include +#endif +#include +#define USE_UNIX_UID_LOOKUP +#else +#define strcasecmp(a,b) stricmp(a,b) +#define snprintf _snprintf +#endif + +#if defined db2Is64bit || defined DB2_FORCE_INT32_TYPES_TO_INT + #define FMT_S32 "%d" +#else + #define FMT_S32 "%ld" +#endif + +db2secLogMessage *logFunc = NULL; +const char * getUserFileName() ; + +/* THE USER DEFINITION FILE + * Userid, password and group information is located in a single + * file defined by "USER_FILENAME". + * + * This file consists of one line per user with the following + * whitespace separated fields on each line: + * + * username password [ group1 [group2 ... ] ] + * + * The username and password are mandatory. Groups are optional. + * Lines that begin with "#" are comments. Blank lines are ignored. + * Note that usernames, passwords, and group names may not + * contain whitespace (this limitation is specific to this particular + * plugin implementation, not to DB2 in general). + * + * The passwords in this file are in clear text. For demonstration + * purposes, conditional code (USE_CRYPT) is available for non-cleartext + * authentication. Note that this does not imply that this authentication + * code is secure. For instance if the file is globally readable, this + * authentication mechanism will suffer from succeptability to + * password cracking and dictionary lookup methods. + * + * If USE_CRYPT is enabled, then the password is a standard unix crypt (3) + * based password. One can generate this for example with something like + * the following perl code: + * + * my $salt = join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64] ; + * my $cryptedText = crypt($clearText, $salt) ; + * + * The maximum line length for this file is 1024 characters; lines longer than + * this value will result in undefined behavior. User and group + * names are limited to SQL_AUTH_IDENT bytes, passwords are limited + * to DB2SEC_MAX_PASSWORD_LENGTH bytes. Lines containing longer + * fields will result in an error. + */ +#if 0 +/* + * Examples of the sorts of paths that could be used. These would + * normally be defined in the makefile instead of hardcoded. + */ +#if !defined WIN32 +#define USER_FILENAME "/home/db2inst1/sqllib/SamplePluginUsers" +#else +#define USER_FILENAME "D:\\sqllib\\DB2\\SamplePluginUsers" +#endif +#endif + +#if defined USER_FILENAME +const char * getUserFileName() +{ + return USER_FILENAME ; +} +#endif + +/* The internal max line length includes room for a line + * separator (CR/LF on Windows, LF on UNIX) and a NULL byte. + */ +#define MAX_LINE_LENGTH 1027 + +#define SQL_AUTH_IDENT 128 + + +/*------------------------------------------------------- + * Functions to read & parse the user definition file + *-------------------------------------------------------*/ + +/* + * NextField() + * Return a pointer to the next whitespace separated token in the input + * string. Skips over any leading whitespace. A NULL byte is written + * to the string after the token. + * + * The "nextString" output parameter can be used on the next call to + * this function to retrieve the next token, if any. + * + * Returns NULL if no more tokens exist in the input string. + * The orginal input string must be NULL terminated. + */ +char *NextField(char *inputString, char **nextString) +{ + char *returnString = NULL; + char *cptr; + + if (nextString != NULL) + { + *nextString = NULL; + } + + cptr = inputString; + + /* If the input string is NULL or zero length, return NULL. */ + if (cptr == NULL || *cptr == '\0') + { + goto exit; + } + + /* Skip any leading whitespace */ + while (*cptr == ' ' || *cptr == '\t') + { + cptr++; + } + + /* If we reach the end of the string return NULL. */ + if (*cptr == '\0') + { + goto exit; + } + + /* Found a non-whitespace, non-NULL character. This is the + * start of the string that we'll return. + */ + returnString = cptr; + + + /* Now we need to NULL terminate this token and set up nextString */ + cptr++; + while (*cptr != '\0') + { + if (*cptr == ' ' || *cptr == '\t') + { + /* Whitespace */ + *cptr = '\0'; /* NULL terminate */ + + if (nextString != NULL) + { + /* nextString starts with the character following + * the NULL byte we just inserted. + */ + *nextString = cptr + 1; + } + goto exit; /* We're done */ + } + cptr++; + } + + /* If we get here we've reached the end of the inputString. */ + if (nextString != NULL) + { + *nextString = NULL; + } + +exit: + return(returnString); +} /* NextField */ + + +/* GetNextLine() + * Returns a pointer to a string containing the next non-blank, + * non-comment line from the input file. A comment line is one + * where "#" is the first non-whitespace character. Leading + * whitespace is stripped from the returned string, as are trailing + * "\n" or "\r\n" sequences. + * + * "buf" and "bufLength" refer to a caller-supplied buffer used + * to hold the information read from the file. + * + * NULL is returned on EOF or error; the caller should use + * feof() and/or ferror() to determine which has occured. + * + * (char*)-1 is returned if an input line is encounted that doesn't + * fit into the supplied buffer. + */ +char *GetNextLine(FILE *fp, char *buf, int bufLength) +{ + char *returnPtr = NULL; + char *cptr; + int length; + + /* Loop until we find a valid line */ + while (returnPtr == NULL) { + + cptr = fgets(buf, bufLength - 1, fp); + if (cptr == NULL) + { + /* EOF or error, return NULL */ + goto exit; + } + + /* Strip trailing CR/NL bytes */ + length = strlen(cptr) - 1; + while (cptr[length] == '\n' || cptr[length] == '\r') + { + cptr[length] = '\0'; + length--; + } + + /* Skip over any leading whitespace */ + while (*cptr != '\0' && (*cptr == ' ' || *cptr == '\t')) + { + cptr++; + } + + /* If we didn't reach the end of the string and the first + * character is not '#', then return the line. Otherwise + * read the next line from the file. + */ + if (*cptr != '\0' && *cptr != '#') + { + returnPtr = cptr; + } + } + +exit: + return(returnPtr); +} + + +/* FindUser() + * Open the indicated file and find the first line where the first + * field matches the provided username. Optionally return the + * second field (password) and/or parse the remaining fields + * (groups) into a non-NULL terminated, length-prefixed sequence + * of strings (see below). + * + * The caller must supply a read buffer for use when processing + * the file. + * + * Leading and trailing whitesapce is stripped from the password + * and all group names. + * + * Returns: 0 for success, + * -1 if the user was not found + * -2 on error, *errorMessage will be set to a static C + * string describing the error. + * + * If groups are requested, the supplied group buffer must be at + * least as large as the supplied read buffer. The groups are + * written into that buffer in the following format: + * ... + * and *numGroups is set to indicate how many groups were written + * to the group buffer. Note that the group name strings are not + * NULL terminated. + */ +int FindUser(const char *fileName, /* File to read */ + const char *userName, /* Who we're looking for */ + char *readBuffer, /* Caller-supplied read buffer */ + int readBufferLength, + char **passwordPtr, /* Output: password */ + char *groupBuffer, /* Output: group list */ + int *numGroups, /* Output: number of groups */ + char **errorMessage) /* Static C string for errors */ +{ + int rc = -1; + int foundUser = 0; /* Found the user yet? */ + + int groupCount = 0; + int length; + char *linePtr; + char *field; + char *nextPtr; + char *cptr; + char *errMsg = NULL; /* Temp local error message */ + FILE *fp = NULL; + + if (userName == NULL) + { + errMsg = "NULL user name supplied"; + rc = -2; + goto exit; + } + + if (readBuffer == NULL) + { + errMsg = "NULL read buffer supplied"; + rc = -2; + goto exit; + } + + if (passwordPtr != NULL) + { + *passwordPtr = NULL; + } + + if (numGroups != NULL) + { + *numGroups = 0; + } + + + fp = fopen(fileName,"r"); + if (fp == NULL) { + errMsg = "Cannot open specified file\n"; + rc = -2; + goto exit; + } + + + while (foundUser == 0) + { + linePtr = GetNextLine(fp, readBuffer, readBufferLength); + if (linePtr == (char*)-1) + { + /* Line length error */ + errMsg = "Encountered an invalid input line in file"; + rc = -2; + goto exit; + } + if (linePtr == NULL) + { + /* We've probably reached the end of file, but make sure. */ + if (feof(fp)) + { + /* End of file: User not found. */ + rc = -1; + } + else + { + /* Not end of file, must have encountered an error. */ + rc = -2; + errMsg = "Unknown file error encountered"; + } + goto exit; + } + + field = NextField(linePtr, &nextPtr); + if (field != NULL && strcasecmp(field, userName) == 0) + { + /* Found the correct user name. Parse the line. */ + foundUser = 1; + + /* Second field is the password */ + field = NextField(nextPtr, &nextPtr); + + /* A blank password field is an error. */ + if (field == NULL) + { + errMsg = "No password for user"; + rc = -2; + goto exit; + } + if (passwordPtr != NULL) + { + *passwordPtr = field; + } + + /* If we were requested to return group information, + * parse the rest of the line. + */ + if (groupBuffer != NULL) + { + cptr = groupBuffer; + + field = NextField(nextPtr, &nextPtr); + while (field != NULL) + { + length = strlen(field); + + if (length > 255) + { + /* Since the group list is formatted using + * one byte lengths, a length of more than 255 + * bytes is an error. + */ + errMsg = "group name too long"; + rc = -2; + goto exit; + } + + *((unsigned char*)cptr) = (unsigned char)length; + cptr++; + + memcpy(cptr, field, length); + cptr += length; + + groupCount++; + + field = NextField(nextPtr, &nextPtr); + } + + /* Write a NULL byte after the last group; a + * "zero length group" indicates the end of the + * group list in case the caller did not supply + * "numGroups". + */ + *cptr = '\0'; + + if (numGroups != NULL) + { + *numGroups = groupCount; + } + } + + rc = 0; /* Found the user */ + } + } + +exit: + if (fp != NULL) + { + fclose(fp); + } + + if (errMsg != NULL) + { + char msg[256]; + snprintf(msg, 256, + "security plugin 'combined' encountered an error\n" + "User: %s\nFile: %s\nError: %s\n", + userName, fileName, errMsg); + msg[255]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + if (errorMessage != NULL) + { + *errorMessage = errMsg; + } + } + + return(rc); +} + + +/*------------------------------------------------------- + * Plugin functions + *-------------------------------------------------------*/ + +/* CheckPassword() + * Look up a user, check their password. + * + * If a domain name ("namespace") is specified it is appended to + * the userid with an "@" separator (userid@domain) and that string + * is then used for the file lookup. + * + * The maximum length for the userid (or userid@domain) is + * SQL_AUTH_IDENT, since it will be returned as the DB2 Authorization + * ID later. + */ +SQL_API_RC SQL_API_FN CheckPassword(const char *userid, + db2int32 useridLength, + const char *domain, + db2int32 domainLength, + db2int32 domainType, /* ignored */ + const char *password, + db2int32 passwordLength, + const char *newPassword, + db2int32 newPasswordLength, + const char *databaseName, /* not used */ + db2int32 databaseNameLength, /* not used */ + db2Uint32 connection_details, + void **token, /* not used */ + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + int length; + + char user[SQL_AUTH_IDENT + 1]; /* User name (possibly with @domain) */ + char lineBuf[MAX_LINE_LENGTH]; /* For reading from the U/P file. */ + char *passwordStringFromFile = NULL; + + char *cptr; + + *errorMessage = NULL; + *errorMessageLength = 0; + + memset(user, '\0', SQL_AUTH_IDENT + 1); + + /* Check for a domain name, and make sure the userid length is ok. */ + if (domain != NULL && domainLength > 0) + { + if ( (useridLength + 1 + domainLength) > SQL_AUTH_IDENT ) + { + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + strncpy(user, userid, useridLength); + strcat(user, "@"); + strncat(user, domain, domainLength); + } + else + { + if ( useridLength > SQL_AUTH_IDENT ) + { + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + strncpy(user, userid, useridLength); + } + + /* Was a new password supplied? */ + if (newPassword != NULL && newPasswordLength > 0) + { + rc = DB2SEC_PLUGIN_CHANGEPASSWORD_NOTSUPPORTED; + goto exit; + } + + + rc = FindUser(getUserFileName(), + user, /* User we're looking for */ + lineBuf, + sizeof(lineBuf), + &passwordStringFromFile, + NULL, /* Don't want group info */ + NULL, + errorMessage); + if (rc == -2) + { + /* Unexpected error. */ + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + else if (rc == -1) + { + /* User not found */ + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + + /* Check the password, if supplied. */ + if (password != NULL && passwordLength > 0) + { +#if defined USE_CRYPT + if (strlen(password) > 8) + { + /* Bad password. */ + rc = DB2SEC_PLUGIN_BADPWD; + } + else if (strlen(passwordStringFromFile) != 13) + { + /* Unexpected length for encrypted password in path specified by getUserFileName() (perhaps not encrypted). */ + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + } + else + { + char * recrypted = crypt(password, passwordStringFromFile); + + if (0 != strcmp(recrypted, passwordStringFromFile)) + { + rc = DB2SEC_PLUGIN_BADPWD; + } + } +#else + if ((strlen(passwordStringFromFile) != passwordLength) || + (strncmp(passwordStringFromFile, password, passwordLength) != 0)) + { + /* Bad password. */ + rc = DB2SEC_PLUGIN_BADPWD; + } +#endif + } + else + { + /* No password was supplied. This is okay as long + * as the following conditions are true: + * + * - The username came from WhoAmI(), and + * - If we're on the server side, the connection must + * be "local" (originating from the same machine) + * + * Note that "DB2SEC_USERID_FROM_OS" means that the userid + * was obtained from the plugin by calling the function + * supplied for "db2secGetDefaultLoginContext". + */ + if (!(connection_details & DB2SEC_USERID_FROM_OS) || + ((connection_details & DB2SEC_VALIDATING_ON_SERVER_SIDE) && + !(connection_details & DB2SEC_CONNECTION_ISLOCAL))) + { + /* Of of the conditions was not met, fail. */ + rc = DB2SEC_PLUGIN_BADPWD; + } + } + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + return(rc); +} + + +/* GetAuthIDs() + * Return the username (possibly with the domain name appended) to + * DB2 as both the System Authentication ID and the Initial Session + * Authorization ID. + */ +SQL_API_RC SQL_API_FN GetAuthIDs(const char *userid, + db2int32 useridLength, + const char *domain, + db2int32 domainLength, + db2int32 domainType, /* not used */ + const char *databaseName, /* not used */ + db2int32 databaseNameLength, /* not used */ + void **token, /* not used */ + char systemAuthID[], + db2int32 *systemAuthIDLength, + char sessionAuthID[], + db2int32 *sessionAuthIDLength, + char username[], + db2int32 *usernameLength, + db2int32 *sessionType, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + int length; + char user[SQL_AUTH_IDENT + 1]; /* User name (possibly with @domain) */ + + *errorMessage = NULL; + *errorMessageLength = 0; + + memset(user, '\0', sizeof(user)); + + /* Check for a domain name, and make sure the userid length is ok. */ + if (domain != NULL && domainLength > 0) + { + if ( (useridLength + 1 + domainLength) > SQL_AUTH_IDENT ) + { + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + strncpy(user, userid, useridLength); + strcat(user, "@"); + strncat(user, domain, domainLength); + } + else + { + if ( useridLength > SQL_AUTH_IDENT ) + { + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + strncpy(user, userid, useridLength); + } + + length = strlen(user); + + memcpy(systemAuthID, user, length); + *systemAuthIDLength = length; + memcpy(sessionAuthID, user, length); + *sessionAuthIDLength = length; + *sessionType = 0; /* TBD ?! */ + memcpy(username, user, length); + *usernameLength = length; + +exit: + return(rc); +} + + +/* DoesAuthIDExist() + * Determine if the supplied DB2 Authorization ID is associated with + * a valid user. + * + * Since this plugin derives the authorization ID directly from the + * username (possibly with the domain name appended), this function + * simply needs to determine if the given Auth ID exists in the User + * definition file. + */ +SQL_API_RC SQL_API_FN DoesAuthIDExist(const char *authID, + db2int32 authIDLength, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc; + char lineBuf[MAX_LINE_LENGTH]; + char localAuthID[SQL_AUTH_IDENT + 1]; + + *errorMessage = NULL; + *errorMessageLength = 0; + + /* NULL terminate the authID */ + if (authIDLength > SQL_AUTH_IDENT) + { + char msg[512]; + memcpy(localAuthID, authID, SQL_AUTH_IDENT); + localAuthID[SQL_AUTH_IDENT] = '\0'; + snprintf(msg, 512, + "DoesAuthIDExist: authID too long ("FMT_S32" bytes): %s... (truncated)", + authIDLength, localAuthID); + + msg[511]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + *errorMessage = "DoesAuthIDExist: authID too long"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + memcpy(localAuthID, authID, authIDLength); + localAuthID[authIDLength] = '\0'; + + + rc = FindUser(getUserFileName(), + localAuthID, /* User we're looking for */ + lineBuf, + sizeof(lineBuf), + NULL, /* Don't want the password */ + NULL, /* Don't want group info */ + NULL, + errorMessage); + if (rc == -2) + { + /* Unexpected error. */ + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + else if (rc == -1) + { + /* User not found */ + rc = DB2SEC_PLUGIN_INVALIDUSERORGROUP; + goto exit; + } + else + { + /* Found the user */ + rc = DB2SEC_PLUGIN_OK; + } + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + return(rc); +} + +#if defined USE_UNIX_UID_LOOKUP +static SQL_API_RC getUsername( + const uid_t uid, + char * const userName, + db2int32 * const userNameLength, + char ** errorMessage) +{ + int err ; + SQL_API_RC rc = 0 ; + struct passwd * pResult ; + struct passwd passwordData = { 0 } ; + size_t bufSize = sysconf(_SC_GETPW_R_SIZE_MAX) ; + char * buf = malloc(bufSize) ; +#if 0 + FILE * o = fopen("/tmp/auth", "a") ; +#endif + + if (!buf) + { + goto MALLOC_FAILED ; + } + + err = getpwuid_r( uid, + &passwordData, + buf, + bufSize, + &pResult ) ; + if (err) + { + goto GETPWUID_FAILED ; + } + + *userNameLength = strlen(pResult->pw_name) ; + + if (*userNameLength > SQL_AUTH_IDENT) + { + goto NAME_TOO_LONG ; + } + + strcpy(userName, pResult->pw_name) ; + free(buf) ; + +FINAL_EXIT: + +#if 0 + if (o) + { + fprintf(o, "uid: %d ; n: %s\n", uid, userName) ; + fclose(o) ; + } +#endif + + return 0 ; + +ERROR_EXIT: + + if (buf) + { + free(buf) ; + } + + rc = DB2SEC_PLUGIN_BADUSER ; + + goto FINAL_EXIT ; + +GETPWUID_FAILED: + *errorMessage = "getpwuid_r failed" ; + goto ERROR_EXIT ; + +NAME_TOO_LONG: + *errorMessage = "User name too long"; + goto ERROR_EXIT ; + +MALLOC_FAILED: + *errorMessage = "malloc failed" ; + goto ERROR_EXIT ; +} +#endif + +/* WhoAmI() + * Determine the default user identity associated with the current + * process context. + * + * For simplicity this plugin returns the string found in the + * DB2DEFAULTUSER environment variable, or an error if that variable + * is undefined. + */ +SQL_API_RC SQL_API_FN WhoAmI(char authID[], + db2int32 *authIDLength, + char userid[], + db2int32 *useridLength, + db2int32 useridType, /* ignored */ + char domain[], + db2int32 *domainLength, + db2int32 *domainType, + const char *databaseName, /* not used */ + db2int32 databaseNameLength, /* not used */ + void **token, /* not used */ + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + + *errorMessage = NULL; + *errorMessageLength = 0; + + authID[0] = '\0'; + *authIDLength = 0; + userid[0] = '\0'; + *useridLength = 0; + domain[0] = '\0'; + *domainLength = 0; + *domainType = DB2SEC_USER_NAMESPACE_UNDEFINED; + +#if defined USE_UNIX_UID_LOOKUP + if (DB2SEC_PLUGIN_REAL_USER_NAME == useridType) + { + rc = getUsername(getuid(), userid, useridLength, errorMessage); + if ( rc ) + { + goto exit; + } + } + else + { + rc = getUsername(geteuid(), userid, useridLength, errorMessage); + if ( rc ) + { + goto exit; + } + } + + strcpy(authID, userid); + *authIDLength = *useridLength; +#else + { + int length; + char *user; + + user = getenv("DB2DEFAULTUSER"); + + /* Check the length */ + if (user != NULL) + { + length = strlen(user); + if (length > SQL_AUTH_IDENT) + { + *errorMessage = "Default user name (from DB2DEFAULTUSER) too long"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + strcpy(authID, user); + *authIDLength = length; + strcpy(userid, user); + *useridLength = length; + } + else + { + *errorMessage = "DB2DEFAULTUSER not defined"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + } +#endif + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + return(rc); +} + + +/* LookupGroups() + * Return the list of groups to which a user belongs. + * + * For this plugin this involves finding the provided authorization + * ID in the User definition file and returning all fields after + * the second. + */ +SQL_API_RC SQL_API_FN LookupGroups(const char *authID, + db2int32 authIDLength, + const char *userid, /* ignored */ + db2int32 useridLength, /* ignored */ + const char *domain, /* ignored */ + db2int32 domainLength, /* ignored */ + db2int32 domainType, /* ignored */ + const char *databaseName, /* ignored */ + db2int32 databaseNameLength, /* ignored */ + void *token, /* ignored */ + db2int32 tokenType, /* ignored */ + db2int32 location, /* ignored */ + const char *authPluginName, /* ignored */ + db2int32 authPluginNameLength, /* ignored */ + void **groupList, + db2int32 *groupCount, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + int length; + int ngroups; + + char localAuthID[SQL_AUTH_IDENT + 1]; + char readBuffer[MAX_LINE_LENGTH]; + char *cptr; + + *errorMessage = NULL; + *errorMessageLength = 0; + + + /* NULL terminate the authID */ + if (authIDLength > SQL_AUTH_IDENT) + { + char msg[512]; + memcpy(localAuthID, authID, SQL_AUTH_IDENT); + localAuthID[SQL_AUTH_IDENT] = '\0'; + snprintf(msg, 512, + "LookupGroups: authID too long ("FMT_S32" bytes): %s... (truncated)", + authIDLength, localAuthID); + + msg[511]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + *errorMessage = "LookupGroups: authID too long"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + memcpy(localAuthID, authID, authIDLength); + localAuthID[authIDLength] = '\0'; + + + /* The maximum amount of group information that we could + * return is less than MAX_LINE_LENGTH bytes. + */ + *groupList = malloc(MAX_LINE_LENGTH); + if (*groupList == NULL) + { + *errorMessage = "malloc failed for group memory"; + rc = DB2SEC_PLUGIN_NOMEM; + goto exit; + } + + rc = FindUser(getUserFileName(), + localAuthID, /* User we're looking for */ + readBuffer, + sizeof(readBuffer), + NULL, /* Don't care about password */ + *groupList, + &ngroups, + errorMessage); + if (rc == -2) + { + /* Unexpected error. */ + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + else if (rc == -1) + { + /* User not found */ + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + *groupCount = ngroups; + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + return(rc); +} + + +/* FreeGroupList() + * Free a group list allocated in LookupGroups(). + */ +SQL_API_RC SQL_API_FN FreeGroupList(void *ptr, + char **errorMessage, + db2int32 *errorMessageLength) +{ + if (ptr != NULL) + { + free(ptr); + } + + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + + +/* DoesGroupExist + * Searches the user definition file for the named group. If + * any user is a member of the group, DB2SEC_PLUGIN_OK is + * returned, otherwise DB2SEC_PLUGIN_INVALIDUSERORGROUP is + * returned. + */ +SQL_API_RC SQL_API_FN DoesGroupExist(const char *groupName, + db2int32 groupNameLength, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + + char localGroupName[DB2SEC_MAX_AUTHID_LENGTH + 1]; + char readBuffer[MAX_LINE_LENGTH]; + + int foundGroup = 0; + + char *linePtr; + char *field; + char *nextPtr; + FILE *fp = NULL; + + *errorMessage = NULL; + *errorMessageLength = 0; + + if (groupName == NULL) + { + *errorMessage = "NULL group name supplied"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + /* NULL terminate the group name */ + if (groupNameLength > DB2SEC_MAX_AUTHID_LENGTH) + { + char msg[512]; + memcpy(localGroupName, groupName, DB2SEC_MAX_AUTHID_LENGTH); + localGroupName[DB2SEC_MAX_AUTHID_LENGTH] = '\0'; + snprintf(msg, 512, + "DoesGroupExist: group name too long ("FMT_S32" bytes): %s... (truncated)", + groupNameLength, localGroupName); + + msg[511]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + *errorMessage = "DoesGroupExist: group name too long"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + memcpy(localGroupName, groupName, groupNameLength); + localGroupName[groupNameLength] = '\0'; + + + fp = fopen(getUserFileName(),"r"); + if (fp == NULL) { + char msg[256]; + snprintf(msg, 256, + "DoesGroupExist: can't open file: %s", + getUserFileName()); + + msg[255]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + *errorMessage = "Cannot open specified file\n"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + while (foundGroup == 0) + { + /* Read the next line from the user definition file */ + linePtr = GetNextLine(fp, readBuffer, sizeof(readBuffer)); + + if (linePtr == (char*)-1) + { + /* Line length error */ + *errorMessage = "Encountered an invalid input line in file"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + if (linePtr == NULL) + { + /* We've probably reached the end of file, but make sure. */ + if (feof(fp)) + { + /* End of file: Group not found. */ + rc = DB2SEC_PLUGIN_INVALIDUSERORGROUP; + } + else + { + /* Not end of file, must have encountered an error. */ + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + *errorMessage = "Unknown file error encountered"; + } + goto exit; + } + + + field = NextField(linePtr, &nextPtr); /* Skip user name */ + field = NextField(nextPtr, &nextPtr); /* and password */ + + /* Examine all of the remaining fields */ + field = NextField(nextPtr, &nextPtr); + while (field != NULL) + { + if (strcasecmp(field, localGroupName) == 0) + { + /* Found it! */ + foundGroup = 1; + break; + } + + field = NextField(nextPtr, &nextPtr); + } + } + + if (foundGroup == 1) + { + rc = DB2SEC_PLUGIN_OK; + } + +exit: + if (fp != NULL) + { + fclose(fp); + } + + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + return(rc); +} + +/* FreeToken() + * This plugin does not make use of the "token" parameter, + * so this function is a no-op. + */ +SQL_API_RC SQL_API_FN FreeToken(void *token, + char **errorMessage, + db2int32 *errorMessageLength) +{ + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + + +/* FreeErrorMessage() + * All of the error messages returned by this plugin are + * literal C strings, so this function is a no-op. + */ +SQL_API_RC SQL_API_FN FreeErrorMessage(char *msg) +{ + return(DB2SEC_PLUGIN_OK); +} + +/* PluginTerminate() + * There is no cleanup required when this plugin is unloaded. + */ +SQL_API_RC SQL_API_FN PluginTerminate(char **errorMessage, + db2int32 *errorMessageLength) +{ + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + + +/* + * PLUGIN INITIALIZATION FUNCTIONS + * + * Unlike previous functions in this file, the names of these + * functions must match those defined in db2secPlugin.h. + */ + +/* Server-side userid/password authentication plugin initialization */ +SQL_API_RC SQL_API_FN db2secServerAuthPluginInit( + db2int32 version, + void *server_fns, + db2secGetConDetails *getConDetails_fn, + db2secLogMessage *msgFunc, + char **errorMessage, + db2int32 *errorMessageLength) +{ + db2secUseridPasswordServerAuthFunctions_1 *p; + + p = (db2secUseridPasswordServerAuthFunctions_1 *)server_fns; + + p->version = 1; /* We're a version 1 plugin */ + p->plugintype = DB2SEC_PLUGIN_TYPE_USERID_PASSWORD; + p->db2secValidatePassword = CheckPassword; + p->db2secGetAuthIDs = GetAuthIDs; + p->db2secDoesAuthIDExist = DoesAuthIDExist; + p->db2secFreeToken = FreeToken; + p->db2secFreeErrormsg = FreeErrorMessage; + p->db2secServerAuthPluginTerm = PluginTerminate; + + logFunc = msgFunc; + + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + +SQL_API_RC SQL_API_FN db2secClientAuthPluginInit (db2int32 version, + void *client_fns, + db2secLogMessage *msgFunc, + char **errorMessage, + db2int32 *errorMessageLength) +{ + db2secUseridPasswordClientAuthFunctions_1 *p; + + p = (db2secUseridPasswordClientAuthFunctions_1 *)client_fns; + + p->version = 1; /* We're a version 1 plugin */ + p->plugintype = DB2SEC_PLUGIN_TYPE_USERID_PASSWORD; + p->db2secRemapUserid = NULL; /* optional */ + p->db2secGetDefaultLoginContext = &WhoAmI; + p->db2secValidatePassword = &CheckPassword; + p->db2secFreeToken = &FreeToken; + p->db2secFreeErrormsg = &FreeErrorMessage; + p->db2secClientAuthPluginTerm = &PluginTerminate; + + logFunc = msgFunc; + + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + +SQL_API_RC SQL_API_FN db2secGroupPluginInit(db2int32 version, + void *group_fns, + db2secLogMessage *msgFunc, + char **errorMessage, + db2int32 *errorMessageLength) +{ + db2secGroupFunction_1 *p; + + p = (db2secGroupFunction_1 *)group_fns; + + p->version = 1; /* We're a version 1 plugin */ + p->plugintype = DB2SEC_PLUGIN_TYPE_GROUP; + p->db2secGetGroupsForUser = &LookupGroups; + p->db2secDoesGroupExist = &DoesGroupExist; + p->db2secFreeGroupListMemory = &FreeGroupList; + p->db2secFreeErrormsg = &FreeErrorMessage; + p->db2secPluginTerm = &PluginTerminate; + + logFunc = msgFunc; + + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} diff --git a/security/plugins/group_file.c b/security/plugins/group_file.c new file mode 100644 index 0000000..26abe71 --- /dev/null +++ b/security/plugins/group_file.c @@ -0,0 +1,738 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 2004 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: group_file.c +** +** SAMPLE: Simple file-based group management plugin +** +** This source file implements a simple, file-based group management +** scheme. +** +** When built, a single loadable object is created (see the makefile), +** which should be copied into the group plugin directory. Then the +** GROUP_PLUGIN database manager configuration parameter should be +** updated to the name of the plugin object file, minus any extensions. +** +** For example, on 32-bit UNIX platforms the loadable object should be +** copied to the .../sqllib/security32/plugin/group directory and the +** GROUP_PLUGIN parameter updated to "group_file". +** +***************************************************************************** +** +** For more information on developing DB2 security plugins, see the +** "Developing Security Plug-ins" section of the Application Development +** Guide. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "sqlenv.h" +#include "db2secPlugin.h" + +#ifdef DB2_PLAT_UNIX +#include +#include +#else +#define strcasecmp(a,b) stricmp(a,b) +#define snprintf _snprintf +#endif + +db2secLogMessage *logFunc = NULL; + +/* THE GROUP DEFINITION FILE + * Group membership information is managed in a file + * defined by "GROUP_FILENAME". + * + * This file consists of one line per user consisting of the + * username followed by zero or more groups, separted by whitespace: + * + * username [ group1 [group2 ... ] ] + * + * Lines that begin with "#" are comments. Blank lines are ignored. + * Note that user and group names may not contain whitespace (this + * limitation applies to this plugin implementation, not DB2 in + * general). + * + * The maximum line length is 1024 characters; lines longer than + * this value will result in undefined behavior. User and group + * names are limited to SQL_AUTH_IDENT bytes. Lines containing + * longer fields will result in an error. + */ +#ifndef GROUP_FILENAME /* Normally defined in the makefile */ +#ifndef WIN32 +#define GROUP_FILENAME "/home/db2inst1/sqllib/SampleGroupFile" +#else +#define GROUP_FILENAME "D:\\sqllib\\DB2\\SampleGroupFile" +#endif +#endif + +/* The internal max line length includes room for a line + * separator (CR/LF on Windows, LF on UNIX) and a NULL byte. + */ +#define MAX_LINE_LENGTH 1027 + +#define SQL_AUTH_IDENT 128 + + +/*------------------------------------------------------- + * Functions to read & parse the group definition file + *-------------------------------------------------------*/ + +/* + * NextField() + * Return a pointer to the next whitespace separated token in the input + * string. Skips over any leading whitespace. A NULL byte is written + * to the string after the token. + * + * The "nextString" output parameter can be used on the next call to + * this function to retrieve the next token, if any. + * + * Returns NULL if no more tokens exist in the input string. + * The orginal input string must be NULL terminated. + */ +char *NextField(char *inputString, char **nextString) +{ + char *returnString = NULL; + char *cptr; + + if (nextString != NULL) + { + *nextString = NULL; + } + + cptr = inputString; + + /* If the input string is NULL or zero length, return NULL. */ + if (cptr == NULL || *cptr == '\0') + { + goto exit; + } + + /* Skip any leading whitespace */ + while (*cptr == ' ' || *cptr == '\t') + { + cptr++; + } + + /* If we reach the end of the string return NULL. */ + if (*cptr == '\0') + { + goto exit; + } + + /* Found a non-whitespace, non-NULL character. This is the + * start of the string that we'll return. + */ + returnString = cptr; + + + /* Now we need to NULL terminate this token and set up nextString */ + cptr++; + while (*cptr != '\0') + { + if (*cptr == ' ' || *cptr == '\t') + { + /* Whitespace */ + *cptr = '\0'; /* NULL terminate */ + + if (nextString != NULL) + { + /* nextString starts with the character following + * the NULL byte we just inserted. + */ + *nextString = cptr + 1; + } + goto exit; /* We're done */ + } + cptr++; + } + + /* If we get here we've reached the end of the inputString. */ + if (nextString != NULL) + { + *nextString = NULL; + } + +exit: + return(returnString); +} /* NextField */ + + +/* GetNextLine() + * Returns a pointer to a string containing the next non-blank, + * non-comment line from the input file. A comment line is one + * where "#" is the first non-whitespace character. Leading + * whitespace is stripped from the returned string, as are trailing + * "\n" or "\r\n" sequences. + * + * "buf" and "bufLength" refer to a caller-supplied buffer used + * to hold the information read from the file. + * + * NULL is returned on EOF or error; the caller should use + * feof() and/or ferror() to determine which has occured. + * + * (char*)-1 is returned if an input line is encounted that doesn't + * fit into the supplied buffer. + */ +char *GetNextLine(FILE *fp, char *buf, int bufLength) +{ + char *returnPtr = NULL; + char *cptr; + int length; + + /* Loop until we find a valid line */ + while (returnPtr == NULL) { + + cptr = fgets(buf, bufLength - 1, fp); + if (cptr == NULL) + { + /* EOF or error, return NULL */ + goto exit; + } + + /* Strip trailing CR/NL bytes */ + length = strlen(cptr) - 1; + while (cptr[length] == '\n' || cptr[length] == '\r') + { + cptr[length] = '\0'; + length--; + } + + /* Skip over any leading whitespace */ + while (*cptr != '\0' && (*cptr == ' ' || *cptr == '\t')) + { + cptr++; + } + + /* If we didn't reach the end of the string and the first + * character is not '#', then return the line. Otherwise + * read the next line from the file. + */ + if (*cptr != '\0' && *cptr != '#') + { + returnPtr = cptr; + } + + } + +exit: + return(returnPtr); +} + + +/* FindUser() + * Open the indicated file and find the first line where the first + * field matches the provided username. Optionally return the + * second field (password) and/or parse the remaining fields + * (groups) into a non-NULL terminated, length-prefixed sequence + * of strings (see below). + * + * The caller must supply a read buffer for use when processing + * the file. + * + * Leading and trailing whitesapce is stripped from the password + * and all group names. + * + * Returns: 0 for success, + * -1 if the user was not found + * -2 on error, *errorMessage will be set to a static C + * string describing the error. + * + * If groups are requested, the supplied group buffer must be at + * least as large as the supplied read buffer. The groups are + * written into that buffer in the following format: + * ... + * and *numGroups is set to indicate how many groups were written + * to the group buffer. Note that the group name strings are not + * NULL terminated. + */ +int FindUser(const char *fileName, /* File to read */ + const char *userName, /* Who we're looking for */ + char *readBuffer, /* Caller-supplied read buffer */ + int readBufferLength, + char *groupBuffer, /* Output: group list */ + int *numGroups, /* Output: number of groups */ + char **errorMessage) /* Static C string for errors */ +{ + int rc = -1; + int foundUser = 0; /* Found the user yet? */ + + int groupCount = 0; + int length; + char *linePtr; + char *field; + char *nextPtr; + char *cptr; + char *errMsg = NULL; /* Temp local error message */ + FILE *fp = NULL; + + if (userName == NULL) + { + errMsg = "NULL user name supplied"; + rc = -2; + goto exit; + } + + if (readBuffer == NULL) + { + errMsg = "NULL read buffer supplied"; + rc = -2; + goto exit; + } + + if (numGroups != NULL) + { + *numGroups = 0; + } + + + fp = fopen(fileName,"r"); + if (fp == NULL) { + errMsg = "Cannot open specified file\n"; + rc = -2; + goto exit; + } + + + while (foundUser == 0) + { + linePtr = GetNextLine(fp, readBuffer, readBufferLength); + if (linePtr == (char*)-1) + { + /* Line length error */ + errMsg = "Encountered an invalid input line in file"; + rc = -2; + goto exit; + } + if (linePtr == NULL) + { + /* We've probably reached the end of file, but make sure. */ + if (feof(fp)) + { + /* End of file: User not found. */ + rc = -1; + } + else + { + /* Not end of file, must have encountered an error. */ + rc = -2; + errMsg = "Unknown file error encountered"; + } + goto exit; + } + + field = NextField(linePtr, &nextPtr); + if (field != NULL && strcasecmp(field, userName) == 0) + { + /* Found the correct user name. Parse the line. */ + foundUser = 1; + + /* If a group buffer pointer was supplied, + * parse the rest of the line. + */ + if (groupBuffer != NULL) + { + cptr = groupBuffer; + + field = NextField(nextPtr, &nextPtr); + while (field != NULL) + { + length = strlen(field); + + if (length > 255) + { + /* Since the group list is formatted using + * one byte lengths, a length of more than 255 + * bytes is an error. + */ + errMsg = "group name too long"; + rc = -2; + goto exit; + } + + *((unsigned char*)cptr) = (unsigned char)length; + cptr++; + + memcpy(cptr, field, length); + cptr += length; + + groupCount++; + + field = NextField(nextPtr, &nextPtr); + } + + /* Write a NULL byte after the last group; a + * "zero length group" indicates the end of the + * group list in case the caller did not supply + * "numGroups". + */ + *cptr = '\0'; + + if (numGroups != NULL) + { + *numGroups = groupCount; + } + } + + rc = 0; /* Found the user */ + } + } + +exit: + if (fp != NULL) + { + fclose(fp); + } + + if (errMsg != NULL) + { + char msg[256]; + snprintf(msg, 256, + "security plugin 'group_file' encountered an error\n" + "User: %s\nFile:%s\nError: %s\n", + userName, fileName, errMsg); + msg[255]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + if (errorMessage != NULL) + { + *errorMessage = errMsg; + } + } + + return(rc); +} + + +/*------------------------------------------------------- + * Plugin functions + *-------------------------------------------------------*/ + +/* LookupGroups() + * Return the list of groups to which a user belongs. + * + * Find the gven Auth ID in the group definition file and + * return the associated groups. + */ +SQL_API_RC SQL_API_FN LookupGroups(const char *authID, + db2int32 authIDLength, + const char *userid, /* ignored */ + db2int32 useridLength, /* ignored */ + const char *domain, /* ignored */ + db2int32 domainLength, /* ignored */ + db2int32 domainType, /* ignored */ + const char *databaseName, /* ignored */ + db2int32 databaseNameLength, /* ignored */ + void *token, /* ignored */ + db2int32 tokenType, /* ignored */ + db2int32 location, /* ignored */ + const char *authPluginName, /* ignored */ + db2int32 authPluginNameLength, /* ignored */ + void **groupList, + db2int32 *groupCount, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + int length; + int ngroups; + + char localAuthID[SQL_AUTH_IDENT + 1]; + char readBuffer[MAX_LINE_LENGTH]; + char *cptr; + + *errorMessage = NULL; + *errorMessageLength = 0; + + + /* NULL terminate the authID */ + if (authIDLength > SQL_AUTH_IDENT) + { + char msg[512]; + memcpy(localAuthID, authID, SQL_AUTH_IDENT); + localAuthID[SQL_AUTH_IDENT] = '\0'; + snprintf(msg, 512, + "LookupGroups: authID too long (%d bytes): %s... (truncated)", + authIDLength, localAuthID); + + msg[511]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + *errorMessage = "LookupGroups: authID too long"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + memcpy(localAuthID, authID, authIDLength); + localAuthID[authIDLength] = '\0'; + + + /* The maximum amount of group information that we could + * return is less than MAX_LINE_LENGTH bytes. + */ + *groupList = malloc(MAX_LINE_LENGTH); + if (*groupList == NULL) + { + *errorMessage = "malloc failed for group memory"; + rc = DB2SEC_PLUGIN_NOMEM; + goto exit; + } + + rc = FindUser(GROUP_FILENAME, + localAuthID, /* User we're looking for */ + readBuffer, + sizeof(readBuffer), + *groupList, + &ngroups, + errorMessage); + if (rc == -2) + { + /* Unexpected error. */ + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + else if (rc == -1) + { + /* User not found */ + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + *groupCount = ngroups; + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + return(rc); +} + + +/* FreeGroupList() + * Free a group list allocated in LookupGroups(). + */ +SQL_API_RC SQL_API_FN FreeGroupList(void *ptr, + char **errorMessage, + db2int32 *errorMessageLength) +{ + if (ptr != NULL) + { + free(ptr); + } + + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + + +/* DoesGroupExist + * Searches the group definition file for the named group. If + * any user is a member of the group, DB2SEC_PLUGIN_OK is + * returned, otherwise DB2SEC_PLUGIN_INVALIDUSERORGROUP is + * returned. + */ +SQL_API_RC SQL_API_FN DoesGroupExist(const char *groupName, + db2int32 groupNameLength, + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + + char localGroupName[DB2SEC_MAX_AUTHID_LENGTH+1]; + char readBuffer[MAX_LINE_LENGTH]; + + int foundGroup = 0; + + char *linePtr; + char *field; + char *nextPtr; + FILE *fp = NULL; + + *errorMessage = NULL; + *errorMessageLength = 0; + + if (groupName == NULL) + { + *errorMessage = "NULL group name supplied"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + /* NULL terminate the group name */ + if (groupNameLength > DB2SEC_MAX_AUTHID_LENGTH) + { + char msg[512]; + memcpy(localGroupName, groupName, DB2SEC_MAX_AUTHID_LENGTH); + localGroupName[DB2SEC_MAX_AUTHID_LENGTH] = '\0'; + snprintf(msg, 512, + "DoesGroupExist: group name too long (%d bytes): %s... (truncated)", + groupNameLength, localGroupName); + + msg[511]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + *errorMessage = "DoesGroupExist: group name too long"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + memcpy(localGroupName, groupName, groupNameLength); + localGroupName[groupNameLength] = '\0'; + + + fp = fopen(GROUP_FILENAME,"r"); + if (fp == NULL) { + char msg[256]; + snprintf(msg, 256, + "DoesGroupExist: can't open file: %s", + GROUP_FILENAME); + + msg[255]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + *errorMessage = "Cannot open specified file\n"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + + while (foundGroup == 0) + { + /* Read the next line from the user definition file */ + linePtr = GetNextLine(fp, readBuffer, sizeof(readBuffer)); + + if (linePtr == (char*)-1) + { + /* Line length error */ + *errorMessage = "Encountered an invalid input line in file"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + if (linePtr == NULL) + { + /* We've probably reached the end of file, but make sure. */ + if (feof(fp)) + { + /* End of file: Group not found. */ + rc = DB2SEC_PLUGIN_INVALIDUSERORGROUP; + } + else + { + /* Not end of file, must have encountered an error. */ + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + *errorMessage = "Unknown file error encountered"; + } + goto exit; + } + + + field = NextField(linePtr, &nextPtr); /* Skip user name */ + + /* Examine all of the remaining fields */ + field = NextField(nextPtr, &nextPtr); + while (field != NULL) + { + if (strcasecmp(field, localGroupName) == 0) + { + /* Found it! */ + foundGroup = 1; + break; + } + + field = NextField(nextPtr, &nextPtr); + } + } + + if (foundGroup == 1) + { + rc = DB2SEC_PLUGIN_OK; + } + +exit: + if (fp != NULL) + { + fclose(fp); + } + + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + return(rc); +} + + +/* FreeErrorMessage() + * All of the error messages returned by this plugin are + * literal C strings, so this function is a no-op. + */ +SQL_API_RC SQL_API_FN FreeErrorMessage(char *msg) +{ + return(DB2SEC_PLUGIN_OK); +} + + +/* PluginTerminate() + * There is no cleanup required when this plugin is unloaded. + */ +SQL_API_RC SQL_API_FN PluginTerminate(char **errorMessage, + db2int32 *errorMessageLength) +{ + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} + + +/* PLUGIN INITIALIZATION FUNCTION + * + * This is the only plugin function that is required to have + * a specific name. + */ +SQL_API_RC SQL_API_FN db2secGroupPluginInit(db2int32 version, + void *group_fns, + db2secLogMessage *msgFunc, + char **errorMessage, + db2int32 *errorMessageLength) +{ + db2secGroupFunction_1 *p; + + p = (db2secGroupFunction_1 *)group_fns; + + p->version = 1; /* We're a version 1 plugin */ + p->plugintype = DB2SEC_PLUGIN_TYPE_GROUP; + p->db2secGetGroupsForUser = &LookupGroups; + p->db2secDoesGroupExist = &DoesGroupExist; + p->db2secFreeGroupListMemory = &FreeGroupList; + p->db2secFreeErrormsg = &FreeErrorMessage; + p->db2secPluginTerm = &PluginTerminate; + + logFunc = msgFunc; + + *errorMessage = NULL; + *errorMessageLength = 0; + return(DB2SEC_PLUGIN_OK); +} diff --git a/security/plugins/gssapi_simple.c b/security/plugins/gssapi_simple.c new file mode 100644 index 0000000..d59641e --- /dev/null +++ b/security/plugins/gssapi_simple.c @@ -0,0 +1,1851 @@ +/**************************************************************************** +** Licensed Materials - Property of IBM +** +** Governed under the terms of the International +** License Agreement for Non-Warranted Sample Code. +** +** (C) COPYRIGHT International Business Machines Corp. 2004 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +***************************************************************************** +** +** SOURCE FILE NAME: gssapi_simple.c +** +** SAMPLE: Basic GSS-API authentication plugin sample (both client & server) +** +** This single source files implements both the client and server pieces +** of a simple GSS-API authentication mechanism. +** +** When built, a single loadable object is created (see the makefile). +** However, because DB2 treats server-side authentication and client-side +** authentication as separate plugins, the single loadable object must +** be copied into two different directories. For example, on 32-bit +** UNIX platforms the loadable object should be copied into: +** .../sqllib/security32/plugin/server +** .../sqllib/security32/plugin/client +** +** To enable the plugin the SRVCON_GSSPLUGIN_LIST database manager +** configuration parameter must be updated (on the server only) to +** include the plugin name, and the AUTHENTICATION parameter (or +** SRVCON_AUTH parameter) must be one of GSSPLUGIN or GSS_SERVER_ENCRYPT. +** +***************************************************************************** +** +** For more information on developing DB2 security plugins, see the +** "Developing Security Plug-ins" section of the Application Development +** Guide. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include + +#ifdef DB2_PLAT_UNIX +#include +#include +#else +#define strcasecmp(a,b) stricmp(a,b) +#define snprintf _snprintf +#endif + +#include "sqlenv.h" +#include "db2secPlugin.h" + +db2secLogMessage *logFunc = NULL; + +/* THE USER DEFINITION FILE + * Userid and password information is located in a + * file defined by "USER_FILENAME". + * + * This file consists of one line per user with two + * whitespace separated fields on each line: + * + * username password + * + * Both the username and password are mandatory. Additional + * fields after the second are ignored. + * + * Lines that begin with "#" are comments. Blank lines are + * ignored. Note that usernames and passwords may not + * contain whitespace. + * + * The maximum line length is 1024 characters; lines longer than + * this value will result in undefined behavior. User names are + * limited to SQL_AUTH_IDENT bytes, passwords are limited to + * DB2SEC_MAX_PASSWORD_LENGTH bytes. Lines containing longer + * fields are silently ignored. + */ +#ifndef USER_FILENAME /* Normally defined in the makefile */ +#ifndef WIN32 +#define USER_FILENAME "/home/db2inst1/sqllib/SamplePluginUsers" +#else +#define USER_FILENAME "D:\\sqllib\\DB2\\SamplePluginUsers" +#endif +#endif + +/* Maximum line length for the user definition file + * The internal max line length includes room for a line + * separator (CR/LF on Windows, LF on UNIX) and a NULL byte. + */ +#define MAX_LINE_LENGTH 1027 + +#define SQL_AUTH_IDENT 128 + +/* Minor Status Codes + * Ordering of messages is important as it corresponds to the + * appropriate minor status codes + */ +static const char *retcodeMessage[] = +{ + "Operation completed successfully", /* RETCODE_OK */ + "Credential failed authenticaiton", /* RECODE_BADPASS */ + "Unexpected input token provided", /* RETCODE_BADTOKEN */ + "Mutual authentication failure", /* RETCODE_MUTFAIL */ + "Illegal call to gss_init/accept_sec_context",/* RETCODE_PROGERR */ + "Memory allocation error", /* RETCODE_MALLOC */ + "Error processing user definition file", /* RETCODE_USERFILE */ + "Error description not available" /* RETCODE_UNKNOWN */ +}; + +#define RETCODE_OK 0 +#define RETCODE_BADPASS 1 +#define RETCODE_BADTOKEN 2 +#define RETCODE_MUTFAIL 3 +#define RETCODE_PROGERR 4 +#define RETCODE_MALLOC 5 +#define RETCODE_USERFILE 6 +#define RETCODE_UNKNOWN 7 + +#define RETCODE_MAXCODE RETCODE_UNKNOWN + +#define MAJOR_CODE_STRING "gssapi_simple plugin encounted an error" + + +/* Format of the token */ +#define TOKEN_MAX_STRLEN 64 +typedef struct _token{ + int useridLen; + char userid[TOKEN_MAX_STRLEN]; + int pwdLen; + char pwd[TOKEN_MAX_STRLEN]; + int targetLen; + char target[TOKEN_MAX_STRLEN]; + OM_uint32 retFlags; +} TOKEN_T; + +typedef struct _name{ + int useridLen; + char *userid; +} NAME_T; + +/* Our GSS-APU Context */ +typedef struct _context{ + int sourceLen; + char *source; + int targetLen; + char *target; + int ctxCount; +} CONTEXT_T; + +/* Our GSS-API credential */ +typedef struct _cred{ + int useridLen; + char *userid; + int pwdLen; + char *pwd; +} CRED_T; + +/* We use a hardcoded principle name that happens to be the name of + * the plugin. In a more complex environment, this would be the + * security mechanism identity associated with the server instance. + */ +#define PRINCIPLE_NAME "GSSAPI_SIMPLE" + +/* Hardcoded "server credentials". This is returned to the + * client for mutual authentication. For this example, we + * use the principle name as the userid and a blank password. + */ +CRED_T serverCred = {sizeof(PRINCIPLE_NAME)-1, PRINCIPLE_NAME, 0, ""}; + + + + +/*-------------------------------------------------- + * COMMON FUNCTIONS - both client and server side + *--------------------------------------------------*/ + +/* ByteReverse() + * This plugin sends a TOKEN_T (defined above) between client + * and server system, which may be of different endianess. + * The length fields in the token are sent in Network Byte Order + * (big endian), and this function is used to convert them when + * required. + * + * Rather than depend on a static #define to determine behavior + * we determine the endianess of the current system on the fly. + */ +int ByteReverse(int input) +{ + int output = input; + union + { + short s; + char c; + } test; + + test.s = 1; + if (test.c == (char)1) + { + /* This is a little endian platform, byte reverse. + * We try to make no assumptions about the size of the native + * type here. This may not be efficient, but it's portable. + */ + char *ip = (char*)&input; + char *op = (char*)&output; + int size = sizeof(int); + int i; + for (i=0; i < size; i++) + { + op[i] = ip[size - i - 1]; + } + } + return(output); +} + +/* NextField() + * Return a pointer to the next whitespace separated token in the input + * string. Skips over any leading whitespace. A NULL byte is written + * to the string after the token. + * + * The "nextString" output parameter can be used on the next call to + * this function to retrieve the next token, if any. + * + * Returns NULL if no more tokens exist in the input string. + * The orginal input string must be NULL terminated. + */ +char *NextField(char *inputString, char **nextString) +{ + char *returnString = NULL; + char *cptr; + + if (nextString != NULL) + { + *nextString = NULL; + } + + cptr = inputString; + + /* If the input string is NULL or zero length, return NULL. */ + if (cptr == NULL || *cptr == '\0') + { + goto exit; + } + + /* Skip any leading whitespace */ + while (*cptr == ' ' || *cptr == '\t') + { + cptr++; + } + + /* If we reach the end of the string return NULL. */ + if (*cptr == '\0') + { + goto exit; + } + + /* Found a non-whitespace, non-NULL character. This is the + * start of the string that we'll return. + */ + returnString = cptr; + + + /* Now we need to NULL terminate this token and set up nextString */ + cptr++; + while (*cptr != '\0') + { + if (*cptr == ' ' || *cptr == '\t') + { + /* Whitespace */ + *cptr = '\0'; /* NULL terminate */ + + if (nextString != NULL) + { + /* nextString starts with the character following + * the NULL byte we just inserted. + */ + *nextString = cptr + 1; + } + goto exit; /* We're done */ + } + cptr++; + } + + /* If we get here we've reached the end of the inputString. */ + if (nextString != NULL) + { + *nextString = NULL; + } + +exit: + return(returnString); +} /* NextField */ + + +/* GetNextLine() + * Returns a pointer to a string containing the next non-blank, + * non-comment line from the input file. A comment line is one + * where "#" is the first non-whitespace character. Leading + * whitespace is stripped from the returned string, as are trailing + * "\n" or "\r\n" sequences. + * + * "buf" and "bufLength" refer to a caller-supplied buffer used + * to hold the information read from the file. + * + * NULL is returned on EOF or error; the caller should use + * feof() and/or ferror() to determine which has occured. + * + * (char*)-1 is returned if an input line is encounted that doesn't + * fit into the supplied buffer. + */ +char *GetNextLine(FILE *fp, char *buf, int bufLength) +{ + char *returnPtr = NULL; + char *cptr; + int length; + + /* Loop until we find a valid line */ + while (returnPtr == NULL) { + + cptr = fgets(buf, bufLength - 1, fp); + if (cptr == NULL) + { + /* EOF or error, return NULL */ + goto exit; + } + + /* Strip trailing CR/NL bytes */ + length = strlen(cptr) - 1; + while (cptr[length] == '\n' || cptr[length] == '\r') + { + cptr[length] = '\0'; + length--; + } + + /* Skip over any leading whitespace */ + while (*cptr != '\0' && (*cptr == ' ' || *cptr == '\t')) + { + cptr++; + } + + /* If we didn't reach the end of the string and the first + * character is not '#', then return the line. Otherwise + * read the next line from the file. + */ + if (*cptr != '\0' && *cptr != '#') + { + returnPtr = cptr; + } + + } + +exit: + return(returnPtr); +} + + +/* FindUser() + * Open the indicated file and find the first line where the first + * field matches the provided username. Optionally return the + * second field (password) and/or parse the remaining fields + * (groups) into a non-NULL terminated, length-prefixed sequence + * of strings (see below). + * + * The caller must supply a read buffer for use when processing + * the file. + * + * Leading and trailing whitesapce is stripped from the password + * and all group names. + * + * Returns: 0 for success, + * -1 if the user was not found + * -2 on error, *errorMessage will be set to a static C + * string describing the error. + * + * If groups are requested, the supplied group buffer must be at + * least as large as the supplied read buffer. The groups are + * written into that buffer in the following format: + * ... + * and *numGroups is set to indicate how many groups were written + * to the group buffer. Note that the group name strings are not + * NULL terminated. + */ +int FindUser(const char *fileName, /* File to read */ + const char *userName, /* Who we're looking for */ + char *readBuffer, /* Caller-supplied read buffer */ + int readBufferLength, + char **passwordPtr, /* Output: password */ + char **errorMessage) /* Static C string for errors */ +{ + int rc = -1; + int foundUser = 0; /* Found the user yet? */ + + int length; + char *linePtr; + char *field; + char *nextPtr; + char *cptr; + char *errMsg = NULL; /* Temp local error message */ + FILE *fp = NULL; + + if (userName == NULL) + { + errMsg = "NULL user name supplied"; + rc = -2; + goto exit; + } + + if (readBuffer == NULL) + { + errMsg = "NULL read buffer supplied"; + rc = -2; + goto exit; + } + + if (passwordPtr != NULL) + { + *passwordPtr = NULL; + } + + + fp = fopen(fileName,"r"); + if (fp == NULL) { + errMsg = "Cannot open specified file\n"; + rc = -2; + goto exit; + } + + + while (foundUser == 0) + { + linePtr = GetNextLine(fp, readBuffer, readBufferLength); + if (linePtr == (char*)-1) + { + /* Line length error */ + errMsg = "Encountered an invalid input line in file"; + rc = -2; + goto exit; + } + if (linePtr == NULL) + { + /* We've probably reached the end of file, but make sure. */ + if (feof(fp)) + { + /* End of file: User not found. */ + rc = -1; + } + else + { + /* Not end of file, must have encountered an error. */ + rc = -2; + errMsg = "Unknown file error encountered"; + } + goto exit; + } + + field = NextField(linePtr, &nextPtr); + if (field != NULL && strcasecmp(field, userName) == 0) + { + /* Found the correct user name. Parse the line. */ + foundUser = 1; + + /* Second field is the password */ + field = NextField(nextPtr, &nextPtr); + + /* A blank password field is an error. */ + if (field == NULL) + { + errMsg = "No password for user"; + rc = -2; + goto exit; + } + if (passwordPtr != NULL) + { + *passwordPtr = field; + } + + rc = 0; /* Found the user */ + } + } + +exit: + if (fp != NULL) + { + fclose(fp); + } + + if (errMsg != NULL) + { + char msg[256]; + snprintf(msg, 256, + "security plugin 'gssapi_simple' encountered an error\n" + "User: %s\nFile: %s\nError: %s\n", + userName, fileName, errMsg); + msg[255]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + if (errorMessage != NULL) + { + *errorMessage = errMsg; + } + } + + return(rc); +} + + +/* FreeErrorMessage() + * This is no-op. All error messaged returned by this plugin + * are static C strings. + */ +SQL_API_RC SQL_API_FN FreeErrorMessage(char *errormsg) +{ + return(DB2SEC_PLUGIN_OK); +} + +/* gss_release_cred() + * Release the specified credential and free associated memory. + */ +OM_uint32 SQL_API_FN gss_release_cred(OM_uint32 *minorStatus, + gss_cred_id_t *pCredHandle) +{ + OM_uint32 rc=GSS_S_COMPLETE; + CRED_T *pCred; + + /* This condition also accounts for pCredHandle == GSS_C_NO_CREDENTIAL */ + if (pCredHandle != NULL) + { + if (*pCredHandle != GSS_C_NO_CREDENTIAL) + { + pCred = (CRED_T *) *pCredHandle; + free(pCred->userid); + free(pCred->pwd); + free(pCred); + *pCredHandle = GSS_C_NO_CREDENTIAL; + } + } + else + { + rc = GSS_S_NO_CRED; + goto exit; + } + +exit: + return(rc); +} + +/* gss_release_name() + * Free memory associated with the specified name. + */ +OM_uint32 SQL_API_FN gss_release_name(OM_uint32 *minorStatus, + gss_name_t *name) +{ + OM_uint32 rc=GSS_S_COMPLETE; + NAME_T *pName; + + if (name != NULL && *name != NULL) + { + pName = (NAME_T *) *name; + free(pName->userid); + free(pName); + *name = GSS_C_NO_NAME; + } + + return(rc); +} + +/* gss_release_buffer() + * Free the specified buffer. + */ +OM_uint32 SQL_API_FN gss_release_buffer(OM_uint32 *minorStatus, + gss_buffer_t buffer) +{ + OM_uint32 rc=GSS_S_COMPLETE; + NAME_T *pName; + + if ((buffer != NULL) && + (buffer->length > 0) && (buffer->value != NULL)) + { + free(buffer->value); + buffer->value = NULL; + buffer->length = 0; + } + + return(rc); +} + +/* gss_delete_sec_context() + * Free the specified context. + */ +OM_uint32 SQL_API_FN gss_delete_sec_context(OM_uint32 *minorStatus, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + OM_uint32 rc=GSS_S_COMPLETE; + CONTEXT_T *pCtx; + + if (context_handle != NULL && *context_handle != NULL) + { + pCtx = (CONTEXT_T *)*context_handle; + free(pCtx->source); + free(pCtx->target); + free(pCtx); + *context_handle = GSS_C_NO_CONTEXT; + + if (output_token != GSS_C_NO_BUFFER) + { + output_token->value = NULL; + output_token->length = 0; + } + } + else + { + rc = GSS_S_NO_CONTEXT; + goto exit; + } + +exit: + + return(rc); +} + +/* gss_display_status() + * Return the text message assocaited with the given status type + * and status value. + */ +OM_uint32 SQL_API_FN gss_display_status(OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + OM_uint32 rc=GSS_S_COMPLETE; + + /* No mech types supported */ + if (mech_type != NULL) + { + rc = GSS_S_BAD_MECH; + goto exit; + } + + /* Regardless of the type of status code, a 0 means success */ + if (status_value == GSS_S_COMPLETE) + { + status_string->length = strlen(retcodeMessage[RETCODE_OK]); + status_string->value = (void *) malloc(status_string->length); + if (status_string->value == NULL) goto malloc_fail; + strcpy((char *)(status_string->value), retcodeMessage[RETCODE_OK]); + goto exit; + } + + if (status_type == GSS_C_GSS_CODE) + { + /* Major status code -- we only have 1 for the moment */ + status_string->length = strlen(MAJOR_CODE_STRING); + status_string->value = (void *)malloc(status_string->length); + if (status_string->value == NULL) goto malloc_fail; + strcpy((char *)(status_string->value), MAJOR_CODE_STRING); + } + else if (status_type == GSS_C_MECH_CODE) + { + /* Minor status code */ + /* Make sure we don't index too high */ + if (status_value > RETCODE_MAXCODE) + { + rc = GSS_S_BAD_STATUS; + *minor_status = RETCODE_UNKNOWN; + goto exit; + } + status_string->length = strlen(retcodeMessage[status_value]); + status_string->value = (void *)malloc(status_string->length); + if (status_string->value == NULL) goto malloc_fail; + strcpy((char *)(status_string->value), retcodeMessage[status_value]); + } + else + { + rc = GSS_S_BAD_STATUS; + goto exit; + } + +exit: + /* No more messages available */ + *message_context = 0; + + return(rc); + +malloc_fail: + status_string->length = 0; + rc = GSS_S_FAILURE; + *minor_status = RETCODE_MALLOC; + goto exit; +} + +/* FreeToken() + * A no-op, since we don't use a token in this plugin. + */ +SQL_API_RC SQL_API_FN FreeToken(void *token, + char **errorMsg, + db2int32 *errorMsgLen) +{ + *errorMsg = NULL; + *errorMsgLen = 0; + return(DB2SEC_PLUGIN_OK); +} + +/* PluginTerminate + * Clean up anything allocated during plugin initialization. + */ +SQL_API_RC SQL_API_FN PluginTerminate(char **errorMsg, + db2int32 *errorMsgLen) +{ + /* Nothing to do */ + + *errorMsg = NULL; + *errorMsgLen = 0; + + return(DB2SEC_PLUGIN_OK); +} + + +/*-------------------------------------------------- + * CLIENT SIDE FUNCTIONS + *--------------------------------------------------*/ + +/* GetDefaultLoginContext() + * Determine the default user identity associated with the current + * process context. + * + * For simplicity this plugin returns the string found in the + * DB2DEFAULTUSER environment variable, or an error if that variable + * is undefined. + */ +SQL_API_RC SQL_API_FN GetDefaultLoginContext( + char authID[], + db2int32 *authIDLength, + char userid[], + db2int32 *useridLength, + db2int32 useridType, /* ignored */ + char domain[], + db2int32 *domainLength, + db2int32 *domainType, + const char *databaseName, /* not used */ + db2int32 databaseNameLength, /* not used */ + void **token, /* not used */ + char **errorMessage, + db2int32 *errorMessageLength) +{ + int rc = DB2SEC_PLUGIN_OK; + int length; + char *user; + + *errorMessage = NULL; + *errorMessageLength = 0; + + authID[0] = '\0'; + *authIDLength = 0; + userid[0] = '\0'; + *useridLength = 0; + domain[0] = '\0'; + *domainLength = 0; + *domainType = DB2SEC_USER_NAMESPACE_UNDEFINED; + + user = getenv("DB2DEFAULTUSER"); + + /* Check the length */ + if (user != NULL) + { + length = strlen(user); + if (length > SQL_AUTH_IDENT) + { + *errorMessage = "Default user name (from DB2DEFAULTUSER) too long"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + strcpy(authID, user); + *authIDLength = length; + strcpy(userid, user); + *useridLength = length; + } + else + { + *errorMessage = "DB2DEFAULTUSER not defined"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + +exit: + if (*errorMessage != NULL) + { + *errorMessageLength = strlen(*errorMessage); + } + + return(rc); +} + + +/* GenerateInitialCredential + */ +SQL_API_RC SQL_API_FN GenerateInitialCredential(const char *userid, + db2int32 useridLen, + const char *usernamespace, + db2int32 usernamespacelen, + db2int32 usernamespacetype, + const char *password, + db2int32 passwordLen, + const char *newpassword, + db2int32 newpasswordLen, + const char *dbname, + db2int32 dbnameLen, + gss_cred_id_t *pGSSCredHandle, + void **ppInitInfo, + char **errorMsg, + db2int32 *errorMsgLen) +{ + int rc = DB2SEC_PLUGIN_OK; + CRED_T *pCred; + char *localErrorMsg = NULL; + char oneNullByte[] = {'\0'}; + + + if (newpasswordLen > 0) + { + rc = DB2SEC_PLUGIN_CHANGEPASSWORD_NOTSUPPORTED; + goto exit; + } + + if (!pGSSCredHandle) + { + localErrorMsg = "GenerateInitialCredential: pGSSCredHandle == NULL"; + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + /* Check lengths */ + if (useridLen > TOKEN_MAX_STRLEN) + { + rc = DB2SEC_PLUGIN_BADUSER; + localErrorMsg = "GenerateInitialCredential: userid too long"; + goto exit; + } + if (passwordLen > TOKEN_MAX_STRLEN) + { + rc = DB2SEC_PLUGIN_BADPWD; + localErrorMsg = "GenerateInitialCredential: password too long"; + goto exit; + } + + pCred = (CRED_T *)malloc(sizeof(CRED_T)); + if (pCred == NULL) goto malloc_fail; + memset(pCred, '\0', sizeof(CRED_T)); + + /* Deal with NULL userids and passwords by using a one-byte + * string containing only a NULL. We flow this to the server + * and let it decide. + */ + if (useridLen == 0 || userid == NULL) + { + userid = oneNullByte; + useridLen = 1; + } + if (passwordLen == 0 || password == NULL) + { + password = oneNullByte; + passwordLen = 1; + } + + pCred->useridLen = useridLen; + pCred->userid = (char *)malloc(useridLen); + if (pCred->userid == NULL) goto malloc_fail; + memcpy(pCred->userid, userid, useridLen); + + pCred->pwdLen = passwordLen; + pCred->pwd = (char *)malloc(passwordLen); + if (pCred->pwd == NULL) goto malloc_fail; + memcpy(pCred->pwd, password, passwordLen); + + *pGSSCredHandle = (gss_cred_id_t)pCred; + +exit: + + /* No init info */ + if (ppInitInfo != NULL) + { + *ppInitInfo = NULL; + } + + if (localErrorMsg != NULL) + { + *errorMsg = localErrorMsg; + *errorMsgLen = strlen(localErrorMsg); + } + else + { + *errorMsg = NULL; + *errorMsgLen = 0; + } + + return(rc); + +malloc_fail: + if (pCred != NULL) { + if (pCred->pwd != NULL) free(pCred->pwd); + if (pCred->userid != NULL) free(pCred->userid); + free(pCred); + } + + localErrorMsg = "GenerateInitialCredential: malloc failed"; + rc = DB2SEC_PLUGIN_NOMEM; + + goto exit; +} + +/* ProcessServerPrincipalName + * Process the principle name string returned from the server + * and package it into a gss_name_t. + */ +SQL_API_RC SQL_API_FN ProcessServerPrincipalName(const char *name, + db2int32 nameLen, + gss_name_t *gssName, + char **errorMsg, + db2int32 *errorMsgLen) +{ + int rc = DB2SEC_PLUGIN_OK; + NAME_T *pName; + + /* No error messages */ + *errorMsg = NULL; + *errorMsgLen = 0; + + if (name != NULL && nameLen > 0) + { + pName = (NAME_T *) malloc(sizeof(NAME_T)); + if (pName == NULL) goto malloc_fail; + memset(pName, '\0', sizeof(NAME_T)); + + pName->useridLen = nameLen; + pName->userid = (char *) malloc(nameLen); + if (pName->userid == NULL) goto malloc_fail; + memcpy(pName->userid, name, nameLen); + + *gssName = (gss_name_t)pName; + } + else + { + rc = DB2SEC_PLUGIN_BAD_PRINCIPAL_NAME; + goto exit; + } + +exit: + return(rc); + +malloc_fail: + if (pName != NULL) + { + if (pName->userid) free(pName->userid); + free(pName); + } + *errorMsg = "ProcessServerPrincipalName: malloc failed"; + *errorMsgLen = strlen(*errorMsg); + goto exit; +} + +/* FreeInitInfo() + * A no-op, since we don't set up any init info. + */ +SQL_API_RC SQL_API_FN FreeInitInfo(void *initInfo, + char **errorMsg, + db2int32 *errorMsgLen) +{ + *errorMsg = NULL; + *errorMsgLen = 0; + return(DB2SEC_PLUGIN_OK); +} + + +/* gss_init_sec_context() + * Initialize a context based on input data. + * + * For the case where no credentials are passed in, the default + * credentials are built from the userid and password in the + * "DB2DEFAULTUSER" and "DB2DEFAULTPSWD" environment variables, + * respectively. NULL values are used if those variables do not + * exist. + */ +OM_uint32 SQL_API_FN gss_init_sec_context( + OM_uint32 * minor_status, + const gss_cred_id_t cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + OM_uint32 rc = GSS_S_COMPLETE; + NAME_T *pTarget = NULL; + NAME_T localTarget; + CONTEXT_T *pCtx = NULL; + CRED_T *pCred = NULL; + CRED_T defaultCred; + TOKEN_T *pInToken = NULL; + TOKEN_T *pOutToken = NULL; + char *localuser = NULL; + char *localpswd = NULL; + char *cptr = NULL; + char *errMsg = NULL; + int length; + + /* Check for unsupported options */ + if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) + { + errMsg = "input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS"; + rc = GSS_S_BAD_BINDINGS; + goto exit; + } + if (mech_type != GSS_C_NO_OID) + { + errMsg = "mech_type != GSS_C_NO_OID"; + rc = GSS_S_BAD_MECH; + goto exit; + } + if (context_handle == NULL) + { + errMsg = "context_handle == NULL"; + rc = GSS_S_NO_CONTEXT; + goto exit; + } + + /* Check the target name; only the hardcoded value is acceptable. */ + pTarget = (NAME_T *)target_name; + if (pTarget == GSS_C_NO_NAME) + { + localTarget.userid = PRINCIPLE_NAME; + localTarget.useridLen = strlen(PRINCIPLE_NAME); + pTarget = &localTarget; + } + else if(strncmp(pTarget->userid, PRINCIPLE_NAME, pTarget->useridLen) != 0) + { + errMsg = "principle mismatch"; + rc = GSS_S_BAD_NAME; + goto exit; + } + + /* Check the input credentials */ + if (cred_handle == GSS_C_NO_CREDENTIAL) + { + /* Get default userid/password from the environment, + * and truncate them if required. + */ + cptr = getenv("DB2DEFAULTUSER"); + if (cptr == NULL) + { + /* Use a one byte NULL for the userid */ + length = 1; + cptr = ""; + } + else + { + length = strlen(cptr); + if (length > TOKEN_MAX_STRLEN) + { + length = TOKEN_MAX_STRLEN; + } + } + + localuser = (char *)malloc(length); + if (localuser == NULL) goto malloc_fail; + memcpy(localuser, cptr, length); + defaultCred.userid = localuser; + defaultCred.useridLen = length; + + cptr = getenv("DB2DEFAULTPSWD"); + if (cptr == NULL) + { + /* Use a one byte NULL for the password */ + length = 1; + cptr = ""; + } + else + { + length = strlen(cptr); + if (length > TOKEN_MAX_STRLEN) + { + length = TOKEN_MAX_STRLEN; + } + } + + localpswd = (char*)malloc(length); + if (localpswd == NULL) goto malloc_fail; + memcpy(localpswd, cptr, length); + defaultCred.pwd = localpswd; + defaultCred.pwdLen = length; + + pCred = &defaultCred; + } + else + { + pCred = (CRED_T *)cred_handle; + } + + + /* On first call to init_sec_context, the context handle should be set to */ + /* GSS_C_NO_CONTEXT; set up the context structure */ + if (*context_handle == GSS_C_NO_CONTEXT) + { + pCtx = (CONTEXT_T *)malloc(sizeof(CONTEXT_T)); + if (pCtx == NULL) goto malloc_fail; + memset(pCtx, '\0', sizeof(CONTEXT_T)); + + pCtx->targetLen = pTarget->useridLen; + pCtx->target = (char *)malloc(pCtx->targetLen); + if (pCtx->target == NULL) goto malloc_fail; + memcpy(pCtx->target, pTarget->userid, pCtx->targetLen); + + pCtx->sourceLen = pCred->useridLen; + pCtx->source = (char *)malloc(pCtx->sourceLen); + if (pCtx->source == NULL) goto malloc_fail; + memcpy(pCtx->source, pCred->userid, pCtx->sourceLen); + + pCtx->ctxCount = 0; + *context_handle = pCtx; + } + else + { + pCtx = (CONTEXT_T *)*context_handle; + if (pCtx->ctxCount == 0) + { + errMsg = "pCtx->ctxCount == 0"; + rc = GSS_S_NO_CONTEXT; + goto exit; + } + } + + + /* Process input token and generate output token */ + + /* First invocation */ + if (pCtx->ctxCount == 0) + { + /* There should be no input token */ + if (input_token != GSS_C_NO_BUFFER) + { + errMsg = "bad input_token"; + rc = GSS_S_FAILURE; + *minor_status = 2; + goto exit; + } + + /* Generate service token */ + pOutToken = (TOKEN_T *)malloc(sizeof(TOKEN_T)); + if (pOutToken == NULL) goto malloc_fail; + memset(pOutToken, '\0', sizeof(TOKEN_T)); + + pOutToken->useridLen = ByteReverse(pCred->useridLen); + pOutToken->pwdLen = ByteReverse(pCred->pwdLen); + pOutToken->targetLen = ByteReverse(pTarget->useridLen); + memcpy(pOutToken->userid, pCred->userid, pCred->useridLen); + memcpy(pOutToken->pwd, pCred->pwd, pCred->pwdLen); + memcpy(pOutToken->target, pTarget->userid, pTarget->useridLen); + pOutToken->retFlags = req_flags; + + output_token->value = (void *)pOutToken; + output_token->length = sizeof(TOKEN_T); + + if (req_flags & GSS_C_MUTUAL_FLAG) + { + /* Mutual authentication requested */ + rc = GSS_S_CONTINUE_NEEDED; + } + else + { + /* Make the context count negative so that the next invocation will */ + /* result in an error */ + pCtx->ctxCount = -2; + } + } + else if (pCtx->ctxCount == 1) + { + /* Second invocation -- mutual authentication if necessary */ + /* Sanity check */ + if (input_token->length != sizeof(TOKEN_T)) + { + errMsg = "bad input_token"; + rc = GSS_S_DEFECTIVE_TOKEN; + goto exit; + } + + /* Normally we would want to check the information returned + * from the server to verify we're talking to who we think + * we are. However, for this example we'll just accept + * whatever the server sent us. + */ + if (0) + { + /* Mutual authentication failed */ + rc = GSS_S_FAILURE; + *minor_status = RETCODE_MUTFAIL; + goto exit; + } + + /* Set the context count to negative so that the next invocation will */ + /* result in an error */ + pCtx->ctxCount = -2; + } + else + { + /* Function shouldn't have been called again for context establishment */ + errMsg = "context count too high!"; + rc = GSS_S_FAILURE; + *minor_status = RETCODE_PROGERR; + goto exit; + } + + /* Fill in secondary information */ + if(actual_mech_type != NULL) + { + *actual_mech_type = mech_type; + } + if(ret_flags != NULL) + { + *ret_flags = req_flags; + } + if(time_rec != NULL) + { + *time_rec = time_req; + } + +exit: + if (errMsg != NULL) + { + char msg[512]; + sprintf(msg,"gssapi_simple/gss_init_sec_context error: %s", errMsg); + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + } + + (pCtx->ctxCount)++; + + return(rc); + +malloc_fail: + if (localuser != NULL) free(localuser); + if (localpswd != NULL) free(localpswd); + if (pCtx != NULL) + { + if (pCtx->target != NULL) free(pCtx->target); + if (pCtx->source != NULL) free(pCtx->source); + free(pCtx); + } + if (pOutToken != NULL) free(pOutToken); + + rc = GSS_S_FAILURE; + *minor_status = RETCODE_MALLOC; + + logFunc(DB2SEC_LOG_ERROR, + "gssapi_simple/gss_init_sec_context: malloc failure", 50); + + return(rc); +} + + +/* db2secClientAuthPluginInit() + * Set up plugin function pointers and perform other initialization. + * This function is called by name when the plugin is loaded. + */ +SQL_API_RC SQL_API_FN db2secClientAuthPluginInit(db2int32 version, + void *fns, + db2secLogMessage *msgFunc, + char **errormsg, + db2int32 *errormsglen) +{ + int rc = DB2SEC_PLUGIN_OK; + db2secGssapiClientAuthFunctions_1 *pFPs; + + /* No error message */ + *errormsg = NULL; + *errormsglen = 0; + + /* Written to version 1 of the API */ + if (version < DB2SEC_API_VERSION) + { + rc = DB2SEC_PLUGIN_INCOMPATIBLE_VER; + goto exit; + } + + pFPs = (db2secGssapiClientAuthFunctions_1 *) fns; + + pFPs->plugintype = DB2SEC_PLUGIN_TYPE_GSSAPI; + pFPs->version = 1; + + /* Set up function pointers */ + pFPs->db2secGetDefaultLoginContext = GetDefaultLoginContext; + pFPs->db2secGenerateInitialCred = GenerateInitialCredential; + pFPs->db2secProcessServerPrincipalName = ProcessServerPrincipalName; + pFPs->db2secFreeToken = FreeToken; + pFPs->db2secFreeErrormsg = FreeErrorMessage; + pFPs->db2secFreeInitInfo = FreeInitInfo; + pFPs->db2secClientAuthPluginTerm = PluginTerminate; + pFPs->gss_init_sec_context = gss_init_sec_context; + pFPs->gss_delete_sec_context = gss_delete_sec_context; + pFPs->gss_display_status = gss_display_status; + pFPs->gss_release_buffer = gss_release_buffer; + pFPs->gss_release_cred = gss_release_cred; + pFPs->gss_release_name = gss_release_name; + + logFunc = msgFunc; + +exit: + + return(rc); +} + + +/*-------------------------------------------------- + * SERVER SIDE FUNCTIONS + *--------------------------------------------------*/ + +/* GetAuthIDs + * Return the DB2 Authorization IDs associated with the supplied + * context. + * + * At this point, the GSS-API context is assumed to have been + * established and the context handle is passed in as the token. + */ +SQL_API_RC SQL_API_FN GetAuthIDs(const char *userid, /* ignored */ + db2int32 useridlen, /* ignored */ + const char *usernamespace, /* ignored */ + db2int32 usernamespacelen, /* ignored */ + db2int32 usernamespacetype, /* ignored */ + const char *dbname, /* ignored */ + db2int32 dbnamelen, /* ignored */ + void **token, + char SystemAuthID[], + db2int32 *SystemAuthIDlen, + char InitialSessionAuthID[], + db2int32 *InitialSessionAuthIDlen, + char username[], + db2int32 *usernamelen, + db2int32 *initsessionidtype, + char **errormsg, + db2int32 *errormsglen) +{ + int rc = DB2SEC_PLUGIN_OK; + int length; + CONTEXT_T *pCtx; + + *errormsg = NULL; + *errormsglen = 0; + + pCtx = (CONTEXT_T *) (*token); + if (pCtx == NULL) + { + rc = DB2SEC_PLUGIN_NO_CRED; + *errormsg = "GetAuthIDs: pCtx is NULL"; + *errormsglen = strlen(*errormsg); + } + + length = pCtx->targetLen; + + /* The DB2 Authid is the userid received from the client, + * currently stored in pCtx->target. Check the length first! + */ + if (length > SQL_AUTH_IDENT) + { + rc = DB2SEC_PLUGIN_BADUSER; + *errormsg = "GetAuthIDs: userid too long"; + *errormsglen = strlen(*errormsg); + goto exit; + } + + memcpy(username, pCtx->target, length); + *usernamelen = length; + memcpy(SystemAuthID, username, length); + *SystemAuthIDlen = length; + memcpy(InitialSessionAuthID, username, length); + *InitialSessionAuthIDlen = length; + + *initsessionidtype = 0; /* TBD ?! --sil */ + +exit: + return(rc); +} + +/* DoesAuthIDExist() + * Does the supplied DB2 Authorization ID refer to a valid user? + */ +SQL_API_RC SQL_API_FN db2secDoesAuthIDExist(const char *authid, + db2int32 authidLen, + char **errorMsg, + db2int32 *errorMsgLen) +{ + int rc; + char lineBuf[MAX_LINE_LENGTH]; + char localAuthID[SQL_AUTH_IDENT + 1]; + + *errorMsg = NULL; + *errorMsgLen = 0; + + /* NULL terminate the authID */ + if (authidLen > SQL_AUTH_IDENT) + { + char msg[512]; + memcpy(localAuthID, authid, SQL_AUTH_IDENT); + localAuthID[SQL_AUTH_IDENT] = '\0'; + snprintf(msg, 512, + "DoesAuthIDExist: authID too long (%d bytes): %s... (truncated)", + authidLen, localAuthID); + + msg[511]='\0'; /* ensure NULL terminated */ + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + + *errorMsg = "DoesAuthIDExist: authID too long"; + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + + memcpy(localAuthID, authid, authidLen); + localAuthID[authidLen] = '\0'; + + rc = FindUser(USER_FILENAME, + localAuthID, /* User we're looking for */ + lineBuf, + sizeof(lineBuf), + NULL, /* Don't want the password */ + errorMsg); + if (rc == -2) + { + /* Unexpected error. */ + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + else if (rc == -1) + { + /* User not found */ + rc = DB2SEC_PLUGIN_BADUSER; + goto exit; + } + else + { + /* Found the user */ + rc = DB2SEC_PLUGIN_OK; + } + +exit: + *errorMsgLen = strlen(*errorMsg); + return(rc); +} + +/* gss_accept_sec_context() + * Process a token received from the client, including + * validating the encapsulated userid/password. + */ +OM_uint32 SQL_API_FN gss_accept_sec_context( + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + OM_uint32 rc = GSS_S_COMPLETE; + CRED_T *pServerCred = NULL; + TOKEN_T *pInToken = NULL; + TOKEN_T *pOutToken = NULL; + NAME_T *pName = NULL; + CONTEXT_T *pCtx = NULL; + char localUserid[SQL_AUTH_IDENT + 1]; /* Null terminated userid */ + char lineBuf[MAX_LINE_LENGTH]; + char *actualPassword = NULL; + char *errMsg = NULL; + int rc2; + int length; + int i; + + /* Check for non-supported options and sanity checks */ + if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) + { + errMsg = "input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS"; + rc = GSS_S_BAD_BINDINGS; + goto exit; + } + if (mech_type != NULL) + { + errMsg = "mech_type != NULL"; + rc = GSS_S_BAD_MECH; + goto exit; + } + if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) + { + errMsg = "acceptor_cred_handle == GSS_C_NO_CREDENTIAL"; + rc = GSS_S_DEFECTIVE_CREDENTIAL; + goto exit; + } + if (input_token == GSS_C_NO_BUFFER) + { + errMsg = "input_token == GSS_C_NO_BUFFER"; + rc = GSS_S_DEFECTIVE_CREDENTIAL; + goto exit; + } + if (context_handle == GSS_C_NO_CONTEXT) + { + errMsg = "context_handle == GSS_C_NO_CONTEXT"; + rc = GSS_S_NO_CONTEXT; + goto exit; + } + /* Ignore delegated_cred_handle since we don't use it. */ + + + /* The Input Token contains the encapsulated userid/password + * received from the client. + */ + if (input_token->length != sizeof(TOKEN_T)) + { + errMsg = "input_token->length != sizeof(TOKEN_T)"; + rc = GSS_S_DEFECTIVE_CREDENTIAL; + goto exit; + } + pInToken = (TOKEN_T *)(input_token->value); + + /* + * The acceptor_cred_handle should be our server credential. + */ + pServerCred = (CRED_T *)acceptor_cred_handle; + + + /* First check to see if the we have the correct target. + * The target refers to the server identity, and in this + * example is the hardcoded principle name. + */ + length = ByteReverse(pInToken->targetLen); + if ((length != pServerCred->useridLen) || + (strncmp(pInToken->target, pServerCred->userid, length) != 0)) + { + errMsg = "problem with target server identity"; + rc = GSS_S_DEFECTIVE_CREDENTIAL; + goto exit; + } + + /* On first call to init_sec_context, the context handle should + * be set to GSS_C_NO_CONTEXT; set up the context structure + */ + if (*context_handle == GSS_C_NO_CONTEXT) + { + pCtx = (CONTEXT_T *)malloc(sizeof(CONTEXT_T)); + if (pCtx == NULL) goto malloc_fail; + + pCtx->targetLen = ByteReverse(pInToken->useridLen); + pCtx->target = (char *)malloc(pCtx->targetLen); + if (pCtx->target == NULL) goto malloc_fail; + memcpy(pCtx->target, pInToken->userid, pCtx->targetLen); + + pCtx->sourceLen = pServerCred->useridLen; + pCtx->source = (char *)malloc(pCtx->sourceLen); + if (pCtx->source == NULL) goto malloc_fail; + memcpy(pCtx->source, pServerCred->userid, pCtx->sourceLen); + + pCtx->ctxCount = 0; + *context_handle = pCtx; + } + else + { + pCtx = (CONTEXT_T *) *context_handle; + if (pCtx->ctxCount == 0) + { + errMsg = "pCtx->ctxCount == 0"; + rc = GSS_S_NO_CONTEXT; + goto exit; + } + } + + /* First invocation */ + if (pCtx->ctxCount == 0) + { + /* Perform authentication */ + + /* Copy & null terminate the userid */ + length = ByteReverse(pInToken->useridLen); + + if (length >= sizeof(localUserid)) + { + /* Bad userid. */ + rc = GSS_S_DEFECTIVE_CREDENTIAL; + *minor_status = RETCODE_BADPASS; + } + else + { + memcpy(localUserid, pInToken->userid, length); + localUserid[length] = '\0'; + + rc2 = FindUser(USER_FILENAME, + localUserid, /* User we're looking for */ + lineBuf, + sizeof(lineBuf), + &actualPassword, + NULL); + if (rc2 == -2) + { + /* Unexpected error. */ + rc = GSS_S_FAILURE; + *minor_status = RETCODE_USERFILE; + } + else if (rc2 == -1) + { + /* User not found */ + rc = GSS_S_DEFECTIVE_CREDENTIAL; + *minor_status = RETCODE_BADPASS; + } + else + { + length = ByteReverse(pInToken->pwdLen); + if ((strlen(actualPassword) != length) || + (strncmp(actualPassword, pInToken->pwd, length) != 0)) + { + /* Bad password. */ + rc = GSS_S_DEFECTIVE_CREDENTIAL; + *minor_status = RETCODE_BADPASS; + } + } + } + + + /* Generate service token + * This is sent back to the client for mutual authentication. + * We send the hardcoded principle name and a zero length + * password. This sample plugin ignores this information on + * the client side. + */ + pOutToken = (TOKEN_T *)malloc(sizeof(TOKEN_T)); + if (pOutToken == NULL) goto malloc_fail; + memset(pOutToken, '\0', sizeof(TOKEN_T)); + + /* Server "userid" (principle name) */ + length = pServerCred->useridLen; + pOutToken->useridLen = ByteReverse(length); + memcpy(pOutToken->userid, pServerCred->userid, length); + + /* Server "password" (zero length in this sample) */ + pOutToken->pwdLen = 0; + + /* Target is the userid provided by the client */ + length = ByteReverse(pInToken->useridLen); + pOutToken->targetLen = pInToken->useridLen; + memcpy(pOutToken->target, pInToken->userid, length); + + pOutToken->retFlags = pInToken->retFlags; + + output_token->value = (void *) pOutToken; + output_token->length = sizeof(TOKEN_T); + + /* We're done. No more flows. Make the context count negative + * so that the next invocation will result in an error. + */ + pCtx->ctxCount = -2; + } + else + { + /* Function shouldn't have been called again for context establishment */ + errMsg = "context count too large!"; + rc = GSS_S_FAILURE; + *minor_status = 4; + goto exit; + } + + /* Fill in the secondary information */ + if (src_name != NULL) + { + pName = (NAME_T *)malloc(sizeof(NAME_T)); + if (pName == NULL) goto malloc_fail; + + length = ByteReverse(pInToken->useridLen); + pName->userid = (char *)malloc(length); + if (pName->userid == NULL) goto malloc_fail; + + pName->useridLen = length; + memcpy(pName->userid, pInToken->userid, length); + *src_name = (gss_name_t)pName; + } + + if (ret_flags != NULL) + { + *ret_flags = pInToken->retFlags; + } + + if (time_rec != NULL) + { + *time_rec = 0; + } + +exit: + if (errMsg != NULL) + { + char msg[512]; + sprintf(msg,"gssapi_simple/gss_accept_sec_context error: %s", errMsg); + logFunc(DB2SEC_LOG_ERROR, msg, strlen(msg)); + } + + (pCtx->ctxCount)++; + return(rc); + +malloc_fail: + if (pCtx != NULL) + { + if (pCtx->target != NULL) free(pCtx->target); + if (pCtx->source != NULL) free(pCtx->source); + free(pCtx); + } + if (pOutToken != NULL) free(pOutToken); + if (pName != NULL) + { + if (pName->userid != NULL) free(pName->userid); + free(pName); + } + + rc = GSS_S_FAILURE; + *minor_status = RETCODE_MALLOC; + + logFunc(DB2SEC_LOG_ERROR, + "gssapi_simple/gss_accept_sec_context: malloc failure", 52); + + return(rc); +} + +/****************************************************************************** +* +* Function Name = +* +* Descriptive Name = +* +* Function = +* +* Dependencies = +* +* Restrictions = +* +* Input = +* +* Output = +* +* Normal Return = DB2SEC_PLUGIN_OK +* +* Error Return = +* +*******************************************************************************/ +OM_uint32 SQL_API_FN gss_display_name(OM_uint32 * minor_status, + const gss_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID * output_name_type) +{ + OM_uint32 rc = GSS_S_COMPLETE; + NAME_T *pName; + + /* No name types supported */ + if (output_name_type != NULL) + { + rc = GSS_S_BAD_NAMETYPE; + goto exit; + } + + if (output_name_buffer) + { + pName = (NAME_T *) input_name; + output_name_buffer->length = pName->useridLen; + output_name_buffer->value = (void *) malloc(output_name_buffer->length); + strncpy((char *)(output_name_buffer->value), + pName->userid, + output_name_buffer->length); + } + else + { + rc = GSS_S_BAD_NAME; + goto exit; + } + +exit: + + return(rc); +} + + +/* db2secServerAuthPluginInit() + * Set up plugin function pointers and perform other initialization. + * This function is called by name when the plugin is loaded. + */ +SQL_API_RC SQL_API_FN db2secServerAuthPluginInit(db2int32 version, + void *functions, + db2secGetConDetails *getConDetails_fn, + db2secLogMessage *msgFunc, + char **errormsg, + db2int32 *errormsglen) +{ + int rc = DB2SEC_PLUGIN_OK; + db2secGssapiServerAuthFunctions_1 *pFPs; + char *principalName; + int length; + + /* No error message */ + *errormsg = NULL; + *errormsglen = 0; + + if (version < DB2SEC_API_VERSION) + { + rc = DB2SEC_PLUGIN_UNKNOWNERROR; + goto exit; + } + + pFPs = (db2secGssapiServerAuthFunctions_1 *)functions; + + pFPs->plugintype = DB2SEC_PLUGIN_TYPE_GSSAPI; + pFPs->version = DB2SEC_API_VERSION; + + /* Populate the server name */ + pFPs->serverPrincipalName.value = PRINCIPLE_NAME; + pFPs->serverPrincipalName.length = strlen(PRINCIPLE_NAME);; + + /* Fill in the server's cred handle */ + pFPs->serverCredHandle = (gss_cred_id_t)&serverCred; + + /* Set up function pointers */ + pFPs->db2secGetAuthIDs = GetAuthIDs; + pFPs->db2secDoesAuthIDExist = db2secDoesAuthIDExist; + pFPs->db2secFreeErrormsg = FreeErrorMessage; + pFPs->db2secServerAuthPluginTerm = PluginTerminate; + pFPs->gss_accept_sec_context = gss_accept_sec_context; + pFPs->gss_display_name = gss_display_name; + pFPs->gss_delete_sec_context = gss_delete_sec_context; + pFPs->gss_display_status = gss_display_status; + pFPs->gss_release_buffer = gss_release_buffer; + pFPs->gss_release_cred = gss_release_cred; + pFPs->gss_release_name = gss_release_name; + + logFunc = msgFunc; + +exit: + return(rc); +} diff --git a/security/plugins/makefile b/security/plugins/makefile new file mode 100644 index 0000000..1a4ade0 --- /dev/null +++ b/security/plugins/makefile @@ -0,0 +1,86 @@ +############################################################################## +# Licensed Materials - Property of IBM +# +# Governed under the terms of the International +# License Agreement for Non-Warranted Sample Code. +# +# (C) COPYRIGHT International Business Machines Corp. 2004 +# All Rights Reserved. +# +# US Government Users Restricted Rights - Use, duplication or +# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +############################################################################## +# +# MAKEFILE for security samples on Linux +# +# Enter one of the following commands +# +# make - Builds the plugin designated by +# make all - Builds all supplied sample plugins +# make clean - Erases all intermediate files +# make cleanall - Erases all files produced in the build process +# except the original source files +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +########################################################################### +# 1 -- VARIABLES # +########################################################################### + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +# shell script used to compile samples +BLDPLUGIN = bldplugin + +# The combined, gssapi_simple and group_file samples all obtain their +# information about users and group from text files. These variables +# define the location of those files. For simplicity, the two +# authentication examples default to the same file. +COMBINED_USERFILE = $(DB2PATH)/USERS +GSSAPI_USERFILE = $(DB2PATH)/USERS +GROUP_FILE = $(DB2PATH)/GROUPS + +# Plugin suffix for Linux +LIBSUFF = so + +ERASE = rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +############################################################################# + +all : combined.$(LIBSUFF) gssapi_simple.$(LIBSUFF) group_file.$(LIBSUFF) + +clean : + $(ERASE) *.o + +cleanall : + $(ERASE) *.o + $(ERASE) combined.$(LIBSUFF) gssapi_simple.$(LIBSUFF) group_file.$(LIBSUFF) + + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +############################################################################# + +combined: combined.$(LIBSUFF) + +combined.$(LIBSUFF): combined.c + bldplugin combined -DUSER_FILENAME="\"$(COMBINED_USERFILE)\"" $(PLUGIN_CFLAGS) + +gssapi_simple: gssapi_simple.$(LIBSUFF) + +gssapi_simple.$(LIBSUFF): gssapi_simple.c + bldplugin gssapi_simple -DUSER_FILENAME="\"$(GSSAPI_USERFILE)\"" $(PLUGIN_CFLAGS) + +group_file: group_file.$(LIBSUFF) + +group_file.$(LIBSUFF): group_file.c + bldplugin group_file -DGROUP_FILENAME="\"$(GROUP_FILE)\"" $(PLUGIN_CFLAGS) diff --git a/selinux/RHEL5/Makefile b/selinux/RHEL5/Makefile new file mode 100644 index 0000000..31be7ba --- /dev/null +++ b/selinux/RHEL5/Makefile @@ -0,0 +1,24 @@ +# installation paths +SHAREDIR := /usr/share/selinux + +AWK ?= gawk +NAME ?= $(strip $(shell $(AWK) -F= '/^SELINUXTYPE/{ print $$2 }' /etc/selinux/config)) + +MLSENABLED := $(shell cat /selinux/mls) +ifeq ($(MLSENABLED),) + MLSENABLED := 1 +endif + +ifeq ($(MLSENABLED),1) + MCSFLAG=-mcs +endif + +ifeq ($(NAME), mls) + NAME = strict + MCSFLAG = -mls +endif + +TYPE ?= $(NAME)${MCSFLAG} +HEADERDIR := $(SHAREDIR)/devel/include +include $(HEADERDIR)/Makefile + diff --git a/selinux/RHEL5/README b/selinux/RHEL5/README new file mode 100644 index 0000000..ea29ba2 --- /dev/null +++ b/selinux/RHEL5/README @@ -0,0 +1,147 @@ +How to install this RHEL5 SELinux policy (customer setup). + +1. Install the selinux-policy-devel rpm from the Redhat install media. + +2. Type "make" -- this will compile the SELinux module, db2.pp + +3. Run "semodule -i db2.pp" -- this will install the db2 module + +4. Make sure selinux is enabled in /etc/sysconfig/selinux: + + # SELINUX= can take one of these three values: + # enforcing - SELinux security policy is enforced. + # permissive - SELinux prints warnings instead of enforcing. + # disabled - SELinux is fully disabled. + SELINUX=enforcing <---- set to "enforcing" + +5. If SELINUX was not previously "enforcing" in /etc/sysconfig/selinux, + reboot the machine -- this will enable selinux and cause files in + /opt/ibm/db2 to be relabeled. + + If SELINUX was previously "enforcing" in /etc/sysconfig/selinux, + run "restorecon -R /opt/ibm/db2". After that is done, you should + see this (note db2_file_t label): + + # ls -Z /opt/ibm/db2/V9.5/ + dr-xr-xr-x bin bin root:object_r:db2_file_t adm + dr-xr-xr-x bin bin root:object_r:db2_file_t adsm + dr-xr-xr-x bin bin root:object_r:db2_file_t bin + dr-xr-xr-x bin bin root:object_r:db2_file_t bnd + dr-xr-xr-x bin bin root:object_r:db2_file_t cfg + dr-xr-xr-x bin bin root:object_r:db2_file_t conv + dr-xr-xr-x bin bin root:object_r:db2_file_t das + dr-xr-xr-x bin bin root:object_r:db2_file_t dasfcn + -rw-rw-r-- root root root:object_r:db2_file_t default.env + dr-xr-xr-x bin bin root:object_r:db2_file_t doc + dr-xr-xr-x bin bin root:object_r:db2_file_t function + dr-xr-xr-x bin bin root:object_r:db2_file_t ha + dr-xr-xr-x bin bin root:object_r:db2_file_t icons + dr-xr-xr-x bin bin root:object_r:db2_file_t include + dr-xr-xr-x bin bin root:object_r:db2_file_t infopop + dr-xr-xr-x bin bin root:object_r:db2_file_t install + dr-xr-xr-x bin bin root:object_r:db2_file_t instance + dr-xr-xr-x bin bin root:object_r:db2_file_t java + dr-xr-xr-x bin bin root:object_r:db2_file_t lib32 + dr-xr-xr-x bin bin root:object_r:db2_file_t lib64 + drwxr-xr-x root root root:object_r:db2_file_t license + dr-xr-xr-x bin bin root:object_r:db2_file_t map + dr-xr-xr-x bin bin root:object_r:db2_file_t misc + dr-xr-xr-x bin bin root:object_r:db2_file_t msg + -rw-r--r-- root root root:object_r:db2_file_t profiles.reg + dr-xr-xr-x bin bin root:object_r:db2_file_t Readme + dr-xr-xr-x bin bin root:object_r:db2_file_t samples + dr-xr-xr-x bin bin root:object_r:db2_file_t security32 + dr-xr-xr-x bin bin root:object_r:db2_file_t security64 + dr-xr-xr-x bin bin root:object_r:db2_file_t tivready + dr-xr-xr-x bin bin root:object_r:db2_file_t tools + +6. Run the "ibm_db2_semanage_das" script to apply SELinux labels to the files + in the DAS user's home directory. Example: + + ./ibm_db2_semanage_das -a /home/dasusr1 + +7. Run the "ibm_db2_semanage_db2inst" script to apply SELinux labels to the + files and directories in the instance owner's home directory: + + # ./ibm_db2_semanage_db2inst -a db2inst1 /home/db2inst1 + # ls -Z /home/db2inst1/sqllib + drwxr-xr-x db2inst1 db2grp1 user_u:object_r:db2_file_t adm + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t adsm -> /opt/ibm/db2/V9.5/adsm + drwxr-x--- db2inst1 db2grp1 user_u:object_r:db2_file_t backup + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t bin -> /opt/ibm/db2/V9.5/bin + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t bnd -> /opt/ibm/db2/V9.5/bnd + drwxrwsr-t db2inst1 db2grp1 user_u:object_r:db2_file_t cfg + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t conv -> /opt/ibm/db2/V9.5/conv + drwxrwsr-t db2inst1 db2grp1 user_u:object_r:db2_file_t ctrl + drwxrwsr-t db2inst1 db2grp1 user_u:object_r:db2_file_t dasfcn + -rwxr-xr-x db2inst1 db2grp1 user_u:object_r:db2_file_t db2cshrc + drwxrwsrwt db2inst1 db2grp1 user_u:object_r:db2_diag_t db2dump + -r--r--r-- db2inst1 db2grp1 user_u:object_r:db2_file_t db2nodes.cfg + -rwxr-xr-x db2inst1 db2grp1 user_u:object_r:db2_file_t db2profile + -rw-rw-r-- db2inst1 db2grp1 user_u:object_r:db2_file_t db2systm + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t doc -> /opt/ibm/db2/V9.5/doc + -rw-r--r-- db2inst1 db2grp1 user_u:object_r:db2_file_t fm.diego.reg + drwxrwsr-t db2inst1 db2grp1 user_u:object_r:db2_shlib_t function + drwx------ db2inst1 db2grp1 user_u:object_r:db2_file_t hmonCache + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t include -> /opt/ibm/db2/V9.5/include + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t infopop -> /opt/ibm/db2/V9.5/infopop + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t java -> /opt/ibm/db2/V9.5/java + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t lib -> lib64 + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t lib32 -> /opt/ibm/db2/V9.5/lib32 + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t lib64 -> /opt/ibm/db2/V9.5/lib64 + drwxrwsr-t db2inst1 db2grp1 user_u:object_r:db2_file_t log + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t map -> /opt/ibm/db2/V9.5/map + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t misc -> /opt/ibm/db2/V9.5/misc + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t msg -> /opt/ibm/db2/V9.5/msg + -rw-rw-r-- db2inst1 db2grp1 user_u:object_r:db2_file_t profile.env + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t Readme -> /opt/ibm/db2/V9.5/Readme + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t samples -> /opt/ibm/db2/V9.5/samples + drwxr-xr-x db2inst1 db2grp1 user_u:object_r:db2_file_t security + drwxr-xr-x db2inst1 db2grp1 user_u:object_r:db2_file_t security32 + drwxr-xr-x db2inst1 db2grp1 user_u:object_r:db2_file_t security64 + drwxrwsrwx db2inst1 db2grp1 user_u:object_r:db2_file_t tmp + lrwxrwxrwx root db2grp1 user_u:object_r:db2_file_t tools -> /opt/ibm/db2/V9.5/tools + drwxrwxrwx db2inst1 db2grp1 user_u:object_r:db2_file_t uif + -rwxr-xr-x db2inst1 db2grp1 user_u:object_r:db2_file_t usercshrc + -rwxr-xr-x db2inst1 db2grp1 user_u:object_r:db2_file_t userprofile + +8. Reboot the machine to restart the DB2 Fault Monitor + +9. Make sure DB2 is running in its own domain(s): + # ps aux -Z | grep db2 + system_u:system_r:init_t root 2928 0.0 0.1 34384 4292 ? Ss Apr18 0:01 /opt/ibm/db2/V9.5/bin/db2fmcd + system_u:system_r:db2_t dasusr1 3077 0.0 0.1 109500 6944 ? Sl Apr18 0:00 /home/dasusr1/das/adm/db2dasrrm + system_u:system_r:db2_t dasusr1 3098 0.0 0.1 57092 4400 ? S Apr18 0:00 /opt/ibm/db2/V9.5/das/bin/db2fmd -i dasusr1 -m /opt/ibm/db2/V9.5/das/lib/libdb2dasgcf.so.1 + system_u:system_r:unconfined_t root 10658 0.0 0.0 60228 708 pts/1 S+ 12:07 0:00 grep db2 + +10. The DB2 instance's processes will also run in their own domain(s): + $ ps aux -Z | grep db2inst1 + system_u:system_r:unconfined_t root 10677 0.0 0.0 100056 1264 pts/1 S 12:08 0:00 su - db2inst1 + system_u:system_r:unconfined_t db2inst1 10678 0.0 0.0 65128 1496 pts/1 S 12:08 0:00 -bash + system_u:system_r:db2adm_t db2inst1 10777 0.0 0.6 341284 25576 pts/1 S 12:08 0:00 db2sysc 0 + system_u:system_r:db2adm_t db2inst1 10782 0.0 0.4 337084 17260 pts/1 S 12:08 0:00 db2licc 0 + system_u:system_r:db2adm_t db2inst1 10783 0.0 0.4 337084 16972 pts/1 S 12:08 0:00 db2ipccm 0 + system_u:system_r:db2adm_t db2inst1 10784 0.0 0.4 341284 16952 pts/1 S 12:08 0:00 db2tcpcm 0 + system_u:system_r:db2adm_t db2inst1 10785 0.0 0.4 341284 16948 pts/1 S 12:08 0:00 db2tcpcm 0 + system_u:system_r:db2adm_t db2inst1 10787 0.0 0.4 341284 17224 pts/1 S 12:08 0:00 db2resync 0 + system_u:system_r:db2adm_t db2inst1 10789 0.0 0.7 345132 29036 pts/1 Sl 12:08 0:00 db2acd ,0,0,0,1,0,0,0,897c7c,14,1e014,2,0,1,11fc0,0x210000000,0x210000000,1610000,30003,2,7000a + system_u:system_r:unconfined_t db2inst1 10847 0.0 0.0 69140 1072 pts/1 R+ 12:12 0:00 ps aux -Z + system_u:system_r:unconfined_t db2inst1 10848 0.0 0.0 60236 724 pts/1 S+ 12:12 0:00 grep db2inst1 + + +Troubleshooting + +A. Watch /var/log/messages for output like this: + setroubleshoot: SELinux is preventing /opt/ibm/db2/V9.5/bin/db2fm (db2_t) "use" to /dev/null (init_t). For complete SELinux messages. run sealert -l 0be517de-b797-4aec-b274-8b936d77cf95 + +B. If any are found: + i) Run the sealert command with the parameters that were given in /var/log/messages: + sealert -l 0be517de-b797-4aec-b274-8b936d77cf95 + + ii) Cut and paste the Raw Audit Message into a file, and pass the file to "audit2allow" + + iii) Add necessary the permission to db2.te, rebuild db2.pp, and reload it + (steps 2 and 3, above) + +3. The command "semanage fcontext -l" will list file contexts. Use with grep + to find contexts related to DB2. diff --git a/selinux/RHEL5/db2.fc b/selinux/RHEL5/db2.fc new file mode 100644 index 0000000..0c2b10a --- /dev/null +++ b/selinux/RHEL5/db2.fc @@ -0,0 +1,52 @@ +##### +# IBM DB2 files stored in /opt and /var +#### +# Identify generic (bind, configuration, sample, etc) DB2 files +/var/db2(/.*)? gen_context(root:object_r:db2_var_t,s0) +/opt/ibm/db2/V9.(1|5)(/.*)? -- gen_context(root:object_r:db2_file_t,s0) +/opt/ibm/db2/V9.(1|5)(/.*)? -l gen_context(root:object_r:db2_file_t,s0) + +# Identify db2_exec_t files, exceptions. Note that order is important because +# trailing rules override. +/opt/ibm/db2/V9.(1|5)/adm/.* gen_context(root:object_r:db2adm_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/adsm/.* gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/bin/.* gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/bin/db2fmcd -- gen_context(root:object_r:db2fm_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/bin/db2refs.ndx -- gen_context(root:object_r:db2_file_t,s0) +/opt/ibm/db2/V9.(1|5)/bin/MQLInstall.sql -- gen_context(root:object_r:db2_file_t,s0) +/opt/ibm/db2/V9.(1|5)/bin/readme.pct -- gen_context(root:object_r:db2_file_t,s0) +/opt/ibm/db2/V9.(1|5)/cfg/db2ln -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/cfg/db2profile -- gen_context(root:object_r:db2_shell_script_t,s0) +/opt/ibm/db2/V9.(1|5)/cfg/db2rmln -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/das/bin/.* gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/das/dasprofile -- gen_context(root:object_r:db2_shell_script_t,s0) +/opt/ibm/db2/V9.(1|5)/das/lib/.*\.so(\..*)? gen_context(root:object_r:db2_shlib_t,s0) +/opt/ibm/db2/V9.(1|5)/das/function/.* -- gen_context(root:object_r:db2_shlib_t,s0) +/opt/ibm/db2/V9.(1|5)/dasfcn/.* -- gen_context(root:object_r:db2_shlib_t,s0) +/opt/ibm/db2/V9.(1|5)/ha/tsa/.* gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/function/.* gen_context(root:object_r:db2_shlib_t,s0) +/opt/ibm/db2/V9.(1|5)/install/db2ls -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/install/db2ls_exec -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/instance/.* gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/instance/common/.* gen_context(root:object_r:db2_file_t,s0) +/opt/ibm/db2/V9.(1|5)/instance/native/.* gen_context(root:object_r:db2_file_t,s0) +/opt/ibm/db2/V9.(1|5)/instance/native/install/db2help -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/instance/native/install/db2incpy -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/instance/native/install/db2iure -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/instance/native/install/db2_run_as -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/instance/native/install/qpmigrate -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/instance/native/install/qpsetup -- gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/lib(32|64)?/.* gen_context(root:object_r:db2_shlib_t,s0) +/opt/ibm/db2/V9.(1|5)/security(32|64)?/db2aud gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/security(32|64)?/db2chkau gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/security(32|64)?/db2ckpw gen_context(root:object_r:db2_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/security(32|64)?/db2flacc gen_context(root:object_r:db2adm_exec_t,s0) +/opt/ibm/db2/V9.(1|5)/security(32|64)?/plugin/IBM/client/.*\.so(\..*)? gen_context(root:object_r:db2_shlib_t,s0) +/opt/ibm/db2/V9.(1|5)/security(32|64)?/plugin/IBM/group/.*\.so(\..*)? gen_context(root:object_r:db2_shlib_t,s0) +/opt/ibm/db2/V9.(1|5)/security(32|64)?/plugin/IBM/server/.*\.so(\..*)? gen_context(root:object_r:db2_shlib_t,s0) + +# Override any of the above rules: directories (hence the -d) should be labeled +# db2_file_t instead of db2_exec_t +/opt/ibm/db2/V9.(1|5)(/.*)? -d gen_context(root:object_r:db2_file_t,s0) +/opt/ibm/db2/V9.(1|5)/java/.* gen_context(root:object_r:db2_java_t,s0) + diff --git a/selinux/RHEL5/db2.if b/selinux/RHEL5/db2.if new file mode 100644 index 0000000..27cd65a --- /dev/null +++ b/selinux/RHEL5/db2.if @@ -0,0 +1,53 @@ +################################################ +# +# Sample IBM DB2 Policy using Reference Policy syntax +# +# Sample IBM DB2 policy for SELinux +# +#

+# Give apps that load libdb2.so the necessary permissions +#

+#
+# +################################################ + +interface(`db2_application',` + gen_require(` + type db2_java_t; + type db2_shlib_t; + type db2_data_t; + type db2_file_t; + type db2_diag_t; + type db2_t; + ') + + can_exec($1, db2_java_t) + can_exec($1, db2_shlib_t) + r_dir_file($1, db2_data_t) + r_dir_file($1, db2_file_t) + rw_dir_file($1, db2_diag_t) + rw_dir_file($1, tmpfs_t) + + allow $1 db2_t:fd use; + allow $1 db2_t:msg { receive send }; + allow $1 db2_t:msgq rw_msgq_perms; + allow $1 db2_t:sem rw_sem_perms; + allow $1 db2_t:shm rw_shm_perms; +') + +################################################ +# +# Sample IBM DB2 policy for SELinux +# +#

+# Allow caller to execute DB2 shell scripts +# (e.g. dasprofile) +#

+#
+# +################################################ + +interface(`db2_exec_db2_shell_scripts',` + allow $1 db2_shell_script_t:file r_file_perms; + can_exec($1,db2_shell_script_t) +') diff --git a/selinux/RHEL5/db2.te b/selinux/RHEL5/db2.te new file mode 100644 index 0000000..35530ab --- /dev/null +++ b/selinux/RHEL5/db2.te @@ -0,0 +1,256 @@ +################################################ +# +# Sample IBM DB2 Policy using Reference Policy syntax +# +################################################ +policy_module(db2,1.1.0) + +gen_require(` + type inetd_t; + type nfs_t; + type node_t; + type rshd_t; + type rsh_port_t; + type telnetd_devpts_t; + type remote_login_t; + type rlogind_devpts_t; + type rlogind_t; + type rpm_t; + type rpm_exec_t; + type shadow_t; + type tmpfs_t; + type xdm_t; + ') + +# The DB2 domains frequently need the same allows, so create an internal +# macro to reduce repetition. + +define(`db2_helper_macro',` + gen_require(` + type init_t; + ') + + kernel_get_sysvipc_info($1) # Allow processes in domain to run ipcs + kernel_read_network_state($1) + kernel_read_kernel_sysctls($1) # Read generic kernel sysctls + kernel_sendrecv_unlabeled_packets($1) + + # DB2 uses shared libraries, uses the dynamic loader + libs_use_shared_libs($1) + libs_use_ld_so($1) + + # /etc/services entry for ibm-db2 port 523 + corenet_tcp_bind_reserved_port($1) + corenet_udp_bind_reserved_port($1) + + corenet_tcp_connect_smtp_port($1) + corenet_tcp_bind_inaddr_any_node($1) + corenet_udp_bind_inaddr_any_node($1) + + corecmd_exec_bin($1) # execute command in the callers domain + corecmd_exec_shell($1) + + unconfined_signull($1) # can send signull to the unconfined domain + unconfined_rw_pipes($1) + + files_getattr_tmp_dirs($1) + files_manage_all_files($1, -shadow_t) + files_manage_generic_locks($1) + files_manage_generic_tmp_files($1) + files_read_etc_files($1) + + miscfiles_read_localization($1) + + db2_exec_db2_shell_scripts($1) + + sysnet_dns_name_resolve($1) + + term_use_generic_ptys($1) + + # Allow execution of DB2 shared libraries, allow + # loading shared libraries with text relocations + allow $1 db2_shlib_t:file { execute execmod }; + allow $1 db2_exec_t:file execmod; + allow $1 nfs_t:file execmod; + + # Access to other processes in the same domain + allow $1 self:process { fork sigchld sigkill sigstop signull signal ptrace getpgid setpgid getcap setcap setrlimit execmem execstack }; + + # Various capabilities + allow $1 self:capability { chown dac_override setgid setuid ipc_lock ipc_owner sys_rawio sys_ptrace sys_admin sys_resource }; + + # Required by the PVP validation test suite + allow $1 tmpfs_t:filesystem getattr; + allow $1 xdm_t:shm create_shm_perms; + + # Access file descriptors, pipes and sockets created by processes + # in the same domain. + allow $1 self:fd use; + allow $1 self:fifo_file rw_file_perms; + allow $1 self:unix_dgram_socket create_socket_perms; + allow $1 self:unix_stream_socket create_stream_socket_perms; + + # Allow communications with processes running in the same domain + allow $1 self:unix_dgram_socket sendto; + allow $1 self:unix_stream_socket connectto; + + # Access SysV IPC objects created by process in the same domain + allow $1 self:shm create_shm_perms; + allow $1 self:sem create_sem_perms; + allow $1 self:msgq create_msgq_perms; + allow $1 self:msg all_msg_perms; + + # Allow communications with processes running in the unconfined domain + allow $1 unconfined_t:sem create_sem_perms; + allow $1 unconfined_t:shm create_shm_perms; + allow $1 unconfined_t:msgq create_msgq_perms; + allow $1 unlabeled_t:msgq create_msgq_perms; + + allow $1 unconfined_t:msg all_msg_perms; + + # Allow domain to create and use UDP and TCP sockets + allow $1 self:udp_socket create_socket_perms; + allow $1 self:tcp_socket create_stream_socket_perms; + + allow $1 self:netlink_route_socket r_netlink_socket_perms; + + # Allow processes in the domain to "use" /dev/pts/1 + allow $1 remote_login_t:fd use; + + # Allow processes in the domain to read and write to the console + allow $1 rlogind_devpts_t:chr_file rw_file_perms; + + # Need this to start DB2 from a telnet session + allow $1 telnetd_devpts_t:chr_file rw_file_perms; + + + # Need these for DFP + allow $1 inetd_t:fd use; + allow $1 inetd_t:tcp_socket rw_socket_perms; + allow $1 init_t:fd use; + allow $1 nfs_t:file {execute execute_no_trans}; + allow $1 node_t:tcp_socket node_bind; + allow $1 rsh_port_t:tcp_socket {name_connect node_bind}; + allow $1 rshd_t:fd use; + allow $1 unconfined_t:tcp_socket rw_socket_perms; + allow $1 unconfined_t:msgq create_msgq_perms; + allow $1 unconfined_t:msg {send receive}; + allow $1 rshd_t:fifo_file rw_file_perms; +') + +############################# +# Private type declarations +############################# +type db2adm_t; # DB2 engine and admin programs run in the db2adm_t domain. +type db2fm_t; # DB2 fault monitor runs as a daemon in its own domain. +type db2_t; # Other DB2 programs (CLP, DAS, CC, FS) run in the db2_t domain. + +type db2adm_exec_t; # Execute file of this type to transition to the db2adm_t domain +type db2fm_exec_t; # Execute file of this type to transition to the db2fm_t domain +type db2_exec_t; # Execute file of this type to transition to the db2_t domain + +type db2_data_t; # DB2 data files (containers, catalogs, etc) and the directories they live in +type db2_diag_t; # sqllib/db2dump directory and the files therein +type db2_file_t; # Catch-all for DB2 config, bnd, diag, msg, etc. files and directories +type db2_java_t; # DB2 java directory and files +type db2_shlib_t; # DB2 shared libraries +type db2_shell_script_t; # e.g. dasprofile +type db2_var_t; # The /var/db2 directory and files therein + +# Creates a domain for processes started by init, in this case db2fm +init_daemon_domain(db2fm_t, db2fm_exec_t) + +# Domain declarations for the following types +domain_type(db2adm_t) +domain_type(db2_t) + +# File type declarations +files_type(db2_data_t) +files_type(db2_diag_t) +files_type(db2_file_t) +files_type(db2_java_t) +files_type(db2_shlib_t) +files_type(db2_shell_script_t) +files_type(db2_var_t) + +# Make usable for lock files +files_lock_file(db2_file_t) + +# db2_adm_exec_t and db2_exec_t are entry points to their respective domains +domain_entry_file(db2adm_t, db2adm_exec_t) +domain_entry_file(db2_t, db2_exec_t) + +# Automatic transitions +domain_auto_trans(unconfined_t, db2adm_exec_t, db2adm_t) +domain_auto_trans(unconfined_t, db2_exec_t, db2_t) +domain_auto_trans(db2_t, db2adm_exec_t, db2adm_t) +domain_auto_trans(db2adm_t, db2_exec_t, db2_t) +domain_auto_trans(db2adm_t, rpm_exec_t, rpm_t) + +# Suppress domain transitions +allow db2adm_t db2_exec_t:file execute_no_trans; +allow db2adm_t db2adm_exec_t:file execute_no_trans; + +# Who else can execute db2 shell scripts +db2_exec_db2_shell_scripts(bin_t) + +############################################################## + +db2_helper_macro(db2_t) +db2_helper_macro(db2adm_t) + +############################################################## +# +# Unique permissions for db2adm_t +# +############################################################## + +kernel_sendrecv_unlabeled_association(db2adm_t) +kernel_rw_kernel_sysctl(db2adm_t) # the other domains don't need to write to sysctl +fs_getattr_xattr_fs(db2adm_t) # how full is the filesystem? +auth_read_shadow(db2adm_t) # db2sysc needs to be able to read /etc/shadow + +allow db2adm_t db2_t:fd use; +allow db2adm_t db2_t:fifo_file rw_file_perms; +allow db2adm_t db2_t:process sigchld; + +############################################################## +# +# Unique permissions for db2_t +# +############################################################## + +allow db2_t db2_exec_t:file execute_no_trans; + +allow db2_t db2adm_t:fd use; +allow db2_t db2adm_t:sem create_sem_perms; # need rw, +destroy for ipclean +allow db2_t db2adm_t:shm create_shm_perms; # need rw, +destroy for ipclean +allow db2_t db2adm_t:msgq create_msgq_perms; # need rw, +destroy for ipclean +allow db2_t db2adm_t:msg {send receive}; +allow db2_t db2adm_t:process sigchld; +allow db2_t db2adm_t:unix_stream_socket all_unix_stream_socket_perms; + +############################################################## +# +# These rules accomodate text relocation in Java and DB2 shared libraries. +# +############################################################## +allow unconfined_t db2_java_t:file execmod; +allow unconfined_t db2_shlib_t:file execmod; +allow unconfined_t ld_so_t:file execmod; +allow unconfined_t lib_t:file execmod; +allow unconfined_t self:process execheap; + +############################################################## +# +# db2fm (the fault monitor) needs these, else db2fmd will fail +# to start at bootup (db2fmd runs in the db2_t domain). +# +############################################################## +allow db2_t init_t:fd use; +allow db2_t init_t:fifo_file rw_file_perms; + +# Because the home directory is labeled db2_data_t, rlogin +# needs to be allowed to search for .rhosts +allow rlogind_t db2_data_t:dir search; + diff --git a/selinux/RHEL5/ibm_db2_semanage_das b/selinux/RHEL5/ibm_db2_semanage_das new file mode 100755 index 0000000..ddf9e8c --- /dev/null +++ b/selinux/RHEL5/ibm_db2_semanage_das @@ -0,0 +1,30 @@ +#!/bin/sh +# +if [ $# != 2 ] || [ \( $1 != "-a" \) -a \( $1 != "-d" \) ] +then + echo "" + echo "Usage: $0 OPTION DAS_USER_HOME_DIR" + echo "" + echo "Options:" + echo " -a Add SELinux file contexts in the given DAS user home directory" + echo " -d Delete SELinux file contexts from the given DAS user home directory" + echo "" + echo "Examples:" + echo " $0 -a /home/dasusr1" + echo " $0 -d /home/dasusr1" + echo "" + exit +fi + +if [ ! -d $2 ] +then + echo "Directory $2 does not exist" + exit +fi + +semanage fcontext $1 --ftype "" --seuser user_u -t db2_file_t "$2/das(/.*)?" +semanage fcontext $1 --ftype -- --seuser user_u -t db2_exec_t "$2/das/adm/.*" +semanage fcontext $1 --ftype -- --seuser user_u -t db2_shell_script_t "$2/das/dasprofile" +semanage fcontext $1 --ftype -- --seuser user_u -t db2_shell_script_t "$2/das/userprofile" + +restorecon -R $2 diff --git a/selinux/RHEL5/ibm_db2_semanage_db2inst b/selinux/RHEL5/ibm_db2_semanage_db2inst new file mode 100755 index 0000000..845bdd4 --- /dev/null +++ b/selinux/RHEL5/ibm_db2_semanage_db2inst @@ -0,0 +1,109 @@ +#!/bin/sh + +if [ $# != 3 ] || [ \( $1 != "-a" \) -a \( $1 != "-d" \) ] +then + echo "" + echo "Usage: $0 OPTION DB2_INSTANCE_NAME DB2_INSTANCE_HOME_DIR" + echo "" + echo "Options:" + echo " -a Add SELinux file contexts in the given DB2 instance's home directory" + echo " -d Delete SELinux file contexts from the given DB2 instance's home directory" + echo "" + echo "Examples:" + echo " $0 -a db2inst1 /home/db2inst1" + echo " $0 -d db2inst1 /home/db2inst1" + echo "" + exit +fi + +if [ ! -d $3 ] +then + echo "Error: directory $3 does not exist" + exit +fi + + +# Use semange to set file contexts of DB2 directories and files in /home to +# override the rules in targeted/contexts/files/file_contexts.homedirs +# +# Subsequent rules override preceeding ones, otherwise this list is ordered by directory or file name +# + +# Label the instance's home directory for DB2 data +semanage fcontext $1 --ftype "" --seuser user_u -t db2_data_t "$3" + +# Label the instance's data directory +semanage fcontext $1 --ftype "" --seuser user_u -t db2_data_t "$3/$2(/.*)?" + +# Routine that allows us to apply a label to both files and symbolic links for the +# same file +semanage_file_and_symlink() +{ + semanage fcontext "$1" --ftype -- --seuser user_u -t "$2" "$3" + semanage fcontext "$1" --ftype -l --seuser user_u -t "$2" "$3" +} + +# Routine that allows us to apply a label to both directories and symbolic links for the +# same directory +semanage_directory_and_symlink() +{ + semanage fcontext "$1" --ftype -d --seuser user_u -t "$2" "$3" + semanage fcontext "$1" --ftype -l --seuser user_u -t "$2" "$3" +} + + +## Label the instance's sqllib directory +semanage fcontext $1 --ftype "" --seuser user_u -t db2_file_t "$3/sqllib(/.*)?" + +semanage_file_and_symlink "$1" "db2adm_exec_t" "$3/sqllib/adm/.*" +semanage_file_and_symlink "$1" "db2_file_t" "$3/sqllib/adm/ITLMready.properties" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/adsm/.*" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/bin/.*" +semanage_file_and_symlink "$1" "db2_file_t" "$3/sqllib/bin/db2refs.ndx" +semanage_file_and_symlink "$1" "db2_file_t" "$3/sqllib/bin/MQLInstall.sql" +semanage_file_and_symlink "$1" "db2_file_t" "$3/sqllib/bin/readme.pct" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/cfg/db2ln" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/cfg/db2rmln" +semanage_file_and_symlink "$1" "db2_shlib_t" "$3/sqllib/dasfcn/.*" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/ha/tsa/.*" +semanage_file_and_symlink "$1" "db2_shlib_t" "$3/sqllib/function/.*" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/install/db2ls" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/install/db2ls_exec" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/instance/.*" +semanage_file_and_symlink "$1" "db2_file_t" "$3/sqllib/instance/common/.*" +semanage_file_and_symlink "$1" "db2_file_t" "$3/sqllib/instance/native/.*" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/instance/native/install/db2help" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/instance/native/install/db2incpy" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/instance/native/install/db2iure" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/instance/native/install/db2_run_as" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/instance/native/install/qpmigrate" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/instance/native/install/qpsetup" +semanage_file_and_symlink "$1" "db2_shlib_t" "$3/sqllib/lib(32|64)?/.*" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/security(32|64)?/db2aud" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/security(32|64)?/db2chkau" +semanage_file_and_symlink "$1" "db2_exec_t" "$3/sqllib/security(32|64)?/db2ckpw" +semanage_file_and_symlink "$1" "db2adm_exec_t" "$3/sqllib/security(32|64)?/db2flacc" +semanage_file_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/client/(.*)?" +semanage_file_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/group/(.*)?" +semanage_file_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/server/(.*)?" +semanage_file_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/IBM/client/(.*)?" +semanage_file_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/IBM/group/(.*)?" +semanage_file_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/IBM/server/(.*)?" + +semanage fcontext $1 --ftype "" --seuser user_u -t db2_diag_t "$3/sqllib/db2dump(/.*)?" + +# Label directories +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/function" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/function/unfenced" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/lib(32|64)?" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/client" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/group" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/server" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/IBM" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/IBM/client" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/IBM/group" +semanage_directory_and_symlink "$1" "db2_shlib_t" "$3/sqllib/security(32|64)?/plugin/IBM/server" + +# Run restorecon to apply the SELinux labels +restorecon -R $3 diff --git a/sql_statements/README b/sql_statements/README new file mode 100644 index 0000000..bf62e37 --- /dev/null +++ b/sql_statements/README @@ -0,0 +1,25 @@ +***************************************************************************** +* +* README for SQL Statement +* +* These sample scripts demonstrate SQL Statements specific to DDL and DML. +* +* +***************************************************************************** +* Documentation +* +* For information on using SQL statements, see the SQL Reference. +* +* For the latest information on programming, building, and running DB2 +* applications, visit the DB2 application development website: +* http://www.software.ibm.com/data/db2/udb/ad +***************************************************************************** +* +***************************************************************************** +* README - this file! +***************************************************************************** +* +* This README will contain the SQL Statements specific to DML and DDL. +* These samples will be made available in the future releases. +* +***************************************************************************** diff --git a/sqlpl/NestedSP.java b/sqlpl/NestedSP.java new file mode 100644 index 0000000..f2eef01 --- /dev/null +++ b/sqlpl/NestedSP.java @@ -0,0 +1,230 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: NestedSP.java +// +// SAMPLE: Client application for invoking nested stored procedures +// +// This sample calls the method callNestedSP() which invokes the +// stored procedures created in nestedsp.db2. +// +// The function callNestSP() demonstrates 3 levels of nesting. +// It first calls the stored procedure OUT_AVERAGE which calls the +// stored procedure OUT_MEDIAN, which then calls the stored procedure +// MAX_SALARY. +// The output consists of the following information in order: +// (1) The average salary of the EMPLOYEE table +// (2) The median salary of the EMPLOYEE table +// (3) The maximum salary of the EMPLOYEE table +// (4) a list of employees who make more than average salary +// (5) a list of employees who make less than average salary. +// +// To run this sample, perform the following steps: +// (1) create and populate the SAMPLE database by running the command: +// db2sampl +// (2) connect to sample database with: +// db2 connect to sample +// (3) register the stored procedures using the nestedsp.db2 script: +// db2 -td@ -vf nestedsp.db2 +// (4) compile NestedSP with: +// (n)make NestedSP +// (5) run NestedSP with: +// java NestedSP +// (6) to drop the stored procedures run the nestedspdrop.db2 script: +// db2 -td@ -vf nestedspdrop.db2 +// +// NOTES: The CLASSPATH and shared library path environment variables +// must be set, as for any JDBC application +// +// OUTPUT FILE: NestedSP.out (available in the online documentation) +// +//*************************************************************************** +// For more information about the sample programs, see the README file. +// +// For information on creating SQL procedures and developing JDBC applications, +// see the Application Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, building, and running DB2 +// applications, visit the DB2 application development website: +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** + +import java.sql.*; + +class NestedSP +{ + + static + { + try + { + System.out.println(); + System.out.println("JAVA STORED PROCEDURE SAMPLE"); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + catch (Exception e) + { + System.out.println("\nError loading DB2 Driver...\n"); + e.printStackTrace(); + } + } + + public static void main(String argv[]) + { + Db db = null; + + try + { + // process command line arguments for database connection + db = new Db(argv); + + System.out.print("THIS SAMPLE SHOWS HOW NESTED STORED PROCEDURES WORK."); + System.out.println(); + + // connect to the 'sample' database + db.connect(); + + // calling NestedSP function + callNestedSP(db.con); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + finally + { + try + { + db.disconnect(); + } + catch( Exception e ) + { + } + } + } // end main + + + public static void callNestedSP(Connection con) + { + ResultSet rs = null; + CallableStatement callStmt = null; + + try + { + double outMedian = 0.0; + double outAverage = 0.0; + double outMaxSalary = 0.0; + + String procName = "OUT_AVERAGE"; + String sql = "CALL " + procName + "(?, ?, ?)"; + callStmt = con.prepareCall(sql); + + // register the output parameter + callStmt.registerOutParameter (1, Types.DOUBLE); + callStmt.registerOutParameter (2, Types.DOUBLE); + callStmt.registerOutParameter (3, Types.DOUBLE); + + // call the stored procedure + System.out.println ("\nCall stored procedure named " + procName); + callStmt.execute(); + + // retrieve output parameters + outAverage = callStmt.getDouble(1); + outMedian = callStmt.getDouble(2); + outMaxSalary = callStmt.getDouble(3); + + System.out.println(procName + " completed successfully"); + System.out.println(); + System.out.println ("Average salary returned from " + procName + " = " + + outAverage); + System.out.println(); + System.out.println ("Median salary returned from OUT_MEDAIN = " + + outMedian); + System.out.println(); + System.out.println ("Max salary returned from MAX_SALARY = " + + outMaxSalary); + + System.out.println(); + System.out.println("Result set 1: Employees who make more than " + + outAverage); + // get the first result set + rs = callStmt.getResultSet(); + fetchAll(rs); + + System.out.println("\nResult set 2: Employees who make less than " + + outAverage); + // get the second result set + callStmt.getMoreResults(); + rs = callStmt.getResultSet(); + fetchAll(rs); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + + } + finally + { + // cleanup - close the result set and the statement + try + { + rs.close(); + } catch (Exception e) + { + } + try + { + callStmt.close(); + } catch (Exception e) + { + } + } + } + + //method fetchAll returns all rows from result set + public static void fetchAll( ResultSet rs) throws SQLException + { + System.out.println( + "============================================================="); + ResultSetMetaData stmtInfo = rs.getMetaData(); + int numOfColumns = stmtInfo.getColumnCount(); + // Do not need to print the last column + int numColumns = numOfColumns - 1; + int r = 0; + + while( rs.next() ) + { + r++; + System.out.print("Row: " + r + ": "); + for( int i=1; i <= numColumns; i++ ) + { + System.out.print(rs.getString(i)); + if( i != numColumns ) System.out.print(" , "); + } + System.out.println(""); + } + } + +} + diff --git a/sqlpl/README b/sqlpl/README new file mode 100644 index 0000000..576cb67 --- /dev/null +++ b/sqlpl/README @@ -0,0 +1,489 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for SQL Procedures Samples +* +* For windows, the \sqllib\samples\sqlpl directory contains +* this README file. +* +* For unix, the /sqllib/samples/sqlpl directory contains +* this README file. +* +* This README describes how to build and run stored procedure sample code +* for DB2 9.7. The DB2 9.7 stored procedure samples are located in the +* \sqllib\samples\sqlpl directory for windows platform +* and /sqllib/samples/sqlpl for unix based platforms. +* where is the location of DB2 9.7 on your hard drive. The +* default location for is C:\Program Files\IBM for windows +* and $HOME for unix based platform. +* +* The following table lists sample programs that demonstrate SQL procedures. +* +* Files with a ".db2" file extension are DB2 Command Line Processer (CLP) +* scripts. These scripts issue CREATE PROCEDURE statements that create +* stored procedure on the database server. +* +* The stored procedures created by "spserver.db2" can be called by client +* applications created from sample files in other sample directories (see +* the "spserver.db2" source file for details). All other CLP scripts have +* a corresponding client application source file in the sqlpl directory. +* +* The client application for nested stored procedure "nestedsp.db2" is +* "NestedSP.java", which is a client application written using JDBC in +* the JAVA programming language. +* +* The client application for "rsultset.db2" is "rsultset.c", which is a +* client application written using CLI in the C programming language. +* +* The other CLP scripts have a corresponding client application file with +* a ".sqc" file extension, indicating that they use embedded SQL in the +* C programming language. +* +* NOTE: The JDBC driver used in "NestedSP.java" is the legacy JDBC Type 2 +* driver. You may modify it to use different DB2 JDBC drivers, but +* be advised that a 64-bit instance of DB2 for Linux on AMD64 does +* not support the DB2 Universal JDBC driver's Type 2 connectivity. +* All other DB2 JDBC drivers are supported. The same is true for the +* "SpClient.java" file mentioned in the comments in the "spserver.db2" +* file. +* +* WARNING: Some of these samples will change your database or database +* manager's configuration. Execute the samples against a test +* database only, such as the DB2 SAMPLE database. +* +****************************************************************************** +* +* Prepare your DB2 sample development environment +* +* On Windows steps 2 to 4 should be run in a DB2 Command Window. +* The DB2 Command Window is needed to execute the db2 specific commands. +* Listed below is how to opening the DB2 Command Window: +* +* o From the Start Menu click Start --> Programs --> IBM DB2 --> +* --> Command Line Tools --> Command Window +* +* This Opens the CLP-enabled DB2 window, and initializes the DB2 command line +* environment. Issuing this command is equivalent to clicking the DB2 +* Command Window as above. +* +* 1) Copy the files in \sqllib\samples\sqlpl\* (for +* windows platform) or /sqllib/samples/sqlpl/* +* (for UNIX based platform) to your working directory and ensure that +* directory has write permission. +* +* 2) Start the Database Manager with the following command: +* db2start +* +* 3) Create the sample database with the following command: +* db2sampl +* +* 4) Connect to the database with the following command: +* db2 "connect to sample" +* +* 5) cd to the directory containing the files copied in step 1. +* +******************************************************************************/ +* +* Building DB2 Stored Procedure Samples +* +* Building Stored Procedure +* +* To run the SQL procedure CLP scripts, perform the following steps: +* 1. Connect to the database +* 2. Issue the following command at the CLP: +* +* db2 -td@ -vf +* +* For example, to issue the CREATE PROCEDURE statement contained in the +* "nestif.db2" CLP script, issue the following command: +* +* db2 -td@ -vf nestif.db2 +* +* Building Stored Procedure Client applications. +* +* There are two ways to build DB2 stored procedure client : using a nmake +* utility for windows(make utility for unix based platform) or using +* build files. +* +* o To build client application using the nmake utility for windows see +* 'BUILDING CLIENT APPLICATION USING nmake UTILITY on WINDOWS'. +* o To build client application using the make utility for unix see +* 'BUILDING CLIENT APPLICATION USING make UTILITY on UNIX'. +* o To build client application using the build files or when you do not +* have a compatible nmake utility see 'BUILDING CLIENT +* APPLICATION USING BUILD FILES'. +* +****************************************************************************** +* +* *** BUILDING CLIENT APPLICATION USING nmake UTILITY on WINDOWS *** +* +* +* If you have a compatible nmake utility on your system, you +* can use the makefile provided. Such a nmake utility may be +* provided by another language compiler.Modify the PATH +* variable to include the directory containing the nmake +* utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'nmake' command in your working +* directory: +* +* nmake - Builds the program designated by +* +* nmake all - Builds the all the supplied sample programs +* +* nmake clean - Erases intermediate files +* nmake cleanall - Erases all files produced in the build process, +* except the original source files +* +****************************************************************************** +* +* *** BUILDING CLIENT APPLICATION USING make UTILITY on UNIX *** +* +* If you have a compatible make utility on your system, you +* can use the makefile provided. Modify the PATH +* variable to include the directory containing the make +* utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'make' command in your working +* directory: +* +* make - Builds the program designated by +* +* make all - Builds the all the supplied sample programs +* +* make clean - Erases intermediate files +* make cleanall - Erases all files produced in the build process, +* except the original source files +* +****************************************************************************** +* +* *** BUILDING CLIENT APPLICATION USING BUILD FILES *** +* +* For building CLI and C client application, use the build file provided. +* Run the following command to make the client application +* bldapp +* where is the name of +* the client application without extension. +* +* For building JAVA client application, use the java bytecode compiler to +* compile the application. +* Util.java has utility classes which are required to compile the java +* client application. Compile the Util.java to generate required classes. +* javac Util.java +* +* Run the following command to make the client application +* javac +* where is the name of +* the client application. +* +****************************************************************************** +* +* Common file Descriptions +* +* The following are the common files for SQL Procedures samples. For more +* information on these files, refer to the program source files. +* +****************************************************************************** +* +* Common files +* +* makefile - Builds the supplied sample programs in the "sqlpl" +* samples directory. +* README - Lists and describes, at a high-level, all files in the +* "sqlpl" samples directory. (This file). +* +****************************************************************************** +* +* BUILD Files for Windows +* +* bldapp.bat - Batch file for compiling embedded C applications +* with the Microsoft Visual C compiler. Use this script to +* compile source files in this directory that have a ".sqc" +* file extension. +* bldcli.bat - Batch file for compiling applications with +* the Microsoft Visual C compiler. Use this batch file to +* compile source files in this directory that have a +* ".c" file extension. +* embprep.bat - Batch file to precompile and bind C sample programs +* that contain embedded SQL. +* +***************************************************************************** +* +* BUILD Files for UNIX +* +* bldapp - Script file for compiling embedded C applications. +* Use this script to compile source files in this directory +* that have a ".sqc" file extension. +* bldcli - Script file for compiling applications. Use +* this script to compile source files in this directory that +* have a ".c" file extension. +* embprep - Script file to precompile and bind C sample +* programs that contain embedded SQL. +* +***************************************************************************** +* +* OTHER +* +* utilapi.c - Utility functions used by DB2 API samples. +* utilapi.h - Header file for utilapi.h. +* utilcli.c - Utility functions used by samples. +* utilcli.h - Header file for utilcli.c. +* utilemb.sqc - Utility functions used by embedded SQL samples. +* utilemb.h - Header file for utilemb.sqc. +* +***************************************************************************** +* +* SQL Procedures sample descriptions +* +* The following are the SQL Procedures sample files included with DB2. +* For more information on these files, refer to program source files. +* +* (CLI) - A client application, which calls a stored procedure or +* declares and calls a user-defined function on the server. +* +****************************************************************************** +* +* COMMAND LINE PROCESSOR SQL Procedures Samples +* +* basecase.db2 - The UPDATE_SALARY procedure raises the salary of an +* employee identified by the "empno" IN parameter in the +* "staff" table of the "sample" database. The procedure +* determines the raise according to a CASE statement +* that uses the "rating" IN parameter. +* To call this SQL procedure from the CLP, +* issue the following statement: +* db2 "CALL update_salary ('000100', 1)" +* +* basecase.sqc - Calls the UPDATE_SALARY procedure. (CLI) +* +* baseif.db2 - The UPDATE_SALARY_IF procedure raises the salary of an +* employee identified by the "empno" IN parameter in the +* "staff" table of the "sample" database. The procedure +* determines the raise according to an IF statement that +* uses the "rating" IN parameter. +* To call this SQL procedure from the CLP, +* issue the following statement: +* db2 "CALL update_salary_if ('000100', 1)" +* +* baseif.sqc - Calls the UPDATE_SALARY_IF procedure. (CLI) +* +* dynamic.db2 - The CREATE_DEPT_TABLE procedure uses dynamic DDL to +* create a new table. The name of the table is based on +* the value of the IN parameter to the procedure. +* To call this SQL procedure from the CLP, +* issue the following statement: +* db2 "CALL create_dept_table ('D11', ?)" +* +* dynamic.sqc - Calls the CREATE_DEPT_TABLE procedure. (CLI) +* +* iterate.db2 - The ITERATOR procedure uses a FETCH loop to retrieve +* data from the "department" table. If the value of the +* "deptno" column is not 'D11', modified data is inserted +* into the "department" table. If the value of the +* "deptno" column is 'D11', an ITERATE statement passes +* the flow of control back to the beginning of the LOOP +* statement. +* To call this SQL procedure from the CLP, +* issue the following statement: +* db2 "CALL iterator ()" +* +* iterate.sqc - Calls the ITERATOR procedure. (CLI) +* +* leave.db2 - The LEAVE_LOOP procedure counts the number of FETCH +* operations performed in a LOOP statement before the +* "not_found" condition handler invokes a LEAVE statement. +* The LEAVE statement causes the flow of control to exit +* the loop and complete the stored procedure. +* To call this SQL procedure from the CLP, +* issue the following statement: +* db2 "CALL leave_loop (?)" +* +* leave.sqc - Calls the LEAVE_LOOP procedure. (CLI) +* +* loop.db2 - The LOOP_UNTIL_SPACE procedure counts the number of +* FETCH operations performed in a LOOP statement until +* the cursor retrieves a row with a space (' ') value +* for column "midinit". The loop statement causes the +* flow of control to exit the loop and complete the +* stored procedure. +* To call this SQL procedure from the CLP, +* issue the following statement: +* db2 "CALL loop_until_space (?)" +* +* loop.sqc - Calls the LOOP_UNTIL_SPACE procedure. (CLI) +* +* nestcase.db2 - The BUMP_SALARY procedure uses nested CASE statements +* to raise the salaries of employees in a department +* identified by the dept IN parameter from the "staff" +* table of the "sample" database. +* To call this SQL procedure from the CLP, +* issue the following statement: +* db2 "CALL bump_salary (51)" +* +* nestcase.sqc - Calls the BUMP_SALARY procedure. (CLI) +* +* nestedsp.db2 - This CLP script contains three stored procedures. +* They are OUT_AVERAGE, OUT_MEDIAN and MAX_SALARY. +* They are nested, where OUT_AVERAGE calls OUT_MEDIAN +* and OUT_MEDIAN calls MAX_SALARY. +* To call these SQL procedures from the CLP, +* issue the following statement: +* db2 "CALL out_average (?,?,?,?,?)" +* +* nestedspdrop.db2- This CLP script drops the three stored procedures +* created by nestedsp.db2. +* +* NestedSP.java - Calls the OUT_AVERAGE procedure. (CLI) +* +* nestif.db2 - The BUMP_SALARY_IF procedure uses nested IF statements +* to raise the salaries of employees in a department +* identified by the dept IN parameter from the "staff" +* table of the "sample" database. +* To call this SQL procedure from the CLP, +* issue the following statement: +* db2 "CALL bump_salary_if (20)" +* +* nestif.sqc - Calls the BUMP_SALARY_IF procedure. (CLI) +* +* repeat.db2 - The REPEAT_STMT procedure counts the number of FETCH +* operations performed in a repeat statement until the +* cursor can retrieve no more rows. The condition handler +* causes the flow of control to exit the repeat loop and +* complete the stored procedure. +* To call this SQL procedure from the CLP, +* issue the following statement: +* db2 "CALL repeat_stmt (?)" +* +* repeat.sqc - Calls the REPEAT_STMT procedure. (CLI) +* +* rsultset.db2 - The MEDIAN_RESULT_SET procedure calculates the median +* salary of employees from the "staff" table of +* the "sample" database. The median value is assigned +* to the salary OUT parameter and returned to the +* "rsultset" client. The procedure opens two +* WITH RETURN cursors to return result sets of the +* employees with a salary greater than the median and +* employees with a salary less than the median salary. +* The procedure returns the result sets to the client. +* To call this SQL procedure from the CLP, issue the +* following statement: +* db2 "CALL median_result_set (?)" +* +* rsultset.c - Calls the MEDIAN_RESULT_SET procedure, (CLI) +* displays the median salary, then displays +* the result set generated by the SQL +* procedure. This client is written using +* the API, which can accept result sets. +* +* spserver.db2 - The SQL procedures in this CLP script demonstrate basic +* error-handling, nested stored procedure calls, and +* returning result sets to the client application or +* the calling application. This script contains the +* following SQL procedures: +* o OUT_LANGUAGE +* o OUT_PARAM +* o IN_PARAMS +* o INOUT_PARAM +* o ONE_RESULT_SET +* o RESULT_SET_CALLER +* o TWO_RESULT_SETS +* o ALL_DATA_TYPES To call these SQL procedures, +* you can use the "spclient" application in the C, +* CLI, and CPP samples directories, or the "SpClient" +* application in the Java/JDBC and Java/SQLj +* samples directories. +* +* tbfn.db2 - The tables and SQL functions in this CLP script are used +* to illustrate various ways of invoking a table function +* that MODIFIES SQL DATA from within a SELECT statement. +* +* tbfnuse.db2 - This script invokes three table functions, updateInv, +* sal_by_dept, and update_salary. It displays the data +* in the tables related to this sample before and after +* the invocations to the table functions. +* +* tbselcreate.db2 - The tables and SQL procedure BUY_COMPANY in this CLP +* script are used to illustrate various ways of using a +* SELECT statement with a data change statement as the +* table-reference in the FROM clause. Data change +* statements include INSERT, UPDATE, DELETE, MERGE. +* Referencing one of these in a SELECT statement +* (also called SELECT FROM a data change statement) +* is useful for retrieving column values of just inserted +* rows (ie. when a column is a generated column), or for +* retrieving the old and new values of an updated column +* without having to use two statements, and more... +* The procedure BUY_COMPANY encapsulates some examples of +* useful applications of this statement. +* To call this SQL procedures, you can use the +* "tbsel" application in this directory. +* +* tbseldrop.db2 - The SQL statements in this script drop the tables and the +* procedure created script tbselcreate.db2 +* +* tbsel.sqc - Client application that CALLs the (CLI) +* BUY_COMPANY SQL procedure, displays the +* data in the tables related to this sample +* before and after the CALL to the SQL procedure. +* +* whiles.db2 - The DEPT_MEDIAN procedure obtains the median salary of +* employees in a department identified by the "dept" IN +* parameter from the "staff" table of the "sample" database. +* The median value is assigned to the salary OUT parameter +* and returned to the "whiles" client. The whiles client +* then prints the median salary. +* To call this SQL procedure from the CLP, issue +* the following statement: +* db2 "CALL dept_median (51, ?)" +* +* whiles.sqc - Calls the DEPT_MEDIAN procedure. (CLI) +* +* arrays_sqlpl.db2- How to use ARRAY data type in SQL stored procedure. +* For java client for this sample please refer to +* sqllib/samples/java/jdbc directory +* +* array_stack.db2 - How to use ARRAY data type in SQL stored procedure +* to implement a stack operations. +* For java client for this sample please refer to +* sqllib/samples/java/jdbc directory +* +* modules.db2 - This sample demonstrates: +* 1. Creation of modules and module objects +* 2. Creation and usage of row data types, boolean data type, +* associative arrays and array of rows +* 3. Creation and usage of strongly-typed, weakly-typed and +* parameterized cursors +* 4. Full SQL PL support for UDFs, triggers and compiled +* compound statements +* 5. Support for INOUT and OUT parameters in compiled UDFs +* 6. Support for compiled UDFs and triggers that contain +* assignment to global variables +* +*defaultparam.db2 - How to use DEFAULT values in procedure. +******************************************************************************** diff --git a/sqlpl/Util.java b/sqlpl/Util.java new file mode 100644 index 0000000..954b84b --- /dev/null +++ b/sqlpl/Util.java @@ -0,0 +1,340 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Util.java +// +// SAMPLE: Utilities for JDBC sample programs +// +// This sample has 3 classes: +// 1. Data - Display the data in the table +// 2. Db - Connect to or disconnect from the 'sample' database +// 3. JdbcException - Handle Java Exceptions +// +// JAVA 2 CLASSES USED: +// DriverManager +// Connection +// Exception +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.util.*; +import java.sql.*; +import java.math.BigDecimal; + +class Data +{ + public static String format(String strData, int finalLen) throws Exception + { + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = strData; + for (int i = strData.length(); i < finalLen; i++) + { + finalStr = finalStr + " "; + } + } + return (finalStr); + } // format(String, int) + + public static String format(int intData, int finalLen) throws Exception + { + String strData = String.valueOf(intData); + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + return (finalStr); + } // format(int, int) + + public static String format(Integer integerData, int finalLen) + throws Exception + { + int intData; + String finalStr; + + intData = integerData.intValue(); + finalStr = format(intData, finalLen); + + return (finalStr); + } // format(Integer, int) + + public static String format(double doubData, int precision, int scale) + throws Exception + { + BigDecimal decData = new BigDecimal(doubData); + decData = decData.setScale(scale, BigDecimal.ROUND_HALF_EVEN); + String strData = decData.toString(); + + // prepare the final string + int finalLen = precision + 1; + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + + return (finalStr); + } // format(double, int, int) + + public static String format(BigDecimal decData, int precision, int scale) + throws Exception + { + decData = decData.setScale(scale, BigDecimal.ROUND_HALF_EVEN); + String strData = decData.toString(); + + // prepare the final string + int finalLen = precision + 1; + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + + return (finalStr); + } // format(BigDecimal, int, int) + + public static String format(Double doubleData, int precision, int scale) + throws Exception + { + double doubData; + String finalStr; + + doubData = doubleData.doubleValue(); + return (format(doubData, precision, scale)); + } // format(Double, int, int) +} // Data + +class Db +{ + public String alias; + public String server; + public int portNumber = -1; // < 0 use universal type 2 connection + // > 0 use universal type 4 connection + public String userId; + public String password; + public Connection con = null; + + public Db() + { + } + + public Db(String argv[]) throws Exception + { + if( argv.length > 5 || + ( argv.length == 1 && + ( argv[0].equals( "?" ) || + argv[0].equals( "-?" ) || + argv[0].equals( "/?" ) || + argv[0].equalsIgnoreCase( "-h" ) || + argv[0].equalsIgnoreCase( "/h" ) || + argv[0].equalsIgnoreCase( "-help" ) || + argv[0].equalsIgnoreCase( "/help" ) ) ) ) + { + throw new Exception( + "Usage: prog_name [dbAlias] [userId passwd] (use universal JDBC type 2 driver)\n" + + " prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)" ); + } + + switch (argv.length) + { + case 0: // Type 2, use all defaults + alias = "sample"; + userId = ""; + password = ""; + break; + case 1: // Type 2, dbAlias specified + alias = argv[0]; + userId = ""; + password = ""; + break; + case 2: // Type 2, userId & passwd specified + alias = "sample"; + userId = argv[0]; + password = argv[1]; + break; + case 3: // Type 2, dbAlias, userId & passwd specified + alias = argv[0]; + userId = argv[1]; + password = argv[2]; + break; + case 4: // Type 4, use default dbAlias + alias = "sample"; + server = argv[0]; + portNumber = Integer.valueOf( argv[1] ).intValue(); + userId = argv[2]; + password = argv[3]; + break; + case 5: // Type 4, everything specified + alias = argv[0]; + server = argv[1]; + portNumber = Integer.valueOf( argv[2] ).intValue(); + userId = argv[3]; + password = argv[4]; + break; + } + } // Db Constructor + + public Connection connect() throws Exception + { + String url = null; + + // In Partitioned Database environment, set this to the node number + // to which you wish to connect (leave as "0" in non-Partitioned Database environment) + String nodeNumber = "0"; + + Properties props = new Properties(); + + if ( portNumber < 0 ) + { + url = "jdbc:db2:" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 2 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + else + { + url = "jdbc:db2://" + server + ":" + portNumber + "/" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 4 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + + if( null != userId ) + { + props.setProperty("user", userId); + props.setProperty("password", password); + } + + props.setProperty("CONNECTNODE", nodeNumber); + + con = DriverManager.getConnection( url, props ); + + // enable transactions + con.setAutoCommit(false); + return con; + } // connect + + public void disconnect() throws Exception + { + System.out.println(); + System.out.println(" Disconnect from '" + alias + "' database."); + + // makes all changes made since the previous commit/rollback permanent + // and releases any database locks currrently held by the Connection. + con.commit(); + + // immediately disconnects from database and releases JDBC resources + con.close(); + } // disconnect +} // Db + +class JdbcException extends Exception +{ + Connection conn; + + public JdbcException(Exception e) + { + super(e.getMessage()); + conn = null; + } + + public JdbcException(Exception e, Connection con) + { + super(e.getMessage()); + conn = con; + } + + public void handle() + { + System.out.println(getMessage()); + System.out.println(); + + if (conn != null) + { + try + { + System.out.println("--Rollback the transaction-----"); + conn.rollback(); + System.out.println(" Rollback done!"); + } + catch (Exception e) + { + }; + } + } // handle + + public void handleExpectedErr() + { + System.out.println(); + System.out.println( + "**************** Expected Error ******************\n"); + System.out.println(getMessage()); + System.out.println( + "**************************************************"); + } // handleExpectedError +} // JdbcException + diff --git a/sqlpl/array_stack.db2 b/sqlpl/array_stack.db2 new file mode 100644 index 0000000..150ff06 --- /dev/null +++ b/sqlpl/array_stack.db2 @@ -0,0 +1,203 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: array_stack.db2 +-- +-- PURPOSE: To demonstrate the new ARRAY type and functions CARDINALITY, +-- TRIM_ARRAY and UNNEST. +-- +-- USAGE SCENARIO: The Sample will show use of new ARRAY type in +-- implementation of Stack using stored procedures. A Stack follows last in +-- first out strategy to insert and retrieve values. This sample implements +-- methods to push, pop and select the top value from the Stack. Stacks can +-- be used to store logs for different operations of an application. These +-- logs can later be written to disk or destroyed when the application is +-- closed. Stacks can also be used to store intermediate results while solving +-- complex mathematical expressions. +-- +-- PREREQUISITE: NONE +-- +-- EXECUTION: db2 -td@ -vf array_stack.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUT: Creation of object of Array type ,int_stack, in database. +-- Stack values are displayed along with the values returned by pop +-- and top methods. +-- +-- OUTPUT FILE: arrays_sqlpl.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- SELECT +-- DROP +-- CALL +-- CREATE PROCEDURE +-- +-- FUNCTIONS USED: +-- CARDINALITY +-- TRIM_ARRAY +-- UNNEST +-- +--------------------------------------------------------------------------- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- +-------------------------------------------------------------------------- +-- +-- SAMPLE DESCRIPTION +-- +-------------------------------------------------------------------------- +-- +--1. Create the ARRAY type to implement the stack. +--2. Create the procedure to push a value in the stack. +--3. Create the procedure to pop/retrieve the value from the stack. +--4. Create the procedure to select the topmost value from the stack. +--5. Create a procedure to return all the stack values as a result set. +--6. Create procedure to show case the stack functionalities. This +-- stored procedure will do the following +-- 1. Call "push" stored procedure 4 times with values 100,200,300 +-- and 400. +-- 2. Call the "pop" stored procedure to retrieve the topmost stack +-- value. +-- 3. Call the "top" stored procedure to select the topmost stack +-- value. +-- 4. Call the "stack_2_resultset" store procedure to select the +-- stack values as a result set. +--7. Call the "use_stack" store procedure. +------------------------------------------------------------------------- + +-- Connect to the database +CONNECT TO sample@ + +-- Drop the database objects if already exists. +DROP PROCEDURE push @ +DROP PROCEDURE top @ +DROP PROCEDURE pop @ +DROP PROCEDURE stack_2_resultset @ +DROP PROCEDURE use_stack @ +DROP TYPE int_stack @ + +---------------------------------------------------------------------------- +-- +-- 1. Create an ARRAY type to implement a stack. +-- +----------------------------------------------------------------------------- + +CREATE TYPE int_stack AS INTEGER ARRAY[] @ + +---------------------------------------------------------------------------- +-- +-- 2. Create the procedure to push a value in the stack. +-- +----------------------------------------------------------------------------- + +-- Create a stored procedure to insert the value in a stack. +CREATE PROCEDURE push(INOUT s int_stack, IN element INTEGER) +BEGIN + IF (s is NULL) THEN + SET s[1] = element; + ELSE + SET s[cardinality(s) + 1] = element; + END IF; +END @ + +---------------------------------------------------------------------------- +-- +-- 3. Create the procedure to pop/retrieve value from the stack. +-- +----------------------------------------------------------------------------- + +-- Create a procedure to pop/retrieve a value from the stack. +CREATE PROCEDURE pop(INOUT s int_stack, OUT element INTEGER) +BEGIN + IF NOT(s is NULL) AND cardinality(s) > 0 THEN + SET element = s[cardinality(s)]; + SET s = trim_array(s, 1); + END IF; +END @ + +---------------------------------------------------------------------------- +-- +-- 4. Create the procedure to select the topmost value from the stack. +-- +----------------------------------------------------------------------------- + +-- Create a procedure to select the topmost value in the stack. +CREATE PROCEDURE top(IN s int_stack, OUT element INTEGER) +BEGIN + IF NOT(s is NULL) AND cardinality(s) > 0 THEN + SET element = s[cardinality(s)]; + END IF; +END @ + +---------------------------------------------------------------------------- +-- +-- 5. Create a procedure to return all the stack values as a result set. +-- +----------------------------------------------------------------------------- + +-- Create a procedure to return the stack values as a result set +CREATE PROCEDURE stack_2_resultset(IN s int_stack) +BEGIN + DECLARE cur CURSOR WITH RETURN TO CLIENT FOR + SELECT elem, idx FROM unnest(s) WITH ORDINALITY AS t(elem, idx); + + OPEN cur; +END @ + +---------------------------------------------------------------------------- +-- +-- 6. Create procedure to show case the stack functionalities. +-- +----------------------------------------------------------------------------- + +-- Create procedure to show case the stack functionalities. +CREATE PROCEDURE use_stack(INOUT s int_stack, + OUT val1 INTEGER, + OUT val2 INTEGER) +BEGIN + CALL push(s, 100); + CALL push(s, 200); + CALL push(s, 300); + CALL push(s, 400); + + CALL pop(s, val1); + CALL top(s, val2); + + CALL stack_2_resultset(s); +END @ + +---------------------------------------------------------------------------- +-- +-- 7. Call the "use_stack" store procedure. +-- +----------------------------------------------------------------------------- + +-- Call the stored procedure +CALL use_stack(array[1,2,3], ?, ?) @ + +-- Disconnect from the database +CONNECT RESET@ + diff --git a/sqlpl/arrays_sqlpl.db2 b/sqlpl/arrays_sqlpl.db2 new file mode 100644 index 0000000..dad4371 --- /dev/null +++ b/sqlpl/arrays_sqlpl.db2 @@ -0,0 +1,180 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: arrays_sqlpl.db2 +-- +-- PURPOSE: To demonstrate the new ARRAY type and functions UNNEST and +-- ARRAY_AGG. +-- +-- USAGE SCENARIO: Scenario is based on the employee data in sample database. +-- The management has selected best projects based on the projects performance +-- in the current year and decided to give the employees of these projects a +-- performance bonus. The bonus will be a specific percentage of employee +-- salary. +-- +-- An array of varchar is used to store the selected project names. +-- +-- A stored procedure is implemented to calculate the bonus. The stored +-- procedure takes this array and percentage value as input. +-- +-- PREREQUISITE: NONE +-- +-- EXECUTION: db2 -td@ -vf arrays_sqlpl.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUT: The employee IDs and the corresponding bonus is calculated and +-- stored in a table. An employee can work for multiple projects therefore +-- multiple entries are possible for the same employee ID in this table. +-- +-- OUTPUT FILE: arrays_sqlpl.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT +-- SELECT +-- DROP +-- CALL +-- CREATE PROCEDURE +-- +-- FUNCTIONS USED: +-- UNNEST +-- ARRAY_AGG +-- +--------------------------------------------------------------------------- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- +-------------------------------------------------------------------------- +-- +-- SAMPLE DESCRIPTION +-- +-------------------------------------------------------------------------- +-- +-- 1. Create a table "bonus_temp" to store employee ID and corresponding +-- bonus. +-- 2. Create ARRAY types to store the values for employee ID, bonus and +-- projects. +-- 3. Create a stored procedure to calculate the bonus. +-- 3.1 Select the ID and corresponding bonus values into +-- corresponding ARRAY type "employees" and "bonus" respectively +-- using aggregate function ARRAY_AGG. +-- 3.2 Use UNNEST function to select the ARRAY elements from ARRAY +-- variables and insert the same in "bonus_temp" table. +--4. Call the stored procedure to calculate the bonus. Input to this +-- stored procedure is the ARRAY of all projects which are +-- applicable for the bonus. +--5. Select the data from the table "bonus_temp". +------------------------------------------------------------------------- + +-- Connect to the database SAMPLE +CONNECT TO sample@ + +---------------------------------------------------------------------------- +-- +-- 1. Create a table "bonus_temp" to store employee ID and corresponding +-- bonus. +-- +----------------------------------------------------------------------------- + +-- Drop the table "bonus_temp" if already exists +drop table bonus_temp@ + +-- Create the table "bonus_temp" to store employee ID and corresponding +-- bonus information. +CREATE TABLE bonus_temp (empno varchar(6), bonus double)@ + +---------------------------------------------------------------------------- +-- +-- 2. Create ARRAY types to store the values for employee ID, bonus and +-- projects. +-- +----------------------------------------------------------------------------- + +-- Create the ARRAY type "projects". +CREATE TYPE projects AS VARCHAR(20) ARRAY[10]@ + +-- Create the ARRAY type "employee" +CREATE TYPE employees AS VARCHAR(6) ARRAY[20]@ + +-- Create the ARRAY type "bonus" +CREATE TYPE bonus AS DOUBLE ARRAY[20]@ + +---------------------------------------------------------------------------- +-- +-- 3. Create a stored procedure to calculate the bonus. +-- +----------------------------------------------------------------------------- + +-- Create the procedure to calculate bonus. +CREATE PROCEDURE bonus_calculate (IN projs projects, IN percentage integer) +BEGIN +DECLARE emp_array employees; +DECLARE bonus_array bonus; + +-- Select the IDs and corresponding bonus in corresponding ARRAY type +-- "employees" and "bonus" using aggregate function +-- ARRAY_AGG. +SELECT cast(array_agg(employee.empno) AS employees), + cast(array_agg(.10*salary) AS bonus) INTO emp_array,bonus_array + FROM vempprojact, unnest(projs) AS P(id), employee + WHERE P.id=vempprojact.projno AND employee.empno=vempprojact.empno; + +-- Use UNNEST function to select the ARRAY elements from ARRAY +-- variables and insert the same in "bonus_temp" table. +INSERT INTO bonus_temp + SELECT T.empno, T.bonus + FROM unnest(emp_array, bonus_array) + WITH ORDINALITY AS T(empno,bonus, idx); +END@ + +---------------------------------------------------------------------------- +-- +-- 4. Call the stored procedure to calculate the bonus.Input to this +-- stored procedure is the ARRAY of all projects which are +-- applicable for bonus. +----------------------------------------------------------------------------- + +-- Call the stored procedure +Call bonus_calculate(ARRAY['AD3111', 'IF1000', 'MA2111'], 10)@ + +---------------------------------------------------------------------------- +-- +-- 5. Select the data from the table "bonus_temp". +-- +----------------------------------------------------------------------------- + +SELECT empno, bonus FROM bonus_temp@ + +--Cleanup +DROP PROCEDURE bonus_calculate@ +DROP TYPE projects@ +DROP TYPE employees@ +DROP TYPE bonus@ +DROP TABLE bonus_temp@ + +-- Disconnect from database +CONNECT RESET@ + diff --git a/sqlpl/basecase.db2 b/sqlpl/basecase.db2 new file mode 100644 index 0000000..95cb6f0 --- /dev/null +++ b/sqlpl/basecase.db2 @@ -0,0 +1,74 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: basecase.db2 +-- +-- SAMPLE: To create the UPDATE_SALARY SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf basecase.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL update_salary ('000100', 1)" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "basecase", using the basecase.sqc +-- source file available in the sqlpl samples directory. +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + + CREATE PROCEDURE update_salary + (IN employee_number CHAR(6), IN rating INT) + LANGUAGE SQL + BEGIN + DECLARE SQLSTATE CHAR(5); + DECLARE not_found CONDITION FOR SQLSTATE '02000'; + DECLARE EXIT HANDLER FOR not_found + SIGNAL SQLSTATE '02444'; + + CASE rating + WHEN 1 THEN + UPDATE employee + SET salary = salary * 1.10, bonus = 1000 + WHERE empno = employee_number; + WHEN 2 THEN + UPDATE employee + SET salary = salary * 1.05, bonus = 500 + WHERE empno = employee_number; + ELSE + UPDATE employee + SET salary = salary * 1.03, bonus = 0 + WHERE empno = employee_number; + END CASE; + END @ diff --git a/sqlpl/basecase.sqc b/sqlpl/basecase.sqc new file mode 100644 index 0000000..aecc257 --- /dev/null +++ b/sqlpl/basecase.sqc @@ -0,0 +1,189 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: basecase.sqc +** +** SAMPLE: To call the UPDATE_SALARY SQL procedure +** +** There are two parts to this program: +** 1. the basecase executable (placed on the client) +** 2. the UPDATE_SALARY SQL procedure (created on the +** server with the basecase.db2 CLP script) +** +** basecase calls the UPDATE_SALARY SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(stmt, "CALL %s (?,?)", procname); +** EXEC SQL prepare st from :stmt; +** EXEC SQL execute st USING :empno:empnoind, :rating:ratingind; +** +** When the CALL with Host Variable is used, +** the precompiler allocates and initializes an internal one +** variable SQLDA for both input and output. +** +** The UPDATE_SALARY procedure raises the salary of an +** employee identified by the "empno" IN parameter +** in the "staff" table of the "sample" database. +** The procedure determines the raise according to a CASE +** statement that uses the "rating" IN parameter. +** +** SQL STATEMENTS USED: +** CONNECT +** DECLARE CURSOR +** OPEN +** FETCH +** CLOSE +** CALL +** +** OUTPUT FILE: basecase.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "UPDATE_SALARY"; + + /* Declare a statement string to call the procedure dynamically */ + char stmt[1200]; + + /* Declare local variables for holding returned values */ + double sal = 0; + double bon = 0; + + /* Declare Local Variables for Passing Data to SQL Procedure */ + char empno[7] = "000100"; + sqlint16 empnoind = 0; + sqlint32 rating = 1; + sqlint16 ratingind = 0; + EXEC SQL END DECLARE SECTION; + + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: basecase remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + /********************************************************\ + * Display the employee info before issuing CALL statement * + \********************************************************/ + + EXEC SQL DECLARE c1 CURSOR FOR + SELECT salary, bonus + FROM employee + WHERE empno = :empno + FOR READ ONLY; + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN CURSOR"); + EXEC SQL FETCH c1 INTO :sal, :bon; + EXEC SQL CLOSE c1; + printf("\nEmployee number %s before CALL: salary = %9.2f, bonus = %9.2f\n", empno, sal, bon); + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + + printf("Use CALL with Host Variables to invoke the Server Procedure " + "named %s\n", procname); + sprintf(stmt, "CALL %s (?,?)", procname); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPARE CALL STATEMENT"); + + EXEC SQL execute st USING :empno:empnoind, :rating:ratingind; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + /********************************************************\ + * Display the employee info after issuing CALL statement * + \********************************************************/ + + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN CURSOR"); + EXEC SQL FETCH c1 INTO :sal, :bon; + EXEC SQL CLOSE c1; + printf("\nEmployee number %s after CALL: salary = %9.2f, bonus = %9.2f\n", empno, sal, bon); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { /* Successful, but rollback the changes to the database */ + EXEC SQL ROLLBACK; + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : basecase.sqc */ + diff --git a/sqlpl/baseif.db2 b/sqlpl/baseif.db2 new file mode 100644 index 0000000..5dc5e28 --- /dev/null +++ b/sqlpl/baseif.db2 @@ -0,0 +1,72 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: baseif.db2 +-- +-- SAMPLE: To create the UPDATE_SALARY_IF SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf baseif.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL update_salary_if ('000100', 1)" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "baseif", using the baseif.sqc +-- source file available in the sqlpl samples directory. +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + + CREATE PROCEDURE update_salary_if + (IN employee_number CHAR(6), IN rating SMALLINT) + LANGUAGE SQL + BEGIN + DECLARE SQLSTATE CHAR(5); + DECLARE not_found CONDITION FOR SQLSTATE '02000'; + DECLARE EXIT HANDLER FOR not_found + SIGNAL SQLSTATE '20000' SET MESSAGE_TEXT = 'Employee not found'; + + IF (rating = 1) + THEN UPDATE employee + SET salary = salary * 1.10, bonus = 1000 + WHERE empno = employee_number; + ELSEIF (rating = 2) + THEN UPDATE employee + SET salary = salary * 1.05, bonus = 500 + WHERE empno = employee_number; + ELSE UPDATE employee + SET salary = salary * 1.03, bonus = 0 + WHERE empno = employee_number; + END IF; + END @ diff --git a/sqlpl/baseif.sqc b/sqlpl/baseif.sqc new file mode 100644 index 0000000..cf3d140 --- /dev/null +++ b/sqlpl/baseif.sqc @@ -0,0 +1,189 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: baseif.sqc +** +** SAMPLE: To call the UPDATE_SALARY_IF SQL procedure +** +** There are two parts to this program: +** 1. the baseif executable (placed on the client) +** 2. the UPDATE_SALARY_IF SQL procedure (created on the +** server with the baseif.db2 CLP script) +** +** baseif calls the UPDATE_SALARY_IF SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(stmt, "CALL %s (?,?)", procname); +** EXEC SQL prepare st from :stmt; +** EXEC SQL execute st USING:empno:empnoind, :rating:ratingind; +** +** When the CALL with Host Variable is used, +** the precompiler allocates and initializes an internal one +** variable SQLDA for both input and output. +** +** The UPDATE_SALARY_IF procedure raises the salary of an +** employee identified by the "empno" IN parameter +** in the "staff" table of the "sample" database. +** The procedure determines the raise according to an IF +** statement that uses the "rating" IN parameter. +** +** SQL STATEMENTS USED: +** CONNECT +** DECLARE CURSOR +** OPEN +** FETCH +** CLOSE +** CALL +** +** OUTPUT FILE: baseif.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "UPDATE_SALARY_IF"; + + /* Declare a statement string to call the procedure dynamically */ + char stmt[1200]; + + /* Declare local variables for holding returned values */ + double sal = 0; + double bon = 0; + + /* Declare Local Variables for Passing Data to SQL Procedure */ + char empno[7] = "000100"; + sqlint16 empnoind = 0; + sqlint16 rating = 1; + sqlint16 ratingind = 0; + EXEC SQL END DECLARE SECTION; + + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: baseif remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + /********************************************************\ + * Display the employee info before issuing CALL statement * + \********************************************************/ + + EXEC SQL DECLARE c1 CURSOR FOR + SELECT salary, bonus + FROM employee + WHERE empno = :empno + FOR READ ONLY; + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN CURSOR"); + EXEC SQL FETCH c1 INTO :sal, :bon; + EXEC SQL CLOSE c1; + printf("\nEmployee number %s before CALL: salary = %9.2f, bonus = %9.2f\n", empno, sal, bon); + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + + printf("Use CALL with Host Variables to invoke the Server Procedure " + "named %s\n", procname); + sprintf(stmt, "CALL %s (?,?)", procname); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPARE CALL STATEMENT"); + + EXEC SQL execute st USING :empno:empnoind, :rating:ratingind; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + /********************************************************\ + * Display the employee info after issuing CALL statement * + \********************************************************/ + + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN CURSOR"); + EXEC SQL FETCH c1 INTO :sal, :bon; + EXEC SQL CLOSE c1; + printf("\nEmployee number %s after CALL: salary = %9.2f, bonus = %9.2f\n", empno, sal, bon); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { /* Successful, but rollback the changes to the database */ + EXEC SQL ROLLBACK; + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : baseif.sqc */ + diff --git a/sqlpl/bldapp b/sqlpl/bldapp new file mode 100755 index 0000000..37a42d3 --- /dev/null +++ b/sqlpl/bldapp @@ -0,0 +1,104 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldapp +# Builds C applications for Linux +# Usage: bldapp [ [ ]] + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then +BITWIDTH=64 +if [ "$HARDWAREPLAT" = "ppc64" ] || [ "$HARDWAREPLAT" = "s390x" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then +EXTRA_C_FLAGS="-m64" +fi +else +# x86 is the only native 32-bit platform +BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] + then + LIB="lib64" +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 $3 $4 + # Compile the utilemb.c error-checking utility. + gcc $EXTRA_C_FLAGS -I$DB2PATH/include -c utilemb.c +else + # Compile the utilcli.c error-checking utility. + gcc $EXTRA_C_FLAGS -I$DB2PATH/include -c utilcli.c +fi + +# Compile the program. +gcc $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c + +if [ -f $1".sqc" ] +then + # Link the program with utilemb.o. + gcc $EXTRA_C_FLAGS -o $1 $1.o utilemb.o $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 +else + # Link the program with utilcli.o. + gcc $EXTRA_C_FLAGS -o $1 $1.o utilcli.o $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 +fi diff --git a/sqlpl/bldcli b/sqlpl/bldcli new file mode 100755 index 0000000..c471c83 --- /dev/null +++ b/sqlpl/bldcli @@ -0,0 +1,91 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldcli +# Builds CLI applications for Linux +# Usage: bldcli + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then +BITWIDTH=64 +EXTRA_C_FLAGS="-m64" +else +# x86 is the only native 32-bit platform +BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] + then + LIB="lib64" +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 $3 $4 +fi + +# Compile the error-checking utility. +gcc $EXTRA_C_FLAGS -I$DB2PATH/include -c utilcli.c + +# Compile the program. +gcc $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c + +# Link the program. +gcc $EXTRA_C_FLAGS -o $1 $1.o utilcli.o $EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2 + diff --git a/sqlpl/defaultparam.db2 b/sqlpl/defaultparam.db2 new file mode 100644 index 0000000..b98e77b --- /dev/null +++ b/sqlpl/defaultparam.db2 @@ -0,0 +1,173 @@ +--/**************************************************************************** +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ****************************************************************************** +-- +-- SAMPLE FILE NAME: defaultparam.db2 +-- +-- PURPOSE: To demonstrate how to use DEFAULT values for procedure parameters. +-- +-- PREREQUISITE : NONE +-- +-- EXECUTION : db2 -td@ -vf defaultparam.db2 +-- +-- INPUTS : NONE +-- +-- OUTPUT : Result of all the procedure calls +-- +-- OUTPUT FILE : defaultparam.out (available in the online documentation) +-- +-- DEPENDENCIES : NONE +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- CREATE PROCEDURE +-- INSERT +-- SELECT +-- DROP TABLE +-- DROP PROCEDURE +-- UPDATE TABLE +-- +-- ************************************************************************* +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- +-- http://www.ibm.com/software/data/db2/ad/ +-- +-- ************************************************************************* + +-- SAMPLE DESCRIPTION +-- +-- Create a procedure bonus_calculation which will take workdept and empjob +-- as a parameter for calculating the bonus for that department. If there +-- is no parameter is specified while calling the procedure DEFAULT value is +-- set. Here default value is ALL. +-- +-- ************************************************************************* + +-- /*****************************************************************/ +-- /* DEFAULT values for procedure parameters */ +-- /*****************************************************************/ + +-- Connect to sample database + +CONNECT TO sample@ + +-- Drop table temp_employee + +DROP TABLE temp_employee@ + +-- Create table temp_employee +CREATE TABLE temp_employee LIKE employee@ + +-- Insert data into temp_employee@ +INSERT INTO temp_employee SELECT * FROM employee@ + +-- Drop procedure bonus_calculation +DROP PROCEDURE bonus_calculation @ + +CREATE PROCEDURE bonus_calculation +(IN emp_job VARCHAR(8), +IN dept_no CHAR(3) DEFAULT 'ALL') + RESULT SETS 1 + LANGUAGE SQL + BEGIN + + DECLARE c1 CURSOR WITH RETURN FOR + SELECT CONCAT(CONCAT(CONCAT + (CONCAT(cast(empno as CHAR(4)), ' || '), workdept), + ' || '), bonus) AS bonus_calculation + FROM temp_employee + ORDER BY workdept; + + DECLARE c2 CURSOR WITH RETURN FOR + SELECT CONCAT(CONCAT(CONCAT + (CONCAT(cast(empno AS CHAR(4)), ' || '), workdept), + ' || '), bonus) AS bonus_calculation + FROM temp_employee + WHERE workdept = dept_no AND job = emp_job; + + + + IF dept_no = 'ALL ' THEN + UPDATE temp_employee + SET bonus = + CASE WHEN year (current date) - year (hiredate) + between 20 and 15 THEN salary * '.30' + WHEN year (current date) - year (hiredate) + between 15 and 10 THEN salary * '.20' + WHEN year (current date) - year (hiredate) + between 10 and 05 THEN salary * '.15' + ELSE salary * '.10' + END + WHERE job = emp_job; + ELSE + UPDATE temp_employee + SET bonus = + CASE WHEN year (current date) - year (hiredate) + between 20 and 15 THEN salary * '.30' + WHEN year (current date) - year (hiredate) + between 15 and 10 THEN salary * '.20' + WHEN year (current date) - year (hiredate) + between 10 and 05 THEN salary * '.15' + ELSE salary * '.10' + END + WHERE workdept = dept_no AND job = emp_job; + END IF; + + + IF dept_no = 'ALL' THEN + OPEN c1; + ELSE + OPEN c2; + END IF; +END @ + + +-- Call Procedure bonus_calculation + +-- Calling procedure with one argument +CALL bonus_calculation(emp_job=>'MANAGER')@ + +-- Calling procedure with more than one argument. +CALL bonus_calculation(dept_no=>'D11', emp_job=>'MANAGER')@ + +-- Calling procedure with one DEFAULT argument. +CALL bonus_calculation(emp_job=>'MANAGER', dept_no=>DEFAULT)@ + +-- Calling procedure with DEFAULT value as arguments +CALL bonus_calculation(emp_job=>DEFAULT, dept_no=>DEFAULT)@ + +-- Calling procedure with DEFAULT arguments +CALL bonus_calculation(DEFAULT,DEFAULT)@ + + +-- /*****************************************************************/ +-- /* Clean up */ +-- /*****************************************************************/ + +DROP TABLE temp_employee@ +DROP PROCEDURE bonus_calculation@ +CONNECT RESET@ + diff --git a/sqlpl/dynamic.db2 b/sqlpl/dynamic.db2 new file mode 100644 index 0000000..7c570e2 --- /dev/null +++ b/sqlpl/dynamic.db2 @@ -0,0 +1,85 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: dynamic.db2 +-- +-- SAMPLE: To create the CREATE_DEPT_TABLE SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf dynamic.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL create_dept_table ('D11', ?)" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "dynamic", using the dynamic.sqc +-- source file available in the sqlpl samples directory. +---------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CREATE PROCEDURE create_dept_table +(IN deptNumber VARCHAR(3), OUT table_name VARCHAR(30)) +LANGUAGE SQL + BEGIN + DECLARE SQLSTATE CHAR(5); + DECLARE new_name VARCHAR(30); + DECLARE stmt VARCHAR(1000); + + -- continue if sqlstate 42704 ('undefined object name') + DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' + SET stmt = ''; + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION + SET table_name = 'PROCEDURE_FAILED'; + + SET new_name = 'DEPT_'||deptNumber||'_T'; + SET stmt = 'DROP TABLE '||new_name; + PREPARE s1 FROM stmt; + EXECUTE s1; + SET stmt = 'CREATE TABLE '||new_name|| + '( empno CHAR(6) NOT NULL, '|| + 'firstnme VARCHAR(12) NOT NULL, '|| + 'midinit CHAR(1) NOT NULL, '|| + 'lastname VARCHAR(15) NOT NULL, '|| + 'salary DECIMAL(9,2))'; + PREPARE s2 FROM STMT; + EXECUTE s2; + SET stmt = 'INSERT INTO '||new_name || ' ' || + 'SELECT empno, firstnme, midinit, lastname, salary '|| + 'FROM employee '|| + 'WHERE workdept = ?'; + PREPARE s3 FROM stmt; + EXECUTE s3 USING deptNumber; + + SET table_name = new_name; +END @ diff --git a/sqlpl/dynamic.sqc b/sqlpl/dynamic.sqc new file mode 100644 index 0000000..c79bf9f --- /dev/null +++ b/sqlpl/dynamic.sqc @@ -0,0 +1,181 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: dynamic.sqc +** +** SAMPLE: To call the CREATE_DEPT_TABLE SQL procedure +** +** There are two parts to this program: +** 1. the dynamic executable (placed on the client) +** 2. the CREATE_DEPT_TABLE SQL procedure (created on the +** server with the dynamic.db2 CLP script) +** +** dynamic calls the CREATE_DEPT_TABLE SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(callstmt, "CALL %s (?,?)", procname); +** EXEC SQL prepare st from :callstmt; +** EXEC SQL execute st INTO :table_name:tableind USING :deptnum:deptind; +** +** When the CALL with Host Variable is used, +** the precompiler allocates and initializes an internal one +** variable SQLDA for both input and output. +** +** The CREATE_DEPT_TABLE procedure uses dynamic DDL to create +** a new table. The name of the table is based on the value +** of the IN parameter to the procedure. +** +** SQL STATEMENTS USED: +** CONNECT +** CALL +** PREPARE +** DECLARE CURSOR +** OPEN +** FETCH +** CLOSE +** +** OUTPUT FILE: dynamic.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + char stmt[200]; + char s1[200]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "CREATE_DEPT_TABLE"; + + /* Declare a statement string to call the procedure dynamically */ + char callstmt[1200]; + + /* Declare Local Variables for Passing Data to SQL Procedure */ + char deptnum[4]; + sqlint16 deptind = 0; /* IN parameter */ + char table_name[31]; + sqlint16 tableind = -1; /* OUT parameter */ + + /* Declare Local Variables for Returning Data from New Table */ + sqlint16 numrows = 0; + EXEC SQL END DECLARE SECTION; + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(2)); + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: dynamic remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + + strcpy (deptnum, "D11"); + printf("Use CALL with Host Variables to invoke the Server Procedure " + "named %s\n", procname); + sprintf(callstmt, "CALL %s (?,?)", procname); + + EXEC SQL prepare st from :callstmt; + EMB_SQL_CHECK("PREPARE CALL STATEMENT"); + + EXEC SQL execute st INTO :table_name:tableind USING :deptnum:deptind; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + /********************************************************\ + * Display the number of rows after issuing CALL statement * + \********************************************************/ + + strcpy ( stmt, "SELECT COUNT(*) FROM "); + strcat (stmt, table_name); + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("PREPARE"); + EXEC SQL DECLARE c1 CURSOR FOR s1; + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN"); + EXEC SQL FETCH c1 INTO :numrows; + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("CLOSE"); + + printf("\nNumber of rows in %11s = %d\n", table_name, numrows); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { /* Successful, but rollback the changes to the database */ + EXEC SQL ROLLBACK; + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : dynamic.sqc */ + diff --git a/sqlpl/embprep b/sqlpl/embprep new file mode 100755 index 0000000..56dce72 --- /dev/null +++ b/sqlpl/embprep @@ -0,0 +1,63 @@ + +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: embprep +# To prep and bind C/C++ and Micro Focus COBOL embedded SQL programs +# +# Usage: embprep [ [ ]] + +# Connect to a database. +if (test $# -lt 2) +then + db2 connect to sample +elif (test $# -lt 3) +then + db2 connect to $2 +else + db2 connect to $2 user $3 using $4 +fi + +# Precompile the program. +if [ -f $1".sqc" ] +then + db2 prep $1.sqc bindfile + if [ -f utilemb.sqc ] + then + db2 prep utilemb.sqc + fi +elif [ -f $1".sqC" ] +then + db2 prep $1.sqC bindfile + if [ -f utilemb.sqC ] + then + db2 prep utilemb.sqC + fi +elif [ -f $1".sqb" ] +then + db2 prep $1.sqb bindfile target mfcob CALL_RESOLUTION DEFERRED +fi + +# Bind the program to the database. +db2 bind $1.bnd + +# Disconnect from the database. +db2 connect reset +db2 terminate diff --git a/sqlpl/iterate.db2 b/sqlpl/iterate.db2 new file mode 100644 index 0000000..9443668 --- /dev/null +++ b/sqlpl/iterate.db2 @@ -0,0 +1,85 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: iterate.db2 +-- +-- SAMPLE: To create the ITERATOR SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf iterate.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL iterator ()" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "iterate", using the iterate.sqc +-- source file available in the sqlpl samples directory. +---------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CREATE PROCEDURE iterator() +LANGUAGE SQL +BEGIN + DECLARE SQLSTATE CHAR(5); + DECLARE v_dept CHAR(3); + DECLARE v_deptname VARCHAR(29); + DECLARE v_admdept CHAR(3); + DECLARE at_end INT DEFAULT 0; + DECLARE new_v_dept VARCHAR(3); + DECLARE dept_no INT DEFAULT 11; + + DECLARE not_found CONDITION FOR SQLSTATE '02000'; + DECLARE c1 CURSOR FOR + SELECT deptno, deptname, admrdept + FROM department + ORDER BY deptno; + DECLARE CONTINUE HANDLER FOR not_found + SET at_end = 1; + + OPEN c1; + ins_loop: + LOOP + FETCH c1 INTO v_dept, v_deptname, v_admdept; + IF at_end = 1 THEN + LEAVE ins_loop; + ELSEIF v_dept = 'D11' THEN + ITERATE ins_loop; + END IF; + SET new_v_dept= VARCHAR('K'||CHAR(dept_no)||'',3); + SET dept_no=dept_no+1; + INSERT INTO department (deptno, deptname, admrdept) + VALUES (new_v_dept, v_deptname, v_admdept); + END LOOP; + CLOSE c1; +END @ diff --git a/sqlpl/iterate.sqc b/sqlpl/iterate.sqc new file mode 100644 index 0000000..a061cd0 --- /dev/null +++ b/sqlpl/iterate.sqc @@ -0,0 +1,156 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: iterate.sqc +** +** SAMPLE: To call the ITERATOR SQL procedure +** +** There are two parts to this program: +** 1. the iterate executable (placed on the client) +** 2. the ITERATOR SQL procedure (created on the +** server with the iterate.db2 CLP script) +** +** iterate calls the ITERATOR SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(stmt, "CALL %s ()", procname); +** EXEC SQL prepare st from :stmt; +** EXEC SQL execute st; +** +** The ITERATOR procedure uses a FETCH loop to retrieve +** data from the "department" table. If the value of the +** "deptno" column is not 'D11', modified data is inserted +** into the "department" table. If the value of the "deptno" +** column is 'D11', an ITERATE statement passes the flow of +** control back to the beginning of the LOOP statement. +** +** SQL STATEMENTS USED: +** CONNECT +** SELECT +** CALL +** +** OUTPUT FILE: iterate.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "ITERATOR"; + + /* Declare a statement string to call the procedure dynamically */ + char stmt[1200]; + + /* Declare a Local Variable for Holding the Number of Rows */ + sqlint32 count = 0; + + EXEC SQL END DECLARE SECTION; + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: iterate remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + EXEC SQL SELECT COUNT(*) INTO :count FROM department; + printf("\nNumber of rows before CALL to %s: %d\n", procname, count); + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + + printf("Use CALL with Host Variables to invoke the Server Procedure " + "named %s\n", procname); + sprintf(stmt, "CALL %s ()", procname); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPARE CALL STATEMENT"); + + EXEC SQL execute st; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + EXEC SQL SELECT COUNT(*) INTO :count FROM department; + printf("\nNumber of rows after CALL to %s: %d\n", procname, count); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { /* Successful, but rollback the changes to the database anyways */ + EXEC SQL ROLLBACK; + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : iterate.sqc */ diff --git a/sqlpl/leave.db2 b/sqlpl/leave.db2 new file mode 100644 index 0000000..7f98454 --- /dev/null +++ b/sqlpl/leave.db2 @@ -0,0 +1,89 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: leave.db2 +-- +-- SAMPLE: To create the LEAVE_LOOP SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf leave.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL leave_loop (?)" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "leave", using the leave.sqc +-- source file available in the sqlpl samples directory. +---------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CREATE PROCEDURE leave_loop(OUT counter INT) +LANGUAGE SQL +BEGIN + DECLARE SQLSTATE CHAR(5); + DECLARE v_firstnme VARCHAR(12); + DECLARE v_midinit CHAR(1); + DECLARE v_lastname VARCHAR(15); + DECLARE v_counter SMALLINT DEFAULT 0; + DECLARE at_end SMALLINT DEFAULT 0; + + DECLARE not_found + CONDITION for SQLSTATE '02000'; + DECLARE c1 CURSOR FOR + SELECT firstnme, midinit, lastname + FROM employee; + DECLARE CONTINUE HANDLER for not_found + SET at_end = 1; + + -- initialize OUT parameter + SET counter = 0; + + OPEN c1; + fetch_loop: + LOOP + FETCH c1 INTO + v_firstnme, v_midinit, v_lastname; + IF at_end <> 0 THEN LEAVE fetch_loop; + END IF; + -- Use a local variable for the iterator variable + -- because SQL procedures only allow you to assign + -- values to an OUT parameter + SET v_counter = v_counter + 1; + END LOOP fetch_loop; + CLOSE c1; + + -- Now assign the value of the local + -- variable to the OUT parameter + SET counter = v_counter; +END @ diff --git a/sqlpl/leave.sqc b/sqlpl/leave.sqc new file mode 100644 index 0000000..373b49c --- /dev/null +++ b/sqlpl/leave.sqc @@ -0,0 +1,163 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: leave.sqc +** +** SAMPLE: To call the LEAVE_LOOP SQL procedure +** +** There are two parts to this program: +** 1. the leave executable (placed on the client) +** 2. the LEAVE_LOOP SQL procedure (created on the +** server with the leave.db2 CLP script) +** +** leave calls the LEAVE_LOOP SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(stmt, "CALL %s (?)", procname); +** EXEC SQL prepare st from :stmt; +** EXEC SQL execute st INTO :count:countind; +** +** When the CALL with Host Variable is used, +** the precompiler allocates and initializes an internal one +** variable SQLDA for both input and output. +** +** The LEAVE_LOOP procedure counts the number of FETCH +** operations performed in a LOOP statement before the +** "not_found" condition handler invokes a LEAVE statement. +** The LEAVE statement causes the flow of control to exit +** the loop and complete the stored procedure. +** +** The counter value is assigned to the counter OUT parameter +** that is returned to the leave client. The leave client +** then prints the counter value. +** +** SQL STATEMENTS USED: +** CONNECT +** CALL +** +** OUTPUT FILE: leave.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "LEAVE_LOOP"; + + /* Declare a statement strings to call the procedure dynamically */ + char stmt[1200]; + + /* Declare Local Variables for Passing Data to SQL Procedure */ + sqlint32 count = 0; + sqlint16 countind = 0; + EXEC SQL END DECLARE SECTION; + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: leave remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + printf("Use CALL with Host Variables to invoke the Server Procedure " + "named %s\n", procname); + countind = -1; /* count has no input, so set to null */ + sprintf(stmt, "CALL %s (?)", procname); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPARE CALL STATEMENT"); + + EXEC SQL execute st INTO :count:countind; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + /********************************************************\ + * Display the # of times the LOOP statement iterated * + \********************************************************/ + + printf("\nLOOP statement iterated %d times before invoking LEAVE\n", count); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { /* Rollback the changes to the database */ + EXEC SQL ROLLBACK; + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : leave.sqc */ + diff --git a/sqlpl/loop.db2 b/sqlpl/loop.db2 new file mode 100644 index 0000000..e84a2eb --- /dev/null +++ b/sqlpl/loop.db2 @@ -0,0 +1,86 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: loop.db2 +-- +-- SAMPLE: To create the LOOP_UNTIL_SPACE SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf loop.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL loop_until_space (?)" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "loop", using the loop.sqc +-- source file available in the sqlpl samples directory. +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CREATE PROCEDURE loop_until_space(OUT counter INT) +LANGUAGE SQL +BEGIN + DECLARE v_firstnme VARCHAR(12); + DECLARE v_midinit CHAR(1); + DECLARE v_lastname VARCHAR(15); + DECLARE v_counter SMALLINT DEFAULT 0; + + DECLARE c1 CURSOR FOR + SELECT firstnme, midinit, lastname + FROM employee + ORDER BY midinit DESC; + DECLARE CONTINUE HANDLER FOR NOT FOUND + SET counter = -1; + + -- initialize OUT parameter + SET counter = 0; + OPEN c1; + fetch_loop: + LOOP + FETCH c1 INTO + v_firstnme, v_midinit, v_lastname; + -- Use a local variable for the iterator variable + -- because SQL procedures only allow you to assign + -- values to an OUT parameter + SET v_counter = v_counter + 1; + IF v_midinit = ' ' THEN + LEAVE fetch_loop; + END IF; + END LOOP fetch_loop; + CLOSE c1; + + -- Now assign the value of the local + -- variable to the OUT parameter + SET counter = v_counter; +END @ diff --git a/sqlpl/loop.sqc b/sqlpl/loop.sqc new file mode 100644 index 0000000..244d19c --- /dev/null +++ b/sqlpl/loop.sqc @@ -0,0 +1,163 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: loop.sqc +** +** SAMPLE: To call the LOOP_UNTIL_SPACE SQL procedure +** +** There are two parts to this program: +** 1. the loop executable (placed on the client) +** 2. the LOOP_UNTIL_SPACE SQL procedure (created on the +** server with the loop.db2 CLP script) +** +** loop calls the LOOP_UNTIL_SPACE SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(stmt, "CALL %s (?)", procname); +** EXEC SQL prepare st from :stmt; +** EXEC SQL execute st INTO :count:countind; +** +** When the CALL with Host Variable is used, +** the precompiler allocates and initializes an internal one +** variable SQLDA for both input and output. +** +** The LOOP_UNTIL_SPACE procedure counts the number of FETCH +** operations performed in a LOOP statement until the cursor +** retrieves a row with a space (' ') value for column "midinit". +** The loop statement causes the flow of control to exit +** the loop and complete the stored procedure. +** +** The counter value is assigned to the counter OUT parameter +** that is returned to the loop client. The loop client +** then prints the counter value. +** +** SQL STATEMENTS USED: +** CONNECT +** CALL +** +** OUTPUT FILE: loop.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "LOOP_UNTIL_SPACE"; + + /* Declare a statement string to call the procedure dynamically */ + char stmt[1200]; + + /* Declare Local Variables for Passing Data to SQL Procedure */ + sqlint32 count = 0; + sqlint16 countind = 0; + EXEC SQL END DECLARE SECTION; + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: loop remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + printf("Use CALL with Host Variables to invoke the Server Procedure " + "named %s\n", procname); + countind = -1; /* count has no input, so set to null */ + sprintf(stmt, "CALL %s (?)", procname); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPATE CALL STATEMENT"); + + EXEC SQL execute st INTO :count:countind; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + /********************************************************\ + * Display the # of times the LOOP statement iterated * + \********************************************************/ + + printf("\nLOOP statement iterated %d times before column midinit = \' \'\n", count); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { /* Rollback the changes to the database */ + EXEC SQL ROLLBACK; + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : loop.sqc */ + diff --git a/sqlpl/makefile b/sqlpl/makefile new file mode 100755 index 0000000..5e2453d --- /dev/null +++ b/sqlpl/makefile @@ -0,0 +1,183 @@ +############################################################################## +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################## +# +# MAKEFILE for SQL Procedures samples for Linux +# +# Enter one of the following commands +# +# make - Builds the program designated by +# +# make all - Builds the all the supplied sample programs +# +# make clean - Erases intermediate files +# make cleanall - Erases all files produced in the build process, +# except the original source files +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +############################################################################## +# 1 -- VARIABLES +############################################################################## + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +BLDAPP=bldapp + +# To connect to a remote SAMPLE database cataloged on the client machine +# with another name, update the DB variable. +DB=sample +# Set UID and PWD if neccesary +UID= +PWD= + +COPY=cp +ERASE=rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all +# 2g - make clean +# 2h - make cleanall +############################################################################# + + +#**************************************************************************** +# 2a - make all +#**************************************************************************** + +all : \ + basecase baseif \ + dynamic \ + iterate \ + leave \ + loop \ + nestcase nestif \ + repeat rsultset \ + tbsel \ + whiles \ + NestedSP + +#**************************************************************************** +# 2b - make clean +#**************************************************************************** + +clean : \ + cleangen \ + cleanemb + +cleangen : + $(ERASE) *.class *.o *.map message.* + +cleanemb : + $(ERASE) basecase.c baseif.c + $(ERASE) dynamic.c + $(ERASE) iterate.c + $(ERASE) leave.c loop.c + $(ERASE) nestcase.c nestif.c + $(ERASE) repeat.c + $(ERASE) tbsel.c + $(ERASE) utilemb.c + $(ERASE) whiles.c + + +#**************************************************************************** +# 2h - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) *.bnd + $(ERASE) basecase baseif + $(ERASE) dynamic + $(ERASE) iterate + $(ERASE) leave loop + $(ERASE) nestcase nestif + $(ERASE) repeat rsultset + $(ERASE) tbsel + $(ERASE) whiles + + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - embedded SQL client samples +# 3b - CLI client sample +# 3c - JDBC client sample +############################################################################# + +#**************************************************************************** +# 3a - embedded SQL client samples +#**************************************************************************** + +basecase : + $(BLDAPP) basecase $(DB) $(UID) $(PWD) + +baseif : + $(BLDAPP) baseif $(DB) $(UID) $(PWD) + +dynamic : + $(BLDAPP) dynamic $(DB) $(UID) $(PWD) + +iterate : + $(BLDAPP) iterate $(DB) $(UID) $(PWD) + +leave : + $(BLDAPP) leave $(DB) $(UID) $(PWD) + +loop : + $(BLDAPP) loop $(DB) $(UID) $(PWD) + +nestif : + $(BLDAPP) nestif $(DB) $(UID) $(PWD) + +nestcase : + $(BLDAPP) nestcase $(DB) $(UID) $(PWD) + +repeat : + $(BLDAPP) repeat $(DB) $(UID) $(PWD) + +tbsel : + $(BLDAPP) tbsel $(DB) $(UID) $(PWD) + +whiles : + $(BLDAPP) whiles $(DB) $(UID) $(PWD) + + +#**************************************************************************** +# 3b - CLI client sample +#**************************************************************************** + +rsultset : + $(BLDAPP) rsultset + +#**************************************************************************** +# 3c - JDBC client samples +#**************************************************************************** + +NestedSP : NestedSP.java + javac Util.java + javac NestedSP.java + diff --git a/sqlpl/modules.db2 b/sqlpl/modules.db2 new file mode 100644 index 0000000..83ba743 --- /dev/null +++ b/sqlpl/modules.db2 @@ -0,0 +1,1086 @@ +------------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +------------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: modules.db2 +-- +-- SAMPLE: This sample demonstrates: +-- 1. Creation of modules and module objects +-- 2. Creation and usage of row data types, boolean data type, +-- associative arrays and array of rows +-- 3. Creation and usage of strongly-typed, weakly-typed and +-- parameterized cursors +-- 4. Full SQL PL support for functions, triggers and compiled +-- compound statements +-- 5. Support for INOUT and OUT parameters in compiled UDFs +-- 6. Support for compiled UDFs and triggers that contain +-- assignment to global variables +-- +-- USAGE SCENARIO: This is a furniture store product purchasing scenario +-- in which data related to purchase orders, product delivery and inventory +-- is managed. Store customers can place a purchase order for a set of +-- furniture items and specify delivery requirements. A customer bill is +-- generated that reflects the order placed and the total order cost. +-- Shippping costs are determined and the shipping information is recorded. +-- A check is maintained on the stock of products in the store. Suppliers can +-- view data regarding supply requirements. A store bill is generated for the +-- stock replenished. +-- +-- SAMPLE DESCRIPTION: The data is stored in tables: +-- +-- (1) Product_details : Contains the details of products available in +-- the store. +-- (2) Customer_details : Contains the customer details. +-- (3) Purchaseorder_master : Contains details of the customer purchase order. +-- This is the master table. +-- (4) Purchaseorder_details : Contains details of products ordered by the +-- customer. This is the child table. +-- (5) Shipping : Contains details of products shipped to the +-- customers. +-- (6) Inventory_details : Contains details of products available with the +-- supplier. +-- (7) Supply_orders : Contains details of products that need to be +-- replenished in the store by the supplier. +-- +-- The application processing is performed by the following routines: +-- +-- (1) Function 'replenish_stock' : Procures details of products that need to +-- be replenished in the store to place an +-- order with the supplier. +-- (2) Trigger 'check_stock' : Checks stock of items remaining in the +-- store and places order with the supplier +-- (3) Module 'store_transactions' : Contains stored procedures, functions, +-- user-defined data types and cursors that +-- process all customer-store transactions. +-- This module is used by the store owner. +-- +-- (a) Function 'compute_bill' : Computes the total amount payable for the +-- customer order. +-- (b) Procedure 'process_order' : Processes the customer-store transactions +-- and calls the 'compute_bill' function to +-- compute the customer bill. +-- (c) Procedure 'take_order' : Takes the customer order as input, inserts +-- it into the tables and generates the +-- customer bill. +-- (d) Procedure 'shipping' : Processes the shipping of products to the +-- customer. +-- +-- (4) Module 'supply_stock' : Processes the supplier-store transactions. +-- This module is used by the supplier. +-- +-- (a) Function 'compute_bill' : Computes the amount payable by the store +-- owner for each product supplied. +-- (b) Procedure 'process_order' : Processes the supplier-store transactions +-- and calls the function 'compute_bill' +-- to compute the store bill. +-- +-- (5) Standalone Compiled Compound Statement : +-- Calls the 'take_order' and 'shipping' procedures of +-- the module 'store_transactions' to process the +-- customer-store transactions and the 'process_order' +-- procedure of the module 'supply_stock' to process the +-- supplier-store transactions. +------------------------------------------------------------------------------- +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- CREATE TYPE +-- CREATE SEQUENCE +-- CREATE TRIGGER +-- CREATE VARIABLE +-- CREATE MODULE +-- ALTER MODULE PUBLISH TYPE +-- ALTER MODULE PUBLISH FUNCTION +-- ALTER MODULE PUBLISH PROCEDURE +-- ALTER MODULE ADD FUNCTION +-- ALTER MODULE ADD PROCEDURE +-- INSERT +-- SELECT +-- UPDATE +-- DROP MODULE +-- DROP TABLE +-- DROP TYPE +-- DROP SEQUENCE +-- DROP VARIABLE +------------------------------------------------------------------------------- + +-- Connect to 'sample' database +CONNECT TO sample@ + +----------------------------------------------------------------------------- +-- 1. Create and populate the tables 'inventory_details', 'product_details', +-- 'customer_details', 'purchaseorder_master', 'purchaseorder_details', +-- 'shipping' and 'supply_orders'. +----------------------------------------------------------------------------- + +-- Create table 'inventory_details' to store details of products available +-- with the supplier +CREATE TABLE inventory_details( + product_ID BIGINT NOT NULL, + quantity INTEGER, + location VARCHAR(20), + cost DECFLOAT, + PRIMARY KEY (product_ID))@ + +-- Insert existing values into the 'inventory_details' table +INSERT INTO inventory_details + VALUES(11, 50, 'warehouse', 80), + (12, 40, 'warehouse', 750), + (13, 35, 'store', 900), + (14, 25, 'warehouse', 2200), + (20, 60, 'store', 400), + (100, 55, 'warehouse', 10000), + (121, 25, 'warehouse', 8000)@ + +-- Create table 'product_details' to store details of the products available +-- in the store +CREATE TABLE product_details( + product_ID BIGINT NOT NULL, + product_name VARCHAR(10), + quantity_available INTEGER, + selling_price DECFLOAT, + PRIMARY KEY (product_ID), + CONSTRAINT fk_prodid2 FOREIGN KEY (product_ID) + REFERENCES inventory_details (product_ID) ON DELETE CASCADE)@ + +-- Insert existing product details into the 'product_details' table +INSERT INTO product_details + VALUES(11, 'VASE', 10, 100), + (12, 'CHAIR', 10, 900), + (13, 'TABLE', 6, 1100), + (14, 'BED', 4, 2500)@ + +-- Create table 'customer_details' to store the customer details +CREATE TABLE customer_details( + customer_ID BIGINT NOT NULL, + customer_name VARCHAR(15), + phoneno BIGINT, + address VARCHAR(50), + purchase_amount BIGINT, + PRIMARY KEY (customer_ID))@ + +-- Insert existing customer details into the 'customer_details' table +INSERT INTO customer_details + VALUES(1000, 'Bob', '9845245388', '104,Millers Street,Toronto', 6000), + (1001, 'Joe', '9876543012', '112,Fairview Lane,Ontario', 10000), + (1002, 'Pat', '9765909016', '15,Singer Street,Langsford', 4800), + (1003, 'Mat', '9890371322', '214,Hilton Street,Parksville', 5400)@ + +-- Tables 'purchaseorder_master' and 'purchaseorder_details' store the +-- customer order details. The master table 'purchaseorder_master' contains +-- details of the order such as the purchaseorder ID, order date, etc. +-- As a customer order may contain multiple products, a separate child table +-- 'purchaseorder_details' stores details of the products ordered. + +-- Create table 'purchaseorder_master' to store details of the orders +-- placed by the customers +CREATE TABLE purchaseorder_master( + purchaseorder_ID BIGINT NOT NULL, + customer_ID BIGINT NOT NULL, + order_date DATE, + status VARCHAR(10) NOT NULL WITH DEFAULT 'UNSHIPPED', + total_amount DECFLOAT WITH DEFAULT 0, + PRIMARY KEY (purchaseorder_ID), + CONSTRAINT fk_custid FOREIGN KEY (customer_ID) + REFERENCES customer_details (customer_ID) ON DELETE RESTRICT)@ + +-- Create table 'purchaseorder_details' to store details of products ordered +-- by the customers +CREATE TABLE purchaseorder_details( + purchaseorder_master_ID BIGINT NOT NULL, + product_ID BIGINT NOT NULL, + quantity_ordered INTEGER, + CONSTRAINT fk_poid1 FOREIGN KEY (purchaseorder_master_ID) + REFERENCES purchaseorder_master (purchaseorder_ID) ON DELETE CASCADE, + CONSTRAINT fk_prodid3 FOREIGN KEY (product_ID) + REFERENCES product_details (product_ID) ON DELETE CASCADE)@ + +-- Insert existing orders into the 'purchaseorder_master' table +INSERT INTO purchaseorder_master + VALUES(10497, 1000, '2008-03-11', 'UNSHIPPED', 2500), + (10498, 1003, '2008-02-15', 'SHIPPED', 2500), + (10499, 1001, '2008-03-10', 'UNSHIPPED', 4200)@ + +-- Insert existing orders into the 'purchaseorder_details' table +INSERT INTO purchaseorder_details + VALUES(10497, 12, 2), + (10498, 14, 1), + (10499, 11, 4), + (10499, 12, 1)@ + +-- Create table 'shipping' to store details of customer orders for shipping +CREATE TABLE shipping( + purchaseorder_ID BIGINT NOT NULL, + customer_ID BIGINT NOT NULL, + customer_address VARCHAR(50), + order_date DATE, + shipping_date DATE, + shipping_cost BIGINT, + CONSTRAINT fk_poid2 FOREIGN KEY (purchaseorder_ID) + REFERENCES purchaseorder_master (purchaseorder_ID) ON DELETE CASCADE, + CONSTRAINT fk_custid2 FOREIGN KEY (customer_ID) + REFERENCES customer_details (customer_ID) ON DELETE RESTRICT)@ + +-- Insert existing shipping details into the 'shipping' table +INSERT INTO shipping + VALUES(10498, + 1003, + '214,Hilton Street,Parksville', + '2008-02-15', + '2008-02-16', + 50)@ + +-- Create table 'supply_orders' that stores details of products that +-- need to be supplied to the store by the supplier +CREATE TABLE supply_orders( + store_ID BIGINT NOT NULL, + product_ID BIGINT NOT NULL, + quantity_required INTEGER, + status VARCHAR(30) NOT NULL, + CONSTRAINT fk_prodid1 FOREIGN KEY (product_ID) + REFERENCES inventory_details (product_ID) ON DELETE CASCADE)@ + +-- Insert existing values into the 'supply_orders' table +INSERT INTO supply_orders + VALUES(1106009, 11, 5, 'STOCK REPLENISHED'), + (2204510, 14, 20, 'STOCK REPLENISHED'), + (1106009, 14, 10, 'PENDING')@ + +----------------------------------------------------------------------------- +-- 2. Create sequence, row data types and global variables +----------------------------------------------------------------------------- + +-- Create a sequence to automatically generate purchase order IDs +CREATE OR REPLACE SEQUENCE purchaseorder_ID START WITH 10500@ + +-- Create an associative array type to store customer input values +CREATE TYPE assoc_array AS INTEGER ARRAY[INTEGER]@ + +-- Create row data types having the same fields as the columns in the +-- respective tables +CREATE TYPE order_stock_t AS ROW ANCHOR ROW OF supply_orders@ +CREATE TYPE product_stock_t AS ROW + (product_ID BIGINT, product_name VARCHAR(10))@ + +-- Create global boolean and row type variables +CREATE OR REPLACE VARIABLE value_v BOOLEAN@ +CREATE OR REPLACE VARIABLE product_stock_v product_stock_t@ + +----------------------------------------------------------------------------- +-- 3. Function 'replenish_stock' showcases : +-- - Row type variable as return type +-- - Usage of row type variable within a function +-- - Global variable support +----------------------------------------------------------------------------- + +CREATE OR REPLACE FUNCTION replenish_stock() +RETURNS order_stock_t +LANGUAGE SQL +BEGIN + ---------------------------- + -- Declaration Section + ---------------------------- + + -- Local variable declaration of row type 'order_stock_t' + DECLARE order_stock_v order_stock_t; + + ---------------------------- + -- Executable SQL Statements + ---------------------------- + + -- Populate values into the row type variable + SET order_stock_v.store_ID = 1106009; + SET order_stock_v.product_ID = product_stock_v.product_ID; + SET order_stock_v.quantity_required = 10; + SET order_stock_v.status = 'PENDING'; + + -- Print the details of products that need to be replenished + + -- Usage of global boolean variable 'value_v' + IF value_v = TRUE THEN + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('--------------------------------------------'); + CALL DBMS_OUTPUT.PUT_LINE('REPLENISH STOCK FOR THE FOLLOWING PRODUCTS :'); + CALL DBMS_OUTPUT.PUT_LINE('--------------------------------------------'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('***********************************************'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('PRODUCT ID'||' '||'PRODUCT NAME'||' '); + CALL DBMS_OUTPUT.PUT_LINE('----------'||' '||'------------'||' '); + END IF; + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT(product_stock_v.product_ID); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(product_stock_v.product_name); + + IF value_v = FALSE THEN + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('***********************************************'); + CALL DBMS_OUTPUT.NEW_LINE; + END IF; + + RETURN order_stock_v; +END@ + +----------------------------------------------------------------------------- +-- 4. Trigger 'check_stock' showcases : +-- - Full SQL PL support for Triggers +-- - Exit handler within a trigger +-- - Support for assignment to global variables +----------------------------------------------------------------------------- + +CREATE OR REPLACE TRIGGER check_stock +AFTER UPDATE OF quantity_available ON product_details +REFERENCING NEW AS new +FOR EACH ROW +BEGIN + ---------------------------- + -- Declaration Section + ---------------------------- + + -- Local variable declaration of row type 'order_stock_t' + DECLARE place_order_v order_stock_t; + + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE SQLCODE INTEGER DEFAULT 0; + DECLARE errorLabel CHAR(50) DEFAULT ''; + + -- Error Handler in case of SQL error + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE VALUE sqlstate SET MESSAGE_TEXT = errorLabel; + + ---------------------------- + -- Executable SQL Statements + ---------------------------- + + -- Assignment to global row type variable 'product_stock_v' + IF new.quantity_available < 5 THEN + SET product_stock_v.product_ID = new.product_ID; + SET product_stock_v.product_name = new.product_name; + + -- Call the function 'replenish_stock' + SET place_order_v = replenish_stock(); + + SET errorLabel = 'INSERT INTO supply_orders'; + + -- Populate the 'supply_orders' table with details of products that need + -- to be replenished + INSERT INTO supply_orders VALUES place_order_v; + + END IF; +END@ + +----------------------------------------------------------------------------- +-- 5. Create module 'store_transactions'. The module showcases encapsulation +-- via Public and Private object visibility. It also showcases support for +-- procedures, functions, cursor types and row data type creation and +-- usage within the module +----------------------------------------------------------------------------- + +echo --------------------------@ +echo Start Module Specification@ +echo --------------------------@ + +CREATE OR REPLACE MODULE store_transactions@ + +-- The objects specified in the module specification are visible outside the +-- module as they are defined with the 'PUBLISH' keyword + +-- Create row data types having the same fields as the columns in the +-- respective tables + +ALTER MODULE store_transactions PUBLISH TYPE product_t + AS ROW(product_ID BIGINT, product_name VARCHAR(10))@ + +ALTER MODULE store_transactions PUBLISH TYPE purchaseorder_master_t + AS ROW(purchaseorder_ID BIGINT, + customer_ID BIGINT, + order_date DATE, + status VARCHAR(10), + total_amount DECFLOAT)@ + +ALTER MODULE store_transactions PUBLISH TYPE purchaseorder_details_t + AS ROW ANCHOR ROW OF purchaseorder_details@ + +ALTER MODULE store_transactions PUBLISH TYPE customer_t + AS ROW ANCHOR ROW OF customer_details@ + +ALTER MODULE store_transactions PUBLISH TYPE stock_orders_t + AS ROW ANCHOR ROW OF supply_orders@ + +-- Create a type for collection of rows to store an array of row type variables +ALTER MODULE store_transactions PUBLISH TYPE purchaseorder_master_array_t + AS purchaseorder_master_t ARRAY[]@ + +-- Create Strong typed cursors that return a row of the corresponding row type + +ALTER MODULE store_transactions + PUBLISH TYPE purchaseorder_master_cursor_t + AS purchaseorder_master_t CURSOR@ + +ALTER MODULE store_transactions + PUBLISH TYPE purchaseorder_details_cursor_t + AS purchaseorder_details_t CURSOR@ + +-- Create procedure prototypes + +ALTER MODULE store_transactions + PUBLISH PROCEDURE take_order(customer_ID_p INTEGER, + productID_quantity_p assoc_array)@ + +ALTER MODULE store_transactions PUBLISH PROCEDURE shipping()@ + +echo ------------------------@ +echo End Module Specification@ +echo ------------------------@ + +echo ------------------------@ +echo Body of Module@ +echo ------------------------@ + +----------------------------------------------------------------------------- +-- 5.(a) Function 'compute_bill' (private module object) showcases : +-- - Full SQL PL support for functions +-- - Support for IN and OUT parameters +-- - Strong typed cursor as input parameter +-- - Cursor predicate 'IS NOT FOUND' +-- - Support for ANCHOR DATA TYPES +-- - Exit handler within a function +-- - Usage of row type variable +----------------------------------------------------------------------------- + +ALTER MODULE store_transactions ADD FUNCTION compute_bill + (IN products_ordered_p purchaseorder_details_cursor_t, + OUT customer_bill_p DECFLOAT) +RETURNS INTEGER +LANGUAGE SQL +BEGIN + ---------------------------- + -- Declaration Section + ---------------------------- + + -- Anchored scalar type in local variable declaration. This anchors the + -- datatype of the variable to that of the corresponding column in the table + DECLARE individual_cost_v ANCHOR DATA TYPE TO product_details.selling_price; + + DECLARE purchase_products_v purchaseorder_details_t; + + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE code, SQLCODE INTEGER DEFAULT 0; + DECLARE errorLabel CHAR(50) DEFAULT ''; + + -- Error Handler in case of SQL error + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE VALUE sqlstate SET MESSAGE_TEXT = errorLabel; + + ---------------------------- + -- Executable SQL Statements + ---------------------------- + + SET code = SQLCODE; + SET customer_bill_p = 0; + + -- SQL statements to compute the amount payable for the customer purchase + -- with a discount of 10% offered if the total cost exceeds 5,000 + + fetch_loop: + LOOP + -- Fetch input cursor value into row type variable 'purchase_products_v' + FETCH products_ordered_p INTO purchase_products_v; + + -- The cursor predicate 'IS NOT FOUND' checks whether a row has been + -- found for the cursor 'products_ordered_p' + IF products_ordered_p IS NOT FOUND + THEN LEAVE fetch_loop; + END IF; + + SET errorLabel = 'SELECT selling_price'; + + SELECT selling_price + INTO individual_cost_v + FROM product_details + WHERE product_ID = purchase_products_v.product_ID; + + SET customer_bill_p = + customer_bill_p + (individual_cost_v * + purchase_products_v.quantity_ordered); + + END LOOP fetch_loop; + + IF customer_bill_p > 5000 + THEN SET customer_bill_p = 0.90 * customer_bill_p; + END IF; + + CLOSE products_ordered_p; + +RETURN code; +END@ + + +------------------------------------------------------------------------------- +-- 5.(b) Procedure 'process_order' (private module object) showcases : +-- - Row type variable as an INOUT parameter +-- - Usage of row type variables within the procedure +-- - Strong typed cursor as OUT parameter +-- - Usage of strong and weak typed cursor within the procedure +-- - Passing of cursors between procedures and functions. +------------------------------------------------------------------------------- + +ALTER MODULE store_transactions ADD PROCEDURE process_order + (INOUT purchaseorder_master_p purchaseorder_master_t, + OUT products_ordered purchaseorder_details_cursor_t) +LANGUAGE SQL +BEGIN + ---------------------------- + -- Declaration Section + ---------------------------- + + DECLARE return_code_v INTEGER DEFAULT 0; + DECLARE customer_bill_v DECFLOAT; + + ---------------------------- + -- Executable SQL Statements + ---------------------------- + + -- Fetch details of products ordered using the strong typed cursor + -- 'products_ordered' + SET products_ordered = CURSOR FOR SELECT * FROM purchaseorder_details + WHERE purchaseorder_master_ID = purchaseorder_master_p.purchaseorder_ID; + + OPEN products_ordered; + + -- Call the function 'compute_bill' with the strong typed cursor + -- 'products_ordered' as IN parameter and the variable + -- 'customer_bill_v' to store the OUT parameter from the function + SET return_code_v = compute_bill(products_ordered, customer_bill_v); + + SET purchaseorder_master_p.total_amount = customer_bill_v; + + -- Update the 'purchaseorder_master' table with the total amount for + -- the transaction + UPDATE purchaseorder_master + SET total_amount = customer_bill_v + WHERE purchaseorder_ID = purchaseorder_master_p.purchaseorder_ID; + + -- Update the 'customer_details' table with the total transaction + -- amount till date of each customer + UPDATE customer_details + SET purchase_amount = purchase_amount + customer_bill_v + WHERE customer_ID = purchaseorder_master_p.customer_ID; + + -- Open the cursor again for the OUT parameter of the procedure + + OPEN products_ordered; +END@ + +----------------------------------------------------------------------------- +-- 5.(c) Procedure 'take_order' (public module object) showcases : +-- - Anchored data type as IN parameter +-- - Usage of row type and boolean variables +-- - Associative array functionality +-- - Print using the DBMS_OUTPUT module routine +----------------------------------------------------------------------------- + +ALTER MODULE store_transactions ADD PROCEDURE take_order + (IN customer_ID_p ANCHOR DATA TYPE TO purchaseorder_master.customer_ID, + IN productID_quantity_p assoc_array) +LANGUAGE SQL +BEGIN + ---------------------------- + -- Declaration Section + ---------------------------- + + -- Local variable declaration of row data types + DECLARE purchaseorder_master_v purchaseorder_master_t; + DECLARE products_v purchaseorder_details_t; + + -- Local declaration of strong typed cursor 'purchaseorder_details_cursor_t' + DECLARE products_cursor purchaseorder_details_cursor_t; + + DECLARE count_v INTEGER DEFAULT 0; + DECLARE product_name_v VARCHAR(10); + + ---------------------------- + -- Executable SQL Statements + ---------------------------- + + -- Insert customer input into the 'purchaseorder_master' and + -- 'purchaseorder_details' table + + SET purchaseorder_master_v.purchaseorder_ID = NEXT VALUE FOR purchaseorder_ID; + SET purchaseorder_master_v.customer_ID = customer_ID_p; + + INSERT INTO purchaseorder_master + VALUES (purchaseorder_master_v.purchaseorder_ID, + purchaseorder_master_v.customer_ID, + CURRENT DATE, + DEFAULT, + DEFAULT); + + -- Use the ARRAY_FIRST and ARRAY_NEXT functions to retrieve the first + -- and next index values respectively in the associative array + + SET count_v = ARRAY_FIRST(productID_quantity_p); + + -- Set a value for the global boolean variable + SET value_v = TRUE; + + while (count_v IS NOT NULL) do + + -- Populate the purchaseorder_ID, product_ID and quantity_ordered columns + -- of the 'purchaseorder_details' table and update the 'product_details' + -- table to reflect the reduction in stock in the store + + INSERT INTO purchaseorder_details + VALUES(purchaseorder_master_v.purchaseorder_ID, + count_v, + productID_quantity_p[count_v]); + + UPDATE product_details + SET quantity_available = quantity_available + - productID_quantity_p[count_v] + WHERE product_ID = count_v; + + SET value_v = FALSE; + SET count_v = ARRAY_NEXT(productID_quantity_p, count_v); + END while; + + -- Call procedure 'process_order' passing a row type variable as an + -- input parameter and a cursor variable to fetch the output parameter + + CALL process_order + (purchaseorder_master_v, products_cursor); + + -- Print the Customer Bill + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('-------------'); + CALL DBMS_OUTPUT.PUT_LINE('CUSTOMER BILL'); + CALL DBMS_OUTPUT.PUT_LINE('-------------'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('******************************************'); + + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE + ('TRANSACTION_ID : ' || purchaseorder_master_v.purchaseorder_ID); + CALL DBMS_OUTPUT.PUT_LINE('--------------'); + CALL DBMS_OUTPUT.NEW_LINE; + + CALL DBMS_OUTPUT.PUT + ('PRODUCT ID'||' '||'PRODUCT NAME'||' '||'QUANTITY ORDERED'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT + ('----------'||' '||'------------'||' '||'----------------'); + CALL DBMS_OUTPUT.NEW_LINE; + + -- Fetch the output from the 'process_order' procedure using the + -- cursor 'products_cursor' into the row type variable 'products_v' + + fetch_loop: + LOOP + FETCH products_cursor INTO products_v; + + IF products_cursor IS NOT FOUND + THEN LEAVE fetch_loop; + END IF; + + SELECT product_name + INTO product_name_v + FROM product_details + WHERE product_ID = products_v.product_ID; + + -- Print the products ordered by the customer + CALL DBMS_OUTPUT.PUT(products_v.product_ID); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(product_name_v); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(products_v.quantity_ordered); + CALL DBMS_OUTPUT.NEW_LINE; + + END LOOP fetch_loop; + CLOSE products_cursor; + + -- Print the total bill payable by the customer + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('TOTAL : ' || purchaseorder_master_v.total_amount); + CALL DBMS_OUTPUT.PUT_LINE('-----'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('******************************************'); + +END@ + +----------------------------------------------------------------------------- +-- 5.(d) Procedure 'shipping' (public module object) showcases : +-- - Strong typed cursor functionality +-- - Array of rows (collection of row types) functionality +----------------------------------------------------------------------------- + +ALTER MODULE store_transactions ADD PROCEDURE shipping() +LANGUAGE SQL +BEGIN + ---------------------------- + -- Declaration Section + ---------------------------- + DECLARE shipping_cost_v BIGINT DEFAULT 0; + DECLARE count_v INTEGER; + + -- Local variable declaration of collection of rows type + -- 'purchaseorder_master_array_t' + DECLARE order_v purchaseorder_master_array_t; + + -- Local variable declaration of row type 'customer_t' + DECLARE customer_v customer_t; + + -- Local variable declaration of strong typed cursor + -- 'purchaseorder_master_cursor_t' + DECLARE order_details purchaseorder_master_cursor_t; + + ---------------------------- + -- Executable SQL Statements + ---------------------------- + + SET count_v = 1; + + -- Strong typed cursor 'order_details' fetches details of 'UNSHIPPED' + -- transactions from the 'purchaseorder_master' table + + SET order_details = CURSOR FOR SELECT * FROM purchaseorder_master + WHERE status = 'UNSHIPPED'; + + OPEN order_details; + + fetch_loop: + LOOP + FETCH order_details INTO order_v[count_v]; + + IF order_details IS NOT FOUND + THEN LEAVE fetch_loop; + END IF; + + -- The shipping cost is waived off for customers with + -- a purchase amount of over 8000 + + SELECT * INTO customer_v + FROM customer_details + WHERE customer_ID = order_v[count_v].customer_ID; + + IF customer_v.purchase_amount > 8000 + THEN SET shipping_cost_v = 0; + ELSE SET shipping_cost_v = 50; + END IF; + + -- Populate the 'shipping' table with details of products shipped to + -- the customer + INSERT INTO shipping + VALUES (order_v[count_v].purchaseorder_ID, + customer_v.customer_ID, + customer_v.address, + order_v[count_v].order_date, + CURRENT DATE, + shipping_cost_v); + + -- Update the order status in the 'purchaseorder_master' table + UPDATE purchaseorder_master + SET status = 'SHIPPED' + WHERE purchaseorder_ID = order_v[count_v].purchaseorder_ID; + + SET count_v = count_v + 1; + + END LOOP fetch_loop; + CLOSE order_details; + +END@ + +echo ------------------------@ +echo End Module Body@ +echo ------------------------@ + +----------------------------------------------------------------------------- +-- 6. Create module 'supply_stock' used by the supplier. +----------------------------------------------------------------------------- + +echo --------------------------@ +echo Start Module Specification@ +echo --------------------------@ + +CREATE OR REPLACE MODULE supply_stock@ + +-- Create a prototype of the procedure 'process_order' +ALTER MODULE supply_stock PUBLISH PROCEDURE process_order(store_ID_p BIGINT)@ + +echo ------------------------@ +echo End Module Specification@ +echo ------------------------@ + +echo ------------------------@ +echo Body of Module@ +echo ------------------------@ + +----------------------------------------------------------------------------- +-- 6.(a) Function 'compute_bill' (private module object) showcases : +-- - Support for IN and INOUT parameters +-- - Anchored data type variable as IN parameter +----------------------------------------------------------------------------- + +ALTER MODULE supply_stock ADD FUNCTION compute_bill + (IN supply_product_p ANCHOR DATA TYPE TO ROW OF supply_orders, + INOUT store_bill_p DECFLOAT, + IN bulk_order_p INTEGER) +RETURNS INTEGER +LANGUAGE SQL +BEGIN + ---------------------------- + -- Declaration Section + ---------------------------- + + DECLARE bill_v DECFLOAT DEFAULT 0; + DECLARE cost_price_v DECFLOAT DEFAULT 0; + + DECLARE code INTEGER DEFAULT 0; + DECLARE SQLCODE INTEGER; + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN + SET code = SQLCODE; + RETURN code; + END; + + ---------------------------- + -- Executable SQL Statements + ---------------------------- + + -- Procure the cost of each product from the 'inventory_details' table + SELECT cost + INTO cost_price_v + FROM inventory_details + WHERE product_ID = supply_product_p.product_ID; + + -- Offer a discount to the store in case of bulk orders and compute the bill + IF bulk_order_p > 2 + THEN SET bill_v = 0.80 * (cost_price_v * supply_product_p.quantity_required); + ELSE + SET bill_v = cost_price_v * supply_product_p.quantity_required; + END IF; + + SET store_bill_p = store_bill_p + bill_v; + +RETURN code; +END@ + +----------------------------------------------------------------------------- +-- 6.(b) Procedure 'process_order' (public module object) showcases : +-- - Weak typed and parameterized cursor functionality +----------------------------------------------------------------------------- + +ALTER MODULE supply_stock ADD PROCEDURE process_order(IN store_ID_p BIGINT) +LANGUAGE SQL +BEGIN + ---------------------------- + -- Declaration Section + ---------------------------- + -- Local variable declaration of anchored data type + DECLARE supply_product_v ANCHOR DATA TYPE TO ROW OF supply_orders; + + DECLARE return_code_v INTEGER DEFAULT 0; + DECLARE bulk_order_v INTEGER DEFAULT 0; + DECLARE store_bill_v DECFLOAT DEFAULT 0; + + -- Declaration of weak typed cursor 'supply_pending' + DECLARE supply_pending CURSOR; + + ---------------------------- + -- Executable SQL Statements + ---------------------------- + -- Print the Store Bill + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('-----------'); + CALL DBMS_OUTPUT.PUT_LINE('STORE BILL'); + CALL DBMS_OUTPUT.PUT_LINE('-----------'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('******************************************'); + + CALL DBMS_OUTPUT.PUT('STORE ID'||' '||'PRODUCT ID'||' '); + CALL DBMS_OUTPUT.PUT('QUANTITY SUPPLIED'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT('--------'||' '||'----------'||' '); + CALL DBMS_OUTPUT.PUT('-----------------'); + CALL DBMS_OUTPUT.NEW_LINE; + + -- Fetch the count of total number of orders placed by the store + SELECT count(*) + INTO bulk_order_v + FROM supply_orders + WHERE store_ID = store_ID_p; + + -- Use 'parameterized cursor' to fetch the details of products that + -- need to be supplied to the store + SET supply_pending = CURSOR(store_ID_v BIGINT) FOR SELECT * FROM supply_orders + WHERE store_ID = store_ID_v AND status = 'PENDING'; + + OPEN supply_pending(store_ID_p); + + fetch_loop: + LOOP + FETCH supply_pending INTO supply_product_v; + + IF supply_pending IS NOT FOUND + THEN LEAVE fetch_loop; + END IF; + + -- Update the 'inventory_details' table once the products are supplied + UPDATE inventory_details + SET quantity = quantity - (supply_product_v.quantity_required) + WHERE product_ID = supply_product_v.product_ID; + + -- Call the function 'compute_bill' to compute the bill for the store. + -- 'store_bill_v' is an INOUT parameter to the function + SET return_code_v = compute_bill(supply_product_v, store_bill_v, + bulk_order_v); + + -- Update the supply status in the 'supply_orders' table + UPDATE supply_orders + SET status = 'STOCK REPLENISHED' + WHERE store_ID = supply_product_v.store_ID + AND product_ID = supply_product_v.product_ID + AND status = 'PENDING'; + + -- Update the 'product_details' table to reflect the replenished stock + UPDATE product_details + SET quantity_available = quantity_available + + supply_product_v.quantity_required + WHERE product_ID = supply_product_v.product_ID; + + -- Print details of products supplied + CALL DBMS_OUTPUT.PUT(supply_product_v.store_ID); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(supply_product_v.product_ID); + CALL DBMS_OUTPUT.PUT(' '); + CALL DBMS_OUTPUT.PUT(supply_product_v.quantity_required); + CALL DBMS_OUTPUT.NEW_LINE; + + END LOOP fetch_loop; + CLOSE supply_pending; + + -- Print the total bill payable to the supplier + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('TOTAL : ' || store_bill_v); + CALL DBMS_OUTPUT.PUT_LINE('-----'); + CALL DBMS_OUTPUT.NEW_LINE; + CALL DBMS_OUTPUT.PUT_LINE('******************************************'); + +END@ + +echo ------------------------@ +echo End Module Body@ +echo ------------------------@ + +----------------------------------------------------------------------------- +-- 7. Standalone compiled compound statement showcases : +-- - Full SQL PL support for such blocks +-- - Associative array functionality +-- - Anchored data type functionality +-- - Exit handler within a compiled compound statement +----------------------------------------------------------------------------- + +-- 'SET SERVEROUTPUT ON' to redirect the output to standard output +SET SERVEROUTPUT ON@ + +BEGIN + ---------------------------- + -- Declaration Section + ---------------------------- + -- Local variable declaration of associative array type + DECLARE productID_quantity_v assoc_array; + + DECLARE customer_ID_v ANCHOR DATA TYPE TO purchaseorder_master.customer_ID; + DECLARE no_of_purchaseorders_v INTEGER; + DECLARE store_ID_v BIGINT; + + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE SQLCODE INTEGER DEFAULT 0; + DECLARE errorLabel CHAR(50) DEFAULT ''; + + -- Error Handler in case of SQL error + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE VALUE sqlstate SET MESSAGE_TEXT = errorLabel; + + ---------------------------- + -- Executable SQL Statements + ---------------------------- + -- Accept the customer input in an associative array + SET customer_ID_v = 1002; + SET productID_quantity_v[12] = 6; + SET productID_quantity_v[13] = 2; + + --------------------------------------------------------------------------- + -- Call the procedure 'store_transactions.take_order' to start the + -- customer-store transaction processing + --------------------------------------------------------------------------- + + -- Pass the associative array input to the 'take_order' procedure for further + -- processing + CALL store_transactions.take_order + (customer_ID_v, productID_quantity_v); + + --------------------------------------------------------------------------- + -- Call the 'store_transactions.shipping' procedure for product delivery + --------------------------------------------------------------------------- + -- Fetch the count of number of 'UNSHIPPED' orders + + SET errorLabel = 'SELECT COUNT'; + + SELECT count(*) + INTO no_of_purchaseorders_v + FROM purchaseorder_master + WHERE status = 'UNSHIPPED'; + + -- Call the 'shipping' procedure based on the number of unshipped orders + IF no_of_purchaseorders_v > 2 + THEN CALL store_transactions.shipping(); + END IF; + + ------------------------------------------------------------------------------ + -- Call the procedure 'supply_stock.process_order' to start the supplier-store + -- transaction processing + ------------------------------------------------------------------------------ + + SET store_ID_v = 1106009; + + -- Use 2-part name to call the object 'process_order' common to both the modules + CALL supply_stock.process_order(store_ID_v); + +END@ + +SET SERVEROUTPUT OFF@ + +------------------------------------------------ +-- 8. Drop the tables and types created +------------------------------------------------ + +DROP TABLE purchaseorder_master@ +DROP TABLE purchaseorder_details@ +DROP TABLE customer_details@ +DROP TABLE product_details@ +DROP TABLE shipping@ +DROP TABLE inventory_details@ +DROP TABLE supply_orders@ +DROP TYPE order_stock_t@ +DROP TYPE product_stock_t@ +DROP TYPE assoc_array@ diff --git a/sqlpl/nestcase.db2 b/sqlpl/nestcase.db2 new file mode 100644 index 0000000..e0b00af --- /dev/null +++ b/sqlpl/nestcase.db2 @@ -0,0 +1,105 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: nestcase.db2 +-- +-- SAMPLE: To create the BUMP_SALARY SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf nestcase.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL bump_salary (51)" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "nestcase", using the nestcase.sqc +-- source file available in the sqlpl samples directory. +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CREATE PROCEDURE bump_salary (IN deptnumber SMALLINT) +LANGUAGE SQL +BEGIN + DECLARE SQLSTATE CHAR(5); + DECLARE v_salary DOUBLE; + DECLARE v_id SMALLINT; + DECLARE v_years SMALLINT; + DECLARE at_end INT DEFAULT 0; + DECLARE not_found CONDITION FOR SQLSTATE '02000'; + + DECLARE C1 CURSOR FOR + SELECT id, CAST(salary AS DOUBLE), years + FROM staff + WHERE dept = deptnumber; + DECLARE CONTINUE HANDLER FOR not_found + SET at_end = 1; + + OPEN C1; + FETCH C1 INTO v_id, v_salary, v_years; + WHILE at_end = 0 DO + CASE + WHEN (v_salary < 15000 * v_years) + THEN CASE + WHEN (15500*v_years > 99000) + THEN UPDATE staff + SET salary = 99000 + WHERE id = v_id; + ELSE UPDATE staff + SET salary = 15500* v_years + WHERE id = v_id; + END CASE; + WHEN (v_salary < 30000 * v_years) + THEN CASE + WHEN (v_salary < 20000 * v_years) + THEN CASE + WHEN (20000*v_years > 99000) + THEN UPDATE staff + SET salary = 99000 + WHERE id = v_id; + ELSE UPDATE staff + SET salary = 20000 * v_years + WHERE id = v_id; + END CASE; + ELSE UPDATE staff + SET salary = v_salary * 1.10 + WHERE id = v_id; + END CASE; + ELSE UPDATE staff + SET job = 'PREZ' + WHERE id = v_id; + END CASE; + FETCH C1 INTO v_id, v_salary, v_years; + END WHILE; + CLOSE C1; +END @ diff --git a/sqlpl/nestcase.sqc b/sqlpl/nestcase.sqc new file mode 100644 index 0000000..6bed851 --- /dev/null +++ b/sqlpl/nestcase.sqc @@ -0,0 +1,224 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: nestcase.sqc +** +** SAMPLE: To call the BUMP_SALARY SQL procedure +** +** There are two parts to this program: +** 1. the nestcase executable (placed on the client) +** 2. the BUMP_SALARY SQL procedure (created on the +** server with the nestcase.db2 CLP script) +** +** nestcase calls the BUMP_SALARY SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(stmt, "CALL %s (?)", procname); +** EXEC SQL prepare st from :stmt; +** EXEC SQL execute st USING :dept:deptind; +** +** When the CALL with Host Variable is used, +** the precompiler allocates and initializes an internal one +** variable SQLDA for both input and output. +** +** The BUMP_SALARY procedure uses nested CASE statements to raise +** the salaries of employees in a department identified by +** the dept IN parameter from the "staff" table of the +** "sample" database. +** +** A cursor fetches rows from the "staff" table until the +** "not_found" (end of file) condition is met and the handler +** sets the value of the "at_end" variable to 1, ending the +** WHILE loop. +** +** The first CASE statement provides three CASE conditions: +** +** Condition 1: Employee salary is less than 2000 * years of service +** Result: Employee salary is updated to 2000 * years of service +** +** Condition 2: Employee salary is less than 5000 * years of service +** (Note that an employee that satisfies condition 1 cannot also +** satisfy condition 2, because the CASE statement exits after the +** first condition was matched.) +** Result: Invoke nested CASE statement 2. +** +** Condition 3: Employee salary does not match condition 1 or 2. +** Result: Update employee job to 'PREZ'. Note that any employee +** with a NULL salary would have their job updated to 'PREZ'. +** +** SQL STATEMENTS USED: +** CONNECT +** DECLARE CURSOR +** OPEN +** FETCH +** CLOSE +** CALL +** +** OUTPUT FILE: nestcase.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "BUMP_SALARY"; + + /* Declare a statement string to call the procedure dynamically */ + char stmt[1200]; + + /* Declare local variables for cursor statements */ + char name[10]; + sqlint16 dept_c = 0; + sqlint16 years = 0; + double salary = 0; + char job[6]; + + /* Declare Local Variables for Holding Returned Data */ + sqlint16 deptnum = 51; + sqlint16 deptind = 0; + EXEC SQL END DECLARE SECTION; + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); /* :rk.2:erk. */ + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: nestcase remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + /********************************************************\ + * Display the contents of STAFF table before CALL * + \********************************************************/ + + EXEC SQL DECLARE c1 CURSOR FOR + SELECT name, dept, years, salary, job FROM staff + WHERE dept = :deptnum + FOR READ ONLY; + + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN CURSOR"); + + printf("\nDepartment %d before calling %s:\n", deptnum, procname); + printf("\n%-9s %6s %5s %10s %-5s\n", "NAME", "DEPT", "YEARS", "SALARY", "JOB"); + do { + EXEC SQL FETCH c1 INTO :name, :dept_c, :years, :salary, :job; + if (SQLCODE != 0) break; + + printf( "%-9s %6d %5d %10.2f %-5s\n", name, dept_c, years, salary, job ); + } while ( 1 ); + + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("CLOSE CURSOR"); + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + printf("\nUse CALL with Host Variable to invoke the Server Procedure " + "named %s\n", procname); + sprintf(stmt, "CALL %s (?)", procname); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPARE CALL STATEMENT"); + + EXEC SQL execute st USING :deptnum:deptind; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN CURSOR"); + + printf("\nDepartment %d after calling %s:\n", deptnum, procname); + printf("%-9s %6s %5s %10s %-5s\n", "NAME", "DEPT", "YEARS", "SALARY", "JOB"); + do { + EXEC SQL FETCH c1 INTO :name, :dept_c, :years, :salary, :job; + if (SQLCODE != 0) break; + + printf("%-9s %6d %5d %10.2f %-5s\n", name, dept_c, years, salary, job ); + } while ( 1 ); + + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("CLOSE CURSOR"); + + EXEC SQL ROLLBACK; + /* to preserve the sample database, changes are not committed; + to commit the changes, you should use: + EXEC SQL COMMIT */ + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : nestcase.sqc */ + diff --git a/sqlpl/nestedsp.db2 b/sqlpl/nestedsp.db2 new file mode 100644 index 0000000..910befc --- /dev/null +++ b/sqlpl/nestedsp.db2 @@ -0,0 +1,126 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: nestedsp.db2 +-- +-- SAMPLE: To create the OUT_AVERAGE, OUT_MEDIAN and MAX_SALARY SQL procedures +-- which are used to calculate the average salary, median salary and +-- maximum salary of the EMPLOYEE table respectively. +-- +-- To create the SQL procedures: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf nestedsp.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL out_average (?,?,?)" +-- +-- To drop the SQL stored procedures created with nestedsp.db2 script: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf nestedspdrop.db2" +-- +-- You can also call this SQL procedure by compiling and running the +-- Java client application using the NestedSP.java +-- source file available in the sqlpl samples directory. +---------------------------------------------------------------------------- + +CREATE PROCEDURE MAX_SALARY (OUT maxSalary DOUBLE) +LANGUAGE SQL +READS SQL DATA + +BEGIN + + SELECT MAX(salary) INTO maxSalary FROM staff; + +END @ + + +CREATE PROCEDURE OUT_MEDIAN (OUT medianSalary DOUBLE, OUT maxSalary DOUBLE) +DYNAMIC RESULT SETS 0 +LANGUAGE SQL +MODIFIES SQL DATA +BEGIN + + DECLARE v_numRecords INT DEFAULT 1; + DECLARE v_counter INT DEFAULT 0; + DECLARE v_mod INT DEFAULT 0; + DECLARE v_salary1 DOUBLE DEFAULT 0; + DECLARE v_salary2 DOUBLE DEFAULT 0; + + DECLARE c1 CURSOR FOR + SELECT CAST(salary AS DOUBLE) FROM staff + ORDER BY salary; + + SELECT COUNT(*) INTO v_numRecords FROM staff; + + SET v_mod = MOD(v_numRecords, 2); + OPEN c1; + + CASE v_mod + WHEN 0 THEN + WHILE v_counter < (v_numRecords / 2 + 1) DO + SET v_salary1 = v_salary2; + FETCH c1 INTO v_salary2; + SET v_counter = v_counter + 1; + END WHILE; + SET medianSalary = (v_salary1 + v_salary2)/2; + WHEN 1 THEN + WHILE v_counter < (v_numRecords / 2 + 1) DO + FETCH c1 INTO medianSalary; + SET v_counter = v_counter + 1; + END WHILE; + END CASE; + + CLOSE c1; + + CALL MAX_SALARY(maxSalary); + +END @ + + +CREATE PROCEDURE OUT_AVERAGE (OUT averageSalary DOUBLE, OUT medianSalary DOUBLE, OUT maxSalary DOUBLE) +DYNAMIC RESULT SETS 2 +LANGUAGE SQL +MODIFIES SQL DATA +BEGIN + + DECLARE r1 CURSOR WITH RETURN TO CLIENT FOR + SELECT name, job, CAST(salary AS DOUBLE) + FROM staff + WHERE salary > averageSalary + ORDER BY name ASC; + + DECLARE r2 CURSOR WITH RETURN TO CLIENT FOR + SELECT name, job, CAST(salary AS DOUBLE) + FROM staff + WHERE salary < averageSalary + ORDER BY name ASC; + + SELECT AVG(salary) INTO averageSalary FROM staff; + CALL OUT_MEDIAN(medianSalary, maxSalary); + + -- open the cursors to return result sets + OPEN r1; + + OPEN r2; + +END @ + diff --git a/sqlpl/nestedspdrop.db2 b/sqlpl/nestedspdrop.db2 new file mode 100644 index 0000000..efd987f --- /dev/null +++ b/sqlpl/nestedspdrop.db2 @@ -0,0 +1,49 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: nestedspdrop.db2 +-- +-- SAMPLE: To drop the OUT_AVERAGE, OUT_MEADIN and MAX_SALARY SQL procedures +-- that are created with the nestedsp.db2 script. +-- +-- To drop the SQL procedures: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf nestedspdrop.db2" +-- +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +DROP PROCEDURE OUT_AVERAGE (DOUBLE, DOUBLE, DOUBLE) @ + +DROP PROCEDURE OUT_MEDIAN (DOUBLE, DOUBLE) @ + +DROP PROCEDURE MAX_SALARY(DOUBLE) @ + diff --git a/sqlpl/nestif.db2 b/sqlpl/nestif.db2 new file mode 100644 index 0000000..328fb9e --- /dev/null +++ b/sqlpl/nestif.db2 @@ -0,0 +1,100 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: nestif.db2 +-- +-- SAMPLE: To create the BUMP_SALARY_IF SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf nestif.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL bump_salary_if (20)" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "nestif", using the nestif.sqc +-- source file available in the sqlpl samples directory. +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CREATE PROCEDURE bump_salary_if (IN deptnumber SMALLINT) +LANGUAGE SQL +BEGIN + DECLARE SQLSTATE CHAR(5); + DECLARE v_salary DOUBLE; + DECLARE v_years SMALLINT; + DECLARE v_id SMALLINT; + DECLARE at_end INT DEFAULT 0; + DECLARE not_found CONDITION FOR SQLSTATE '02000'; + + DECLARE C1 CURSOR FOR + SELECT id, CAST(salary AS DOUBLE), years + FROM staff; + DECLARE CONTINUE HANDLER FOR not_found + SET at_end = 1; + + OPEN C1; + FETCH C1 INTO v_id, v_salary, v_years; + WHILE at_end = 0 DO + IF (v_salary < 15000 * v_years) + THEN IF (15500*v_years > 99000) + THEN UPDATE staff + SET salary = 99000 + WHERE id = v_id; + ELSE UPDATE staff + SET salary =2150 * v_years + WHERE id = v_id; + END IF; + ELSEIF (v_salary < 30000 * v_years) + THEN IF (v_salary < 20000 * v_years) + THEN IF (20000*v_years > 99000) + THEN UPDATE staff + SET salary = 99000 + WHERE id = v_id; + ELSE UPDATE staff + SET salary = 20000 * v_years + WHERE id = v_id; + END IF; + ELSE UPDATE staff + SET salary = v_salary * 1.10 + WHERE id = v_id; + END IF; + ELSE UPDATE staff + SET job = 'PREZ' + WHERE id = v_id; + END IF; + FETCH C1 INTO v_id, v_salary, v_years; + END WHILE; + CLOSE C1; +END @ diff --git a/sqlpl/nestif.sqc b/sqlpl/nestif.sqc new file mode 100644 index 0000000..a6483fe --- /dev/null +++ b/sqlpl/nestif.sqc @@ -0,0 +1,226 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: nestif.sqc +** +** SAMPLE: To call the BUMP_SALARY_IF SQL procedure +** +** There are two parts to this program: +** 1. the nestif executable (placed on the client) +** 2. the BUMP_SALARY_IF SQL procedure (created on the +** server with the nestif.db2 CLP script) +** +** nestif calls the BUMP_SALARY_IF SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(stmt, "CALL %s (?)", procname); +** EXEC SQL prepare st from :stmt; +** EXEC SQL execute st USING :dept:deptind; +** +** When the CALL with Host Variable is used, +** the precompiler allocates and initializes an internal one +** variable SQLDA for both input and output. +** +** The BUMP_SALARY procedure uses nested IF statements to raise +** the salaries of employees in a department identified by +** the deptnum IN parameter from the "staff" table of the +** "sample" database. +** +** A cursor fetches rows from the "staff" table until the +** "not_found" (end of file) condition is met and the handler +** sets the value of the "at_end" variable to 1, ending the +** WHILE loop. +** +** The first IF statement provides three IF conditions: +** +** Condition 1: Employee salary is less than 2000 * years of service +** Result: Employee salary is updated to 2000 * years of service +** +** Condition 2: Employee salary is less than 5000 * years of service +** (Note that an employee that satisfies condition 1 cannot also +** satisfy condition 2, because the IF statement exits after the +** first condition was matched.) +** Result: Call nested IF statement 2. +** +** Condition 3: Employee salary does not match condition 1 or 2. +** Result: Update employee job to 'PREZ'. Note that any employee +** with a NULL salary would have their job updated to 'PREZ'. +** +** SQL STATEMENTS USED: +** CONNECT +** DECLARE CURSOR +** OPEN +** FETCH +** CLOSE +** CALL +** +** OUTPUT FILE: nestif.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "BUMP_SALARY_IF"; + + /* Declare a statement strings to call the procedure dynamically */ + char stmt[1200]; + + /* Declare local variables for cursor statements */ + char name[10]; + sqlint16 dept_c = 0; + sqlint16 years = 0; + double salary = 0; + char job[6]; + + /* Declare Local Variables for Holding Returned Data */ + sqlint16 deptnum = 20; + sqlint16 deptind = 0; + EXEC SQL END DECLARE SECTION; + + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); /* :rk.2:erk. */ + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: nestif remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + /********************************************************\ + * Display the contents of STAFF table before CALL * + \********************************************************/ + + EXEC SQL DECLARE c1 CURSOR FOR + SELECT name, dept, years, salary, job FROM staff + WHERE dept = :deptnum + FOR READ ONLY; + + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN CURSOR"); + + printf("\nDepartment %d before calling %s:\n", deptnum, procname); + printf("\n%-9s %6s %5s %10s %-5s\n", "NAME", "DEPT", "YEARS", "SALARY", "JOB"); + do { + EXEC SQL FETCH c1 INTO :name, :dept_c, :years, :salary, :job; + if (SQLCODE != 0) break; + + printf( "%-9s %6d %5d %10.2f %-5s\n", name, dept_c, years, salary, job ); + } while ( 1 ); + + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("CLOSE CURSOR"); + + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + printf("\nUse CALL with Host Variable to invoke the Server Procedure " + "named %s\n", procname); + sprintf(stmt, "CALL %s (?)", procname); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPATE CALL STATEMENT"); + + EXEC SQL execute st USING :deptnum:deptind; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN CURSOR"); + + printf("\nDepartment %d after calling %s:\n", deptnum, procname); + printf("%-9s %6s %5s %10s %-5s\n", "NAME", "DEPT", "YEARS", "SALARY", "JOB"); + do { + EXEC SQL FETCH c1 INTO :name, :dept_c, :years, :salary, :job; + if (SQLCODE != 0) break; + + printf("%-9s %6d %5d %10.2f %-5s\n", name, dept_c, years, salary, job ); + } while ( 1 ); + + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("CLOSE CURSOR"); + + EXEC SQL ROLLBACK; + /* to preserve the sample database, changes are not committed; + to commit the changes, you should use: + EXEC SQL COMMIT */ + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : nestif.sqc */ + diff --git a/sqlpl/repeat.db2 b/sqlpl/repeat.db2 new file mode 100644 index 0000000..73a5a53 --- /dev/null +++ b/sqlpl/repeat.db2 @@ -0,0 +1,86 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: repeat.db2 +-- +-- SAMPLE: To create the REPEAT_STMT SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf repeat.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL repeat_stmt (?)" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "repeat", using the repeat.sqc +-- source file available in the sqlpl samples directory. +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CREATE PROCEDURE repeat_stmt(OUT counter INT) +LANGUAGE SQL +BEGIN + DECLARE SQLSTATE CHAR(5); + DECLARE v_firstnme VARCHAR(12); + DECLARE v_midinit CHAR(1); + DECLARE v_lastname VARCHAR(15); + DECLARE at_end SMALLINT DEFAULT 0; + DECLARE v_counter SMALLINT DEFAULT 0; + + DECLARE not_found + CONDITION FOR SQLSTATE '02000'; + DECLARE c1 CURSOR FOR + SELECT firstnme, midinit, lastname + FROM employee; + DECLARE CONTINUE HANDLER FOR not_found + SET at_end = 1; + + -- initialize OUT parameter + SET counter = 0; + OPEN c1; + fetch_loop: + REPEAT + FETCH c1 INTO + v_firstnme, v_midinit, v_lastname; + -- Use a local variable for the iterator variable + -- because SQL procedures only allow you to assign + -- values to an OUT parameter + SET v_counter = v_counter + 1; + -- Now assign the value of the local + -- variable to the OUT parameter + SET counter = v_counter; + UNTIL at_end <> 0 + END REPEAT fetch_loop; + CLOSE c1; +END @ diff --git a/sqlpl/repeat.sqc b/sqlpl/repeat.sqc new file mode 100644 index 0000000..2218400 --- /dev/null +++ b/sqlpl/repeat.sqc @@ -0,0 +1,163 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: repeat.sqc +** +** SAMPLE: To call the REPEAT_STMT SQL procedure +** +** There are two parts to this program: +** 1. the repeat executable (placed on the client) +** 2. the REPEAT_STMT SQL procedure (created on the +** server with the repeat.db2 CLP script) +** +** repeat calls the REPEAT_STMT SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(stmt, "CALL %s (?)", procname); +** EXEC SQL prepare st from :stmt; +** EXEC SQL execute st INTO :count:countind; +** +** When the CALL with Host Variable is used, +** the precompiler allocates and initializes an internal one +** variable SQLDA for both input and output. +** +** The REPEAT_STMT procedure counts the number of FETCH +** operations performed in a repeat statement until the cursor +** can retrieve no more rows. +** The condition handler causes the flow of control to exit +** the repeat loop and complete the stored procedure. +** +** The counter value is assigned to the counter OUT parameter +** that is returned to the repeat client. The repeat client +** then prints the counter value. +** +** SQL STATEMENTS USED: +** CONNECT +** CALL +** +** OUTPUT FILE: repeat.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "REPEAT_STMT"; + + /* Declare a statement strings to call the procedure dynamically */ + char stmt[1200]; + + /* Declare Local Variables for Passing Data to SQL Procedure */ + sqlint32 count = 0; + sqlint16 countind = 0; + EXEC SQL END DECLARE SECTION; + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: repeat remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + printf("Use CALL with Host Variables to invoke the Server Procedure " + "named %s\n", procname); + countind = -1; /* count has no input, so set to null */ + sprintf(stmt, "CALL %s (?)", procname); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPARE CALL STATEMENT"); + + EXEC SQL execute st INTO :count:countind; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + /********************************************************\ + * Display the # of times the repeat statement iterated * + \********************************************************/ + + printf("\nREPEAT statement iterated %d times before invoking NOT FOUND condition\n", count); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { /* Rollback the changes to the database */ + EXEC SQL ROLLBACK; + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : repeat.sqc */ + diff --git a/sqlpl/rsultset.c b/sqlpl/rsultset.c new file mode 100644 index 0000000..85298f5 --- /dev/null +++ b/sqlpl/rsultset.c @@ -0,0 +1,156 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: rsultset.c +** +** SAMPLE: To call the MEDIAN_RESULT_SET SQL procedure +** +** The program demonstrates how to return a result set from a stored +** procedure. +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLPrepare -- Prepare a Statement +** SQLBindParameter -- Bind a Parameter Marker to a Buffer or +** LOB locator +** SQLExecute -- Execute a Statement +** SQLMoreResults -- Determine if There Are More Result Sets +** SQLFreeHandle -- Free Handle Resources +** SQLEndTran -- End Transactions of a Connection +** SQLDisconnect -- Disconnect from a Data Source +** +** OUTPUT FILE: rsultset.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures, see the Application +** Development Guide. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ + +int main( int argc, char * argv[] ) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + int count = 1; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + SQLHANDLE hstmt; /* statement handle */ + SQLINTEGER outSqlrc; + SQLDOUBLE medianSalary = 0; + SQLSMALLINT numCols; + SQLCHAR outName[40]; + SQLCHAR outJob[10]; + char procName[] = "MEDIAN_RESULT_SET"; + SQLCHAR *stmt = (SQLCHAR *) "CALL MEDIAN_RESULT_SET (?)"; + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + char language[9]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF); + if (rc != 0) + { + return rc; + } + + printf("\nHOW TO CALL AN SQL STORED PROCEDURE."); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind parameter 1 to the statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_OUTPUT, + SQL_C_DOUBLE, + SQL_DOUBLE, + 0, + 0, + &medianSalary, + 0, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\n\nMedian salary: %.2f", medianSalary); + + do + { + printf("\n\nReturning result set #%d:\n", count); + cliRC = StmtResultPrint(hstmt, hdbc); + DBC_HANDLE_CHECK( hdbc, cliRC ); + count++; + } + + while (SQLMoreResults(hstmt) == SQL_SUCCESS); + + + /* free the statement handles */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* terminate the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; +} /* end main */ diff --git a/sqlpl/rsultset.db2 b/sqlpl/rsultset.db2 new file mode 100644 index 0000000..8899bbb --- /dev/null +++ b/sqlpl/rsultset.db2 @@ -0,0 +1,102 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: rsultset.db2 +-- +-- SAMPLE: To register and create the MEDIAN_RESULT_SET SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf rsultset.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL median_result_set (?)" +-- +-- You can also call this SQL procedure by compiling and running the +-- CLI client application, "rsultset", using the rsultset.c +-- source file available in the sqlpl samples directory. +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CREATE PROCEDURE median_result_set +-- Declare medianSalary as OUT so it can be used to return values +(OUT medianSalary DOUBLE) +RESULT SETS 2 +LANGUAGE SQL +BEGIN + DECLARE v_numRecords INT DEFAULT 1; + DECLARE v_counter INT DEFAULT 0; + + DECLARE c1 CURSOR FOR + SELECT salary FROM staff + ORDER BY CAST(salary AS DOUBLE); + + -- use WITH RETURN in DECLARE CURSOR to return a result set + DECLARE c2 CURSOR WITH RETURN FOR + SELECT name, job, salary + FROM staff + WHERE CAST(salary AS DOUBLE) > medianSalary + ORDER BY salary; + + -- you can return as many result sets as you like, just + -- ensure that the exact number is declared in the RESULT SETS + -- clause of the CREATE PROCEDURE statement + + -- use WITH RETURN in DECLARE CURSOR to return another result set + DECLARE c3 CURSOR WITH RETURN FOR + SELECT name, job, salary + FROM staff + WHERE CAST(salary AS DOUBLE) < medianSalary + ORDER BY SALARY DESC; + + DECLARE CONTINUE HANDLER FOR NOT FOUND + SET medianSalary = 6666; + + -- initialize OUT parameter + SET medianSalary = 0; + + SELECT COUNT(*) INTO v_numRecords FROM STAFF; + + OPEN c1; + WHILE v_counter < (v_numRecords / 2 + 1) DO + FETCH c1 INTO medianSalary; + SET v_counter = v_counter + 1; + END WHILE; + CLOSE c1; + + -- return 1st result set, do not CLOSE cursor + OPEN c2; + + -- return 2nd result set, do not CLOSE cursor + OPEN c3; +END @ diff --git a/sqlpl/spserver.db2 b/sqlpl/spserver.db2 new file mode 100644 index 0000000..a9851b0 --- /dev/null +++ b/sqlpl/spserver.db2 @@ -0,0 +1,549 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: spserver.db2 +-- +-- SAMPLE: To create a set of SQL procedures +-- +-- To create the SQL procedures: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf spserver.db2" +-- +-- To call these SQL procedures, you can use the +-- C, CLI, or C++ spclient application, or the Spclient +-- application in Java, by compiling and running one of +-- the following source files: +-- C: samples/c/spclient.sqc (UNIX) or samples\c\spclient.sqc (Windows) +-- CLI: samples/cli/spclient.c (UNIX) or samples\c\spclient.c (Windows) +-- C++: samples/cpp/spclient.sqC (UNIX) or samples\cpp\spclient.sqx (Windows) +-- Java JDBC: samples/java/jdbc/Spclient.java (UNIX) +-- or samples\java\jdbc\Spclient.java (Windows) +-- Java SQLJ: samples/java/sqlj/Spclient.sqlj (UNIX) +-- or samples\java\sqlj\Spclient.sqlj (Windows) +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Stored Procedure: OUT_LANGUAGE +-- +-- Purpose: Returns the code implementation language of +-- routine 'OUT_LANGUAGE' (as it appears in the +-- database catalog) in an output parameter. +-- +-- Parameters: +-- +-- IN: (none) +-- OUT: procedureLanguage - the code language of this routine +----------------------------------------------------------------------------- +CREATE PROCEDURE OUT_LANGUAGE (OUT procedureLanguage CHAR(8)) +SPECIFIC SQL_OUT_LANGUAGE +DYNAMIC RESULT SETS 0 +LANGUAGE SQL +READS SQL DATA +BEGIN + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE errorLabel CHAR(32) DEFAULT ''; + + -- in case of no data found + DECLARE EXIT HANDLER FOR NOT FOUND + SIGNAL SQLSTATE value '38200' SET MESSAGE_TEXT= '100: NO DATA FOUND'; + + -- in case of SQL error + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE value SQLSTATE SET MESSAGE_TEXT = errorLabel; + + SET errorLabel = 'SELECT STATEMENT'; + SELECT language INTO procedureLanguage + FROM sysibm.sysprocedures + WHERE procname = 'OUT_LANGUAGE'; +END @ + +----------------------------------------------------------------------------- +-- Stored Procedure: OUT_PARAM +-- +-- Purpose: Sorts table STAFF by salary, locates and returns +-- the median salary +-- +-- Parameters: +-- +-- IN: (none) +-- OUT: medianSalary - median salary in table STAFF +----------------------------------------------------------------------------- +CREATE PROCEDURE OUT_PARAM (OUT medianSalary DOUBLE) +SPECIFIC SQL_OUT_PARAM +DYNAMIC RESULT SETS 0 +LANGUAGE SQL +READS SQL DATA +BEGIN + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE errorLabel CHAR(32) DEFAULT ''; + DECLARE SQLCODE INTEGER DEFAULT 0; + DECLARE v_numRecords INT DEFAULT 1; + DECLARE v_counter INT DEFAULT 0; + DECLARE v_mod INT DEFAULT 0; + DECLARE v_salary1 DOUBLE DEFAULT 0; + DECLARE v_salary2 DOUBLE DEFAULT 0; + + DECLARE c1 CURSOR FOR + SELECT CAST(salary AS DOUBLE) FROM staff + ORDER BY salary; + + -- in case of no data found + DECLARE EXIT HANDLER FOR NOT FOUND + SIGNAL SQLSTATE value '38200' SET MESSAGE_TEXT= '100: NO DATA FOUND'; + + -- in case of SQL error + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE value SQLSTATE SET MESSAGE_TEXT = errorLabel; + + -- initialize OUT parameter + SET medianSalary = 0; + + SET errorLabel = 'SELECT COUNT'; + SELECT COUNT(*) INTO v_numRecords FROM staff; + + SET errorLabel = 'OPEN CURSOR'; + OPEN c1; + + SET v_mod = MOD(v_numRecords, 2); + + CASE v_mod + WHEN 0 THEN + WHILE v_counter < (v_numRecords / 2 + 1) DO + SET v_salary1 = v_salary2; + FETCH c1 INTO v_salary2; + SET v_counter = v_counter + 1; + END WHILE; + SET medianSalary = (v_salary1 + v_salary2)/2; + WHEN 1 THEN + WHILE v_counter < (v_numRecords / 2 + 1) DO + FETCH c1 INTO medianSalary; + SET v_counter = v_counter + 1; + END WHILE; + END CASE; + + SET errorLabel = 'CLOSE CURSOR'; + CLOSE c1; +END @ + +----------------------------------------------------------------------------- +-- Stored Procedure: IN_PARAMS +-- +-- Purpose: Updates salaries of employees in department 'department' +-- using inputs lowsal, medsal, highsal as +-- salary raise/adjustment values. +-- +-- Parameters: +-- +-- IN: lowsal - new salary for low salary employees +-- medsal - new salary for mid salary employees +-- highsal - new salary for high salary employees +-- department - department to use in SELECT predicate +-- OUT: (none) +-- +----------------------------------------------------------------------------- +CREATE PROCEDURE IN_PARAMS (IN lowsal DOUBLE, IN medsal DOUBLE, IN highsal DOUBLE, IN department CHAR(3)) +SPECIFIC SQL_IN_PARAMS +DYNAMIC RESULT SETS 0 +DETERMINISTIC +LANGUAGE SQL +MODIFIES SQL DATA +BEGIN + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE SQLCODE INTEGER DEFAULT 0; + DECLARE errorLabel CHAR(32) DEFAULT ''; + DECLARE v_firstnme VARCHAR(12); + DECLARE v_midinit CHAR(1); + DECLARE v_lastname VARCHAR(15); + DECLARE v_salary DOUBLE; + DECLARE at_end SMALLINT DEFAULT 0; + + DECLARE c1 CURSOR FOR + SELECT firstnme, midinit, lastname, CAST(salary AS DOUBLE) + FROM employee + WHERE workdept = department + FOR UPDATE OF salary; + + DECLARE CONTINUE HANDLER FOR NOT FOUND + SET at_end = 1; + + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE value SQLSTATE SET MESSAGE_TEXT = errorLabel; + + -- initialize OUT parameter + SET errorLabel = 'OPEN CURSOR'; + OPEN c1; + SET errorLabel = 'FIRST FETCH'; + FETCH c1 INTO v_firstnme, v_midinit, v_lastname, v_salary; + WHILE (at_end = 0) DO + IF (lowsal > v_salary) THEN + UPDATE employee + SET salary = lowsal + WHERE CURRENT OF c1; + ELSEIF (medsal > v_salary) THEN + UPDATE employee + SET salary = medsal + WHERE CURRENT OF c1; + ELSEIF (highsal > v_salary) THEN + UPDATE employee + SET salary = highsal + WHERE CURRENT OF c1; + ELSE UPDATE employee + SET salary = salary * 1.10 + WHERE CURRENT OF c1; + END IF; + SET errorLabel = 'FETCH IN WHILE LOOP'; + FETCH c1 INTO v_firstnme, v_midinit, v_lastname, v_salary; + END WHILE; + SET errorLabel = 'CLOSE CURSOR'; + CLOSE c1; +END @ + +----------------------------------------------------------------------------- +-- Stored Procedure: INOUT_PARAM +-- +-- Purpose: Calculates the median salary of all salaries in the STAFF +-- above table the input median salary. +-- +-- Parameters: +-- +-- IN/OUT: medianSalary - median salary +-- The input value is used in a SELECT predicate. +-- Its output value is set to the median salary. +-- +----------------------------------------------------------------------------- +CREATE PROCEDURE INOUT_PARAM (INOUT medianSalary DOUBLE) +SPECIFIC SQL_INOUT_PARAM +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE SQL +READS SQL DATA +BEGIN + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE SQLCODE INTEGER DEFAULT 0; + DECLARE errorLabel CHAR(32) DEFAULT ''; + DECLARE v_mod INT DEFAULT 0; + DECLARE v_medianSalary DOUBLE DEFAULT 0; + DECLARE v_numRecords INT DEFAULT 1; + DECLARE v_counter INT DEFAULT 0; + DECLARE v_salary1 DOUBLE DEFAULT 0; + DECLARE v_salary2 DOUBLE DEFAULT 0; + + DECLARE c1 CURSOR FOR + SELECT CAST(salary AS DOUBLE) FROM staff + WHERE salary > medianSalary + ORDER BY salary; + + DECLARE EXIT HANDLER FOR NOT FOUND + SIGNAL SQLSTATE value '38200' SET MESSAGE_TEXT= '100: NO DATA FOUND'; + + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE value SQLSTATE SET MESSAGE_TEXT = errorLabel; + + SET errorLabel = 'SELECT COUNT'; + SELECT COUNT(*) INTO v_numRecords FROM staff WHERE salary > medianSalary; + + SET v_mod = MOD(v_numRecords, 2); + + SET errorLabel = 'OPEN CURSOR'; + OPEN c1; + + CASE v_mod + WHEN 0 THEN + WHILE v_counter < (v_numRecords / 2 + 1) DO + SET v_salary1 = v_salary2; + FETCH c1 INTO v_salary2; + SET v_counter = v_counter + 1; + END WHILE; + SET medianSalary = (v_salary1 + v_salary2)/2; + WHEN 1 THEN + WHILE v_counter < (v_numRecords / 2 + 1) DO + FETCH c1 INTO medianSalary; + SET v_counter = v_counter + 1; + END WHILE; + END CASE; + + SET errorLabel = 'CLOSE CURSOR'; + CLOSE c1; +END @ + +----------------------------------------------------------------------------- +-- Stored Procedure: DECIMAL_TYPE +-- +-- Purpose: Takes in a decimal number as input, divides it by 2 +-- and returns the resulting decimal rounded off to 2 +-- decimal places. +-- +-- Parameters: +-- +-- INOUT: inOutDecimal - DECIMAL(10,2) +-- +----------------------------------------------------------------------------- +CREATE PROCEDURE DECIMAL_TYPE (INOUT inOutDecimal DECIMAL(10,2)) +SPECIFIC SQL_DEC_TYPE +DYNAMIC RESULT SETS 0 +DETERMINISTIC +LANGUAGE SQL +READS SQL DATA +BEGIN + + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE errorLabel CHAR(32) DEFAULT ''; + + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE value SQLSTATE SET MESSAGE_TEXT = errorLabel; + + SET errorLabel = 'IF DECIMAL'; + IF (inOutDecimal = 0) THEN SET inOutDecimal = 1; + ELSE SET inOutDecimal = inOutDecimal / 2; + END IF; + +END @ + +----------------------------------------------------------------------------- +-- Stored Procedure: ALL_DATA_TYPES +-- +-- Purpose: Take each parameter and set it to a new output value. +-- This sample shows only a subset of DB2 supported data types. +-- For a full listing of DB2 data types, please see the SQL +-- Reference. +-- +-- Parameters: +-- +-- INOUT: inOutSmallint, inOutInteger, inOutBigint, inOutReal, +-- inoutDouble +-- OUT: charOut, charsOut, varcharOut, charsOut, timeOut +-- +----------------------------------------------------------------------------- +CREATE PROCEDURE ALL_DATA_TYPES (INOUT inOutSmallint SMALLINT, + INOUT inOutInteger INTEGER, INOUT inOutBigint BIGINT, + INOUT inOutReal REAL, INOUT inoutDouble DOUBLE, + OUT charOut CHAR(1), OUT charsOut CHAR(15), + OUT varcharOut VARCHAR(12), OUT dateOut DATE, + OUT timeOut TIME) +SPECIFIC SQL_ALL_DAT_TYPES +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE SQL +READS SQL DATA +BEGIN + + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE errorLabel CHAR(32) DEFAULT ''; + + DECLARE EXIT HANDLER FOR NOT FOUND + SIGNAL SQLSTATE value '38200' SET MESSAGE_TEXT= '100: NO DATA FOUND'; + + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE value SQLSTATE SET MESSAGE_TEXT = errorLabel; + + SET errorLabel = 'IF SMALLINT'; + IF (inOutSmallint = 0) THEN SET inOutSmallint = 1; + ELSE SET inOutSmallint = inOutSmallint / 2; + END IF; + + SET errorLabel = 'IF INTEGER'; + IF (inOutInteger = 0) THEN SET inOutInteger = 1; + ELSE SET inOutInteger = inOutInteger / 2; + END IF; + + SET errorLabel = 'IF BIGINT'; + IF (inOutBigint = 0) THEN SET inOutBigint = 1; + ELSE SET inOutBigint = inOutBigint / 2; + END IF; + + SET errorLabel = 'IF REAL'; + IF (inOutReal = 0) THEN SET inOutReal = 1; + ELSE SET inOutReal = inOutReal / 2; + END IF; + + SET errorLabel = 'IF DOUBLE'; + IF (inoutDouble = 0) THEN SET inoutDouble = 1; + ELSE SET inoutDouble = inoutDouble / 2; + END IF; + + SET errorLabel = 'SELECT midinit'; + SELECT midinit INTO charOut FROM employee WHERE empno = '000180'; + + SET errorLabel = 'SELECT lastname'; + SELECT lastname INTO charsOut FROM employee WHERE empno = '000180'; + + SET errorLabel = 'SELECT firstnme'; + SELECT firstnme INTO varcharOut FROM employee WHERE empno = '000180'; + + SET errorLabel = 'VALUES CURRENT DATE'; + VALUES CURRENT DATE INTO dateOut; + + SET errorLabel = 'VALUES CURRENT TIME'; + VALUES CURRENT TIME INTO timeOut; + +END @ + +----------------------------------------------------------------------------- +-- Stored Procedure: ONE_RESULT_SET +-- +-- Purpose: Returns a result set to the caller that identifies employees +-- with salaries greater than the value of input parameter +-- salValue. +-- +-- Parameters: +-- +-- IN: salValue - salary +-- +----------------------------------------------------------------------------- +CREATE PROCEDURE ONE_RESULT_SET (IN salValue DOUBLE) +SPECIFIC SQL_ONE_RES_SET +DYNAMIC RESULT SETS 1 +NOT DETERMINISTIC +LANGUAGE SQL +READS SQL DATA +BEGIN + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE SQLCODE INTEGER DEFAULT 0; + DECLARE errorLabel CHAR(32) DEFAULT ''; + + -- use WITH RETURN TO CLIENT in DECLARE CURSOR to always + -- return a result set to the client application + DECLARE c1 CURSOR WITH RETURN TO CLIENT FOR + SELECT name, job, CAST(salary AS DOUBLE) + FROM staff + WHERE salary > salValue + ORDER BY salary; + + DECLARE EXIT HANDLER FOR NOT FOUND + SIGNAL SQLSTATE value '38200' SET MESSAGE_TEXT= '100: NO DATA FOUND'; + + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE value SQLSTATE SET MESSAGE_TEXT = errorLabel; + + -- to return result set, do not CLOSE cursor + SET errorLabel = 'OPEN CURSOR'; + OPEN c1; + +END @ + +----------------------------------------------------------------------------- +-- Stored Procedure: RESULT_SET_CALLER +-- +-- Purpose: Returns a result set to the caller that identifies employees +-- with salaries greater than the value of input parameter +-- salValue. +-- +-- Parameters: +-- +-- IN: salValue +-- OUT: ResultSet +----------------------------------------------------------------------------- +CREATE PROCEDURE RESULT_SET_CALLER (IN salValue DOUBLE) +SPECIFIC SQL_RES_SET_CALLER +DYNAMIC RESULT SETS 1 +LANGUAGE SQL +READS SQL DATA +BEGIN + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE errorLabel CHAR(32) DEFAULT ''; + + -- use WITH RETURN TO CALLER in DECLARE CURSOR to always + -- return a result set to the calling application + DECLARE c1 CURSOR WITH RETURN TO CALLER FOR + SELECT name, job, CAST(salary AS DOUBLE) + FROM staff + WHERE salary > salValue + ORDER BY salary; + + -- in case of no data found + DECLARE EXIT HANDLER FOR NOT FOUND + SIGNAL SQLSTATE value '38200' SET MESSAGE_TEXT= '100: NO DATA FOUND'; + + -- in case of SQL error + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE value SQLSTATE SET MESSAGE_TEXT = errorLabel; + + -- to return result set, do not CLOSE cursor + OPEN c1; +END @ + +----------------------------------------------------------------------------- +-- Stored Procedure: TWO_RESULT_SETS +-- +-- Purpose: Return two result sets to the caller. One result set +-- consists of employee data of all employees with +-- salaries greater than medianSalary. The other +-- result set contains employee data for employees with salaries +-- less than medianSalary. +-- +-- Parameters: +-- +-- IN: medianSalary - salary +-- +----------------------------------------------------------------------------- +CREATE PROCEDURE TWO_RESULT_SETS (IN medianSalary DOUBLE) +SPECIFIC SQL_TWO_RES_SETS +DYNAMIC RESULT SETS 2 +NOT DETERMINISTIC +LANGUAGE SQL +READS SQL DATA +BEGIN + + DECLARE nestCode INTEGER; + DECLARE nestLabel CHAR(32); + DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; + DECLARE errorLabel CHAR(32) DEFAULT ''; + + DECLARE r1 CURSOR WITH RETURN FOR + SELECT name, job, CAST(salary AS DOUBLE) + FROM staff + WHERE salary > medianSalary + ORDER BY salary; + + DECLARE r2 CURSOR WITH RETURN FOR + SELECT name, job, CAST(salary AS DOUBLE) + FROM staff + WHERE salary < medianSalary + ORDER BY salary DESC; + + DECLARE EXIT HANDLER FOR NOT FOUND + SIGNAL SQLSTATE value '38200' SET MESSAGE_TEXT= '100: NO DATA FOUND'; + + DECLARE EXIT HANDLER FOR SQLEXCEPTION + SIGNAL SQLSTATE value SQLSTATE SET MESSAGE_TEXT = errorLabel; + + SET errorLabel = 'OPEN CURSOR r1'; + OPEN r1; + + SET errorLabel = 'OPEN CURSOR r2'; + OPEN r2; + + -- the EXIT handler ensures that we will not reach this point unless the + -- result set has results + +END @ + diff --git a/sqlpl/tbfn.db2 b/sqlpl/tbfn.db2 new file mode 100644 index 0000000..36e4307 --- /dev/null +++ b/sqlpl/tbfn.db2 @@ -0,0 +1,198 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: tbfn.db2 +-- +-- SAMPLE: Create the tables and table functions used in tbfnuse sample +-- After the tbfnuse script is run, all changes are rolled back and +-- the tables and functions created in this file are dropped. +-- +-- To create/register the tables and SQL functions defined in this file: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf tbfn.db2" +-- +-- To invoke an SQL table function from the command line: +-- 1. Connect to the database (if not already connected) +-- 2. Enter the command: +-- +-- db2 "SELECT * FROM sal_by_dept(char('111'))" +-- +-- This issues a SELECT statement that references the table function as +-- a table-reference in the FROM clause. A result set is returned. +-- +-- To invoke the SQL table functions defined in this file within a sample: +-- 1. Connect to the database (if not already connected) +-- 2. Enter the command "db2 -td@ -vf tbfnuse.db2" +-- +-- This issues a series of SQL statements that invoke table functions +-- that read or modify data in the tables, and that show the state of the +-- tables after the table-function invocations. +-- +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL functions, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +DROP FUNCTION updateInv@ +DROP FUNCTION sal_by_dept@ +DROP FUNCTION update_salary@ + +DROP TABLE INVENTORY@ +DROP TABLE PRICELIST@ +DROP TABLE EMPLOYEES@ +DROP TABLE AUDIT_TABLE@ + +echo -- This table contains the inventory for a book store.@ +echo@ + +CREATE TABLE INVENTORY(itemID varchar(20), + itemName varchar(20), + quantity integer)@ +INSERT INTO INVENTORY VALUES('ISBN-0-8021-3424-6', + 'Feng Shui at Home', + 10)@ +INSERT INTO INVENTORY VALUES('ISBN-0-8021-4612-1', + 'Baseball Heroes', + 10)@ +INSERT INTO INVENTORY VALUES('ISBN-0-8021-5551-0', + 'Shakespeare in Love', + 10)@ + +echo -- This table contains the inventory pricelist for a book store.@ +echo@ + +CREATE TABLE PRICELIST(itemID varchar(20), unitprice decimal(4,2))@ +INSERT INTO PRICELIST VALUES('ISBN-0-8021-3424-6', 12.40)@ +INSERT INTO PRICELIST VALUES('ISBN-0-8021-4612-1', 16.00)@ +INSERT INTO PRICELIST VALUES('ISBN-0-8021-5551-0', 4.99)@ + +echo -- The table function that follows updates the quantity of@ +echo -- a product item in the "INVENTORY" table by a specified amount@ +echo -- and returns a result set indicating the new product inventory.@ +echo@ +echo -- Note that because the table function modifies table data@ +echo -- the clause "MODIFIES SQL DATA" is used in the CREATE@ +echo -- FUNCTION statement.@ +echo@ + +CREATE FUNCTION updateInv(itemNo VARCHAR(20), amount INTEGER) +RETURNS TABLE (productName varchar(20), quantity INTEGER) +LANGUAGE SQL +MODIFIES SQL DATA +BEGIN ATOMIC + UPDATE Inventory as I + SET quantity = quantity + amount + WHERE I.itemID = itemNo; + RETURN + SELECT I.itemName, I.quantity + FROM Inventory as I + WHERE I.itemID = itemNo; +END@ + +echo -- This table contains the employees of a company.@ +echo@ + +CREATE TABLE EMPLOYEES(EMPNUM CHAR(4), + FIRSTNAME varchar(128), + LASTNAME varchar(128), + DEPT CHAR(4), SALARY integer)@ + +INSERT INTO EMPLOYEES VALUES('1124', 'NADIM', 'RATANI', '111', 75000), + ('1136', 'GWYNETH', 'EVANS', '112', 90000)@ + +echo -- This table contains audit records of transactions performed on@ +echo -- table "EMPLOYEES". Each record in this table contains information@ +echo -- about a user, what table they accessed, what was the access, and@ +echo -- what was the time of that access. Records are added to this@ +echo -- table whenever the table functions "sal_by_dept" and "update_salary"@ +echo -- are invoked.@ +echo@ + +CREATE TABLE AUDIT_TABLE(USER varchar(10), + TABLE varchar(10), + ACTION varchar(50), + TIME TIMESTAMP)@ + +echo -- This table function returns the salary of an employee in table@ +echo -- "EMPLOYEES" and inserts an audit record into "AUDIT_TABLE" containing@ +echo -- information about the user that invoked the table function and what@ +echo -- table access that user performed. A result set is returned containing@ +echo -- the lastname, firstname, and salary of the employee.@ +echo@ + +CREATE FUNCTION sal_by_dept(deptno CHAR(3)) + RETURNS TABLE(lastname VARCHAR(10), + firstname VARCHAR(10), + salary INTEGER) + LANGUAGE SQL + MODIFIES SQL DATA + NO EXTERNAL ACTION + NOT DETERMINISTIC + BEGIN ATOMIC + INSERT INTO audit_table(USER, TABLE, ACTION, TIME) + VALUES(USER, + 'EMPLOYEES', + 'Read employee salaries in department ' || DEPTNO, + CURRENT_TIMESTAMP); + RETURN + SELECT lastname, firstname, salary + FROM employees as E + WHERE E.DEPT = DEPTNO; + END@ + +echo -- This table function updates the salary of an employee identified by@ +echo -- his employee number, by a specified amount. It also inserts an audit@ +echo -- record into "AUDIT_TABLE" containing information about the user that@ +echo -- invoked the table function and what table access the user performed. A@ +echo -- result set is returned containing the lastname, firstname and the@ +echo -- new salary of the employee.@ +echo@ + +CREATE FUNCTION update_salary(updEmpNum CHAR(4), amount INTEGER) +RETURNS TABLE(emp_lastname VARCHAR(10), + emp_firstname VARCHAR(10), + newSalary INTEGER) + LANGUAGE SQL + MODIFIES SQL DATA + NO EXTERNAL ACTION + NOT DETERMINISTIC + BEGIN ATOMIC + INSERT INTO audit_table(USER, TABLE, ACTION, TIME) + VALUES(USER, + 'EMPLOYEES', + 'Update of employee salary. ID: ' + || updEmpNum || ', BY: $' || char(amount), + CURRENT_TIMESTAMP); + RETURN + SELECT lastname, firstname, salary + FROM FINAL TABLE(UPDATE employees + SET salary = salary + amount + WHERE employees.empnum = updEmpNum); + END@ + diff --git a/sqlpl/tbfnuse.db2 b/sqlpl/tbfnuse.db2 new file mode 100644 index 0000000..8475b96 --- /dev/null +++ b/sqlpl/tbfnuse.db2 @@ -0,0 +1,205 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: tbfnuse.db2 +-- +-- SAMPLE: Demonstrate use of table functions created in tbfnuse sample +-- At the end of this script, statements are rolled back and the +-- tables and functions created in tbfn.db2 are dropped. +-- +-- To create/register the tables, and invoke the SQL function using this file: +-- 1. Connect to the database +-- 2. Enter the commands: +-- +-- db2 -td@ -vf tbfn.db2 +-- db2 -td@ -vf tbfnuse.db2 +-- +-- Note: creating and registering the tables in tbfn.db2 is a prerequisite +-- for running this script. +-- ----------------------------------------------------------------------------- -- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL functions, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +echo -- EXAMPLES OF INVOKING SQL TABLE FUNCTIONS@ +echo -- ========================================@ +echo@ +echo -- BASIC INVOCATION OF AN SQL TABLE FUNCTION THAT MODIFIES SQL DATA@ +echo -- ------------------------------------------------------@ +echo -- The SQL table function "updateInv" can be invoked from within the@ +echo -- FROM clause of a SELECT statement. Table function "updateInv"@ +echo -- updates the quantity of an item identified by item number@ +echo -- 'ISBN-0-8021-3424-6' by an amount of five. The product name and the@ +echo -- updated quantity of the item are returned in a result set.@ +echo@ + +echo -- Display the initial contents of table "INVENTORY":@ +echo@ +SELECT * FROM INVENTORY@ + +echo -- Invoke the table function from the FROM clause of a SELECT@ +echo -- statement:@ +echo@ +SELECT productName, quantity + FROM TABLE(updateInv('ISBN-0-8021-3424-6', 5)) AS T@ + +echo -- Display the updated contents of table "INVENTORY":@ +echo@ +SELECT * FROM INVENTORY@ + +echo -- INVOKING AN SQL TABLE FUNCTION THAT MODIFIES SQL DATA WHICH IS@ +echo -- CORRELATED TO ANOTHER TABLE-REFERENCE.@ +echo -- --------------------------------------------------------------@ +echo -- In this example, the quantities of multiple items in the inventory@ +echo -- table, "INVENTORY", are updated. The VALUES clause is used to@ +echo -- generate table "newItem" which contains rows of items to be updated.@ +echo -- The table function "updateInv" is correlated to table reference@ +echo -- "newItem", because at least one column in "newItem" appears as an@ +echo -- argument to the table function "updateInv".@ +echo@ +echo -- Note: It is required that a table function that MODIFIES SQL DATA@ +echo -- (only) be the last table reference in the FROM clause of an@ +echo -- outermost SELECT.@ +echo@ + +echo -- Invoke the correlated table function from the FROM clause of a@ +echo -- SELECT statement:@ +echo@ +SELECT newItem.id, TF.productName, TF.Quantity + FROM (VALUES ('ISBN-0-8021-3424-6', 5), + ('ISBN-0-8021-4612-1', 10)) AS newItem(id, quantity), + TABLE(updateInv(newItem.id, newItem.quantity)) AS TF@ + +echo -- Display the updated contents of table INVENTORY:@ +echo@ +SELECT * FROM INVENTORY@ + +echo -- INVOKING AN SQL TABLE FUNCTION THAT MODIFIES SQL DATA WHICH IS@ +echo -- CORRELATED TO ANOTHER TABLE-REFERENCE AND IN A@ +echo -- COMMON-TABLE-EXPRESSION@ +echo -- -----------------------------------------------------------------------@ +echo -- This example extends the previous example by returning the unit price@ +echo -- and total inventory value of the updated stock items. The total@ +echo -- inventory value is calculated by multiplying the new quantities of@ +echo -- these items by the price from a price list table, "PRICELIST".@ +echo@ +echo -- Note: A common table expression is identified by the use of the@ +echo -- WITH clause which instantiates a temporary table newInv that@ +echo -- can be queried in the SELECT portion of an SQL statement.@ +echo@ + +echo -- Invoke the correlated table function from within a@ +echo -- common-table-expression@ +echo@ +WITH newInv(itemNo, quantity) AS + (SELECT id, TF.quantity + FROM (VALUES ('ISBN-0-8021-3424-6', 5), + ('ISBN-0-8021-4612-1', 10)) AS newItem(id, q), + TABLE(updateInv(newItem.id, newItem.q)) AS TF) +SELECT itemNo, quantity, unitPrice, (quantity * unitPrice) as TotalInvValue + FROM newInv, priceList + WHERE itemNo = priceList.itemID@ + +echo -- Display the updated contents of table INVENTORY:@ +echo@ +SELECT * FROM INVENTORY@ + +echo -- AUDITING READ ACCESSES OF A TABLE USING AN SQL@ +echo -- TABLE FUNCTION THAT MODIFIES SQL DATA@ +echo -- ----------------------------------------------@ +echo -- The table function "sal_by_dept" is referenced as a table-reference@ +echo -- in the FROM clause of a SELECT statement. Upon execution of the@ +echo -- statement, the table function is invoked. The table function@ +echo -- "sal_by_dept" reads data from a table EMPLOYEES and returns@ +echo -- salary information for employees of a specified department@ +echo -- in a result set. It also inserts a record into an audit table,@ +echo -- "AUDIT_TABLE recording details of the read access on table@ +echo -- "EMPLOYEES".@ +echo@ + +echo -- Display initial contents of table "AUDIT_TABLE":@ +echo@ + +SELECT * FROM AUDIT_TABLE@ + +echo -- The following SELECT statement shows how a user might@ +echo -- invoke the routine to read the salaries of employees in@ +echo -- department '111'. A result set is returned with the last name,@ +echo -- first name, and salary for the employee.@ +echo@ +SELECT * from table(sal_by_dept(char('111'))) as T@ + +echo -- The invoker of the "sal_by_dept" table function need not know@ +echo -- that an audit record was also inserted into an audit table.@ +echo@ + +SELECT * FROM AUDIT_TABLE@ + +echo -- AUDITING UPDATES TO A TABLE USING AN SQL A TABLE FUNCTION THAT@ +echo -- MODIFIES SQL DATA@ +echo -- -----------------------------------------------------------------@ +echo -- The table function "update_salary" is referenced as a table-reference@ +echo -- in the FROM clause of a SELECT statement. Upon execution of the@ +echo -- statement, the table function is invoked. The table function updates@ +echo -- the salary of a specified employee and inserts a record into an@ +echo -- AUDIT TABLE recording details of the read access on table@ +echo -- "EMPLOYEES".@ +echo@ +echo -- The following SELECT statement shows how a user might invoke the@ +echo -- routine to update the salary of an employee with employee ID '1136,@ +echo -- by an amount of $500:@ +echo@ + +SELECT emp_lastname, emp_firstname, newsalary + FROM TABLE(update_salary(CHAR('1136'), 500)) AS T@ + +echo -- The invoker of the "update_salary" table function need not know@ +echo -- that an audit record was also inserted into an audit table.@ +echo@ + +SELECT * FROM AUDIT_TABLE@ + +echo -- Rolling back changes and dropping the@ +echo -- tables and functions created by this sample.@ +echo@ + +echo@ +-- If you don't want the changes made by this sample to be rolled back, +-- comment out all lines below this line. + +ROLLBACK@ + +DROP FUNCTION updateInv@ +DROP FUNCTION sal_by_dept@ +DROP FUNCTION update_salary@ + +DROP TABLE INVENTORY@ +DROP TABLE PRICELIST@ +DROP TABLE EMPLOYEES@ +DROP TABLE AUDIT_TABLE@ + diff --git a/sqlpl/tbsel.sqc b/sqlpl/tbsel.sqc new file mode 100644 index 0000000..3bd83cd --- /dev/null +++ b/sqlpl/tbsel.sqc @@ -0,0 +1,272 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: tbsel.sqc +** +** SAMPLE: How to select from each of: insert, update, delete +** +** This sample consists of a client application (this file) that calls +** an SQL stored procedure BUY_COMPANY (see tbselcreate.db2). +** The procedure BUY_COMPANY contains usage examples of a SELECT +** from a data change statement. +** +** CONTEXT: +** The context for this sample is that of a company "Company B" taking +** over company "Company A". This sample illustrates how Company B +** incorporates data from table company_b into table company_a using +** an SQL stored procedure BUY_COMPANY. +** +** The table company_b differs from table company_a. In company_b there +** is a generated column for the employee ID. Another table salary_change +** records the old and new salaries of each employee transferred from +** Company A to Company B. +** statement. +** +** PREREQUISITES: +** - Ensure existence of database for precompile purposes. +** - Ensure that the tables and stored procedure referenced in this program +** have been created. To create these tables see the instructions in +** tbselcreate.db2 +** - Use the makefile to precompile/bind/compile and link this client +** application -or- +** -Precompile this application with the SQL precompiler (PREP in DB2) +** -Bind this application to a database (BIND in DB2) +** -Compile and link this application with the compiler supported on your platform. +** +** +** SQL STATEMENTS USED: +** CONNECT +** CALL +** SELECT +** +** OUTPUT FILE: tbsel.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +int main(int argc, char *argv[]) +{ + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; /* string to hold input database name */ + char userid[9]; /* string to hold input user ID */ + char passwd[19]; /* string to hold input password */ + char stmt[1200]; /* string to hold SQL statements used in this procedure*/ + EXEC SQL END DECLARE SECTION; + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* Error message buffer */ + + if (argc != 4) + { + printf ("\nUSAGE: tbsel database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + + /* Connect to database */ + printf("Connect to database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("Connect to sample"); + + printf("\nOutput the contents of tables COMPANY_A and COMPANY_B"); + printf("\nprior to the CALL of procedure BUY_COMPANY: \n"); + + Print(); + + /********************************************************\ + * Call the procedures via the CALL statement * + \********************************************************/ + printf("\nIssue SQL to call procedure BUY_COMPANY:\n\n"); + + sprintf(stmt, "CALL BUY_COMPANY ()"); + printf("%s\n", stmt); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPARE CALL STATEMENT"); + + EXEC SQL execute st; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + printf("\nOutput the contents of tables COMPANY_A and COMPANY_B"); + printf("\nafter CALL of procedure BUY_COMPANY.\n"); + + Print(); + + /* ROLLBACK the stored procedure's actions. If there was an error + report the error and then ROLLBACK the changes effected by the + stored procedure. This is done to reset the data in the tables + requied by this sample so that this application can be invoked + again immediately with the same data.*/ + if (SQLCODE == 0) + { /* Rollback the changes to the database */ + EXEC SQL ROLLBACK; + printf("\nServer Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + + /* Free allocated memory. */ + free( inout_sqlda ); + + /* Disconnect from database. */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} /* main */ + +/* The Print function outputs the data in the tables: company_a, company_b + and salary_change. For each table, a while loop and cursor are used to + fetch and display row data. +*/ +int Print(void) +{ + EXEC SQL BEGIN DECLARE SECTION; + short id; /* Employee's ID */ + short department; /* Employee's department */ + short years; /* Number of years employee has worked with the + company */ + short new_id; /* Employee's new ID when they switch companies */ + + char name[10]; /* Employee's name */ + char job[6]; /* Employee's job title */ + char benefits[51]; /* Employee's benefits */ + + double salary; /* Employee's current salary */ + double old_salary; /* Employee's old salary */ + EXEC SQL END DECLARE SECTION; + int rc = 0; + + char c1[] = "(SELECT ID, NAME, DEPARTMENT, JOB, YEARS, SALARY FROM company_a)"; + char c2[] = "(SELECT ID, NAME, DEPARTMENT, JOB, YEARS, SALARY, BENEFITS, OLD_ID FROM company_b)"; + char c3[] = "(SELECT ID, OLD_SALARY, SALARY FROM salary_change)"; + + EXEC SQL PREPARE S1 FROM :c1; + EMB_SQL_CHECK("Prepare first SELECT cursor"); + + EXEC SQL PREPARE S2 FROM :c2; + EMB_SQL_CHECK("Prepare second SELECT cursor"); + + EXEC SQL PREPARE S3 FROM :c3; + EMB_SQL_CHECK("Prepare third SELECT cursor"); + + EXEC SQL DECLARE company_a CURSOR FOR S1; + EMB_SQL_CHECK("Declare company_a cursor"); + + EXEC SQL DECLARE company_b CURSOR FOR S2; + EMB_SQL_CHECK("Declare company_b cursor"); + + EXEC SQL DECLARE salary_change CURSOR FOR S3; + EMB_SQL_CHECK("Declare salary_change cursor"); + + EXEC SQL OPEN company_a; + EMB_SQL_CHECK("Open company_a cursor"); + + EXEC SQL OPEN company_b; + EMB_SQL_CHECK("Open company_b cursor"); + + EXEC SQL OPEN salary_change; + EMB_SQL_CHECK("Open salary_change cursor"); + + EXEC SQL FETCH company_a INTO :id, :name, :department, :job, :years, :salary; + EMB_SQL_CHECK("Fetch from company_a"); + + printf("\nSELECT * FROM company_a\n\n"); + printf("ID NAME DEPARTMENT JOB YEARS SALARY\n"); + printf("------ --------- ---------- ----- ------ ---------\n"); + while (sqlca.sqlcode != 100) + { + printf("%-6d %-9s %-10d %-5s %-7d %-9.2f\n", id, name, department, job, years, salary); + + EXEC SQL FETCH company_a INTO :id, :name, :department, :job, :years, :salary; + EMB_SQL_CHECK("Fetch from company_a"); + } + + EXEC SQL FETCH company_b INTO :new_id, :name, :department, :job, :years, :salary, :benefits, :id; + EMB_SQL_CHECK("Fetch from company_b"); + printf("\nSELECT * FROM company_b\n\n"); + printf("ID NAME DEPARTMENT JOB YEARS SALARY BENEFITS OLD_ID\n"); + printf("------ --------- ---------- ----- ------ --------- -------------------------------------------------- ------\n"); + while (sqlca.sqlcode != 100) + { + printf("%-7d %-10s %-10d %-5s %-7d %-9.2f %-50s %-6d\n", new_id, name, department, job, years, salary, benefits, id); + EXEC SQL FETCH company_b INTO :new_id, :name, :department, :job, :years, :salary, :benefits, :id; + EMB_SQL_CHECK("Fetch from company_b"); + } + + EXEC SQL FETCH salary_change INTO :id, :old_salary, :salary; + EMB_SQL_CHECK("Fetch from salary_change"); + printf("\nSELECT * FROM salary_change\n\n"); + printf("ID OLD_SALARY SALARY\n"); + printf("------ ---------- ---------\n"); + while (sqlca.sqlcode != 100) + { + printf("%-8d %-9.2f %-8.2f\n", id, old_salary, salary); + EXEC SQL FETCH salary_change INTO :id, :old_salary, :salary; + EMB_SQL_CHECK("Fetch from salary_change"); + } + + EXEC SQL CLOSE company_a; + EMB_SQL_CHECK("Close company_a cursor"); + + EXEC SQL CLOSE company_b; + EMB_SQL_CHECK("Close company_b cursor"); + + EXEC SQL CLOSE salary_change; + EMB_SQL_CHECK("Close salary_change cursor"); + + return rc; +} /* Print */ + diff --git a/sqlpl/tbselcreate.db2 b/sqlpl/tbselcreate.db2 new file mode 100644 index 0000000..c0f45ca --- /dev/null +++ b/sqlpl/tbselcreate.db2 @@ -0,0 +1,215 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: tbselcreate.db2 +-- +-- SAMPLE: How to create the tables and procedure used in tbsel.sqc client +-- +-- To run this script from the CLP, perform the following steps: +-- 1. connect to the database +-- 2. issue the command "db2 -td@ -vf " +-- where represents the name of this script +-- OR +-- The script tbseldrop.db2 can be run as indicated above to drop the +-- tables and procedure that are created within this script. +----------------------------------------------------------------------------- +-- For more information on the sample programs, see the README file. +-- +-- For information on developing C applications, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- This table represents a table belonging to a company, Company A + + CREATE TABLE company_a + (ID SMALLINT NOT NULL UNIQUE, + NAME VARCHAR(9), + DEPARTMENT SMALLINT, + JOB CHAR(5), + YEARS SMALLINT, + SALARY DECIMAL(7,2))@ + + -- Populate table company_a with data. + INSERT INTO company_a VALUES(5275, 'Sanders', 20, 'Mgr', 15, 18357.50), + (5265, 'Pernal', 20, 'Sales', 1, 18171.25), + (5791, 'O''Brien', 38, 'Sales', 10, 18006.00)@ + +-- This table represents a table belonging to a company, Company B +-- One column in this table is a generated column (column ID) - the +-- value for this column is a generated unique value when a row is +-- inserted to this table. + + CREATE TABLE company_b + (ID SMALLINT GENERATED BY DEFAULT AS IDENTITY(START WITH 2000, INCREMENT BY 1 NOCACHE) NOT NULL, + NAME VARCHAR(9), + DEPARTMENT SMALLINT, + JOB CHAR(5), + YEARS SMALLINT, + SALARY DECIMAL(7,2), + BENEFITS VARCHAR(50), + OLD_ID SMALLINT)@ + + -- Populate table company_b with data. + INSERT INTO company_b VALUES + (default, 'Naughton', 38, 'Clerk', 0, 12954.75, 'No Benefits', 0), + (default, 'Yamaguchi', 42, 'Clerk', 6, 10505.90, 'Basic Health Coverage', 0), + (default, 'Fraye', 51, 'Mgr', 6, 21150.00, 'Basic Health Coverage', 0), + (default, 'Williams', 51, 'Sales', 6, 19456.50, 'Basic Health Coverage', 0), + (default, 'Molinare', 10, 'Mgr', 7, 22959.20, 'Basic Health Coverage', 0)@ + + +-- This table holds salary information about employees. +-- The old and new (after an update) salary values are stored with +-- the associated employee's ID. + + CREATE TABLE salary_change + (ID SMALLINT NOT NULL UNIQUE, + OLD_SALARY DECIMAL(7,2), + SALARY DECIMAL(7,2))@ + + +-- ---------------------------------------------------------------------------- +-- SQL PROCEDURE: buy_company +-- +-- No parameters. +-- +-- PURPOSE: The buy_company procedure encapsulates the table updates required +-- after Company B takes over Company A. Each employees from table +-- company_a is allocated a new benefits package based on their years of +-- experience. The employee data is moved into table company_b. +-- Each employee's salary is increased by 5%. The old and new salaries +-- are recorded in table salary_change. Encapsulated in this procedure +-- are SQL statements that illustrate a SELECT from a data change +-- statement. Data change statements include: INSERT, UPDATE, DELETE, +-- MERGE statements. +-- +-- SHOWS: How to use retrieve result sets from a data change statement. +-- - to retrieve generated column values after an INSERT to a table +-- without requiring a subsequent SELECT statement +-- - to retrieve the OLD and NEW values of a column after an UPDATE +-- stateent modifies the column value +-- - to use INCLUDE columns with a retrieved result set (SELECT FROM +-- a data change statement. +-- - to efficiently encapsulate a data change statement and subsequent +-- SELECT statement into one statement (useful for performance!) +-- ---------------------------------------------------------------------------- +CREATE PROCEDURE buy_company +LANGUAGE SQL +BEGIN + DECLARE new_id SMALLINT; -- employee's new id when they switch companies + DECLARE old_salary DECIMAL(7,2); -- employee's old salary + DECLARE benefits VARCHAR(50); -- employee's benefits + + -- The following SELECT statement has a DELETE statement as the + -- table-reference in its FROM clause. When executed this statement + -- deletes all the rows from company_a, while selecting all of the just + -- deleted rows into the cursor emp_cursor. The for loop is used to + -- iterate through each employee in the cursor. + + FOR iterate_employees AS emp_cursor CURSOR FOR (SELECT ID, NAME, DEPARTMENT, JOB, YEARS, SALARY + FROM OLD TABLE (DELETE FROM company_a )) + DO + -- The following case statement sets the new employee's benefits based + -- on their years of experience. + + CASE + WHEN (YEARS > 14) + THEN SET benefits = 'Advanced Health Coverage and Pension Plan'; + WHEN (YEARS > 9) + THEN SET benefits = 'Advanced Health Coverage'; + WHEN (YEARS > 4) + THEN SET benefits = 'Basic Health Coverage'; + ELSE + SET benefits = 'No Benefits'; + END CASE; + + -- The following SELECT statement references an INSERT statement as the + -- table-reference in its FROM clause. It inserts an employee record + -- into table company_b using the values held in the cursor. + -- The current employee ID of the cursor is selected into the variable new_id. + -- The keywords FROM FINAL TABLE determine that the value in new_id is + -- the value of ID after the INSERT statement is complete. + + -- Note: By using the SELECT from a data change statement statement only a + -- single query is required to both INSERT and retrieve the generated column + -- value from the target table. To retrieve the generated ID column value + -- otherwise would ahve required 2 statements (an INSERT statement and a + -- subsequent SELECT statement) Using the SELECT from a data change statement + -- is more efficient and is a particularly useful solution for this problem in + -- applications where performance is a priority (eg. OLTP applications). + + SELECT ID INTO new_id + FROM FINAL TABLE (INSERT INTO company_b + VALUES(default, NAME, DEPARTMENT, + JOB, YEARS, SALARY, benefits, ID)); + + -- The following SELECT statement references an UPDATE statement + -- in its FROM clause. It updates an employee's salary by giving + -- them a 5% raise. The employee's id, old salary and current + -- salary are all read into varibles for later use in this + -- function. + + -- The INCLUDE statement works by creating a temporary column to + -- keep track of the old salary. This temporary column is only + -- available for this statement and is gone once the statement + -- completes. The only way to keep this data after the statement + -- completes is to read it into a variable. + + SELECT ID, OLD_SALARY, SALARY into id, old_salary, salary + FROM FINAL TABLE (UPDATE company_b INCLUDE (OLD_SALARY DECIMAL(7,2)) + SET OLD_SALARY = SALARY, + SALARY = SALARY * 1.05 + WHERE ID = new_id); + + -- This INSERT statement inserts an employee's id, old salary and + -- current salary into the salary_change table. + + INSERT INTO salary_change VALUES(id, old_salary, salary); + + END FOR; + + -- The following DELETE statement references a SELECT statement in its + -- FROM clause. It lays off the highest paid manager. This DELETE + -- statement removes the manager from the table company_b. + + DELETE FROM (SELECT * FROM company_b + ORDER BY SALARY DESC FETCH FIRST ROW ONLY); + + -- The following UPDATE statement references a SELECT statement in its + -- FROM clause. It gives the most senior employee a $10000 bonus. + -- This UPDATE statement raises the employee's salary in the table + -- company_b. + + UPDATE (SELECT MAX(YEARS) OVER() AS max_years, + YEARS, + SALARY + FROM company_b) + SET SALARY = SALARY + 10000 + WHERE max_years = YEARS; +END@ + + + diff --git a/sqlpl/tbseldrop.db2 b/sqlpl/tbseldrop.db2 new file mode 100644 index 0000000..c5acc4b --- /dev/null +++ b/sqlpl/tbseldrop.db2 @@ -0,0 +1,49 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: tbseldrop.db2 +-- +-- SAMPLE: How to drop the tables for the tbsel program +-- +-- To run this script from the CLP, perform the following steps: +-- 1. connect to the database +-- 2. issue the command "db2 -td@ -vf " +-- where represents the name of this script +-- +-- This script can be run to drop the tables and procedure that +-- are created for the tbsel sample when tbselcreate.db2 is run. +-- +----------------------------------------------------------------------------- +-- For more information on the sample programs, see the README file. +-- +-- For information on developing C applications, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +DROP TABLE company_a@ +DROP TABLE company_b@ +DROP TABLE salary_change@ +DROP PROCEDURE buy_company@ diff --git a/sqlpl/utilapi.c b/sqlpl/utilapi.c new file mode 100644 index 0000000..6d0da7b --- /dev/null +++ b/sqlpl/utilapi.c @@ -0,0 +1,340 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilapi.c +** +** SAMPLE: Checks for and prints to the screen SQL warnings and errors +** +** This utility file is compiled and linked in as an object module +** with non-embedded SQL sample programs by the supplied makefile +** and build files. +** +** DB2 APIs USED: +** sqlaintp -- Get Error Message +** sqlogstt -- Get SQLSTATE Message +** sqleatin -- Attach to an Instance +** sqledtin -- Detach from an Instance +** +** Included functions: +** SqlInfoPrint - prints to the screen SQL warnings and errors +** CmdLineArgsCheck1 - checks the command line arguments, version 1 +** CmdLineArgsCheck2 - checks the command line arguments, version 2 +** CmdLineArgsCheck3 - checks the command line arguments, version 3 +** CmdLineArgsCheck4 - checks the command line arguments, version 4 +** InstanceAttach - attach to instance +** InstanceDetach - detach from instance +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For more information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "utilapi.h" + +void SqlInfoPrint(char *appMsg, struct sqlca *pSqlca, int line, char *file) +{ + int rc = 0; + char sqlInfo[1024]; + char sqlInfoToken[1024]; + char sqlstateMsg[1024]; + char errorMsg[1024]; + + if (pSqlca->sqlcode != 0 && pSqlca->sqlcode != 100) + { + strcpy(sqlInfo, ""); + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "\n---- error report -----------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } + else + { + sprintf(sqlInfoToken, + "\n---- warning report ---------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } /* endif */ + + sprintf(sqlInfoToken, "\napplication message = %s\n", appMsg); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "line = %d\n", line); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "file = %s\n", file); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "SQLCODE = %ld\n\n", pSqlca->sqlcode); + strcat(sqlInfo, sqlInfoToken); + + /* get error message */ + rc = sqlaintp(errorMsg, 1024, 80, pSqlca); + if (rc > 0) /* return code is the length of the errorMsg string */ + { + sprintf(sqlInfoToken, "%s\n", errorMsg); + strcat(sqlInfo, sqlInfoToken); + } + + /* get SQLSTATE message */ + rc = sqlogstt(sqlstateMsg, 1024, 80, pSqlca->sqlstate); + if (rc > 0) + { + sprintf(sqlInfoToken, "%s\n", sqlstateMsg); + strcat(sqlInfo, sqlInfoToken); + } + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "---- end error report ------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } + else + { + sprintf(sqlInfoToken, + "---- end warning report ----------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } /* endif */ + } /* endif */ +} /* SqlInfoPrint */ + + +int CmdLineArgsCheck1(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck1 */ + +int CmdLineArgsCheck2(int argc, + char *argv[], + char nodeName[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(nodeName, ""); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(nodeName, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(nodeName, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [nodeName [userid passwd]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck2 */ + +int CmdLineArgsCheck3(int argc, + char *argv[], + char dbAlias[], + char nodeName[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(nodeName, ""); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(nodeName, ""); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 3: + strcpy(dbAlias, argv[1]); + strcpy(nodeName, argv[2]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 5: + strcpy(dbAlias, argv[1]); + strcpy(nodeName, argv[2]); + strcpy(user, argv[3]); + strcpy(pswd, argv[4]); + break; + default: + printf("\nUSAGE: %s [dbAlias [nodeName [userid passwd]]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck3 */ + +int CmdLineArgsCheck4(int argc, + char * argv[], + char dbAlias1[], + char dbAlias2[], + char user1[], + char pswd1[], + char user2[], + char pswd2[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias1, "sample"); + strcpy(dbAlias2, "sample2"); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 3: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 5: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[3]); + strcpy(pswd2, argv[4]); + break; + case 7: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[5]); + strcpy(pswd2, argv[6]); + break; + default: + printf("\nUSAGE: %s " + "[dbAlias1 dbAlias2 [user1 pswd1 [user2 pswd2]]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck4 */ + +int InstanceAttach(char nodeName[], + char user[], + char pswd[]) +{ + struct sqlca sqlca; + + if (strlen(nodeName) > 0) + { + printf("\n\n############## ATTACH TO THE INSTANCE: %s #######\n\n", + nodeName); + + /* attach to an instance */ + sqleatin(nodeName, user, pswd, &sqlca); + DB2_API_CHECK("instance -- attach"); + } + + return 0; +} /* CmdLineArgsCheck4 */ + + +int InstanceDetach(char * nodeName) +{ + struct sqlca sqlca; + + if (strlen(nodeName) > 0) + { + printf("\n\n############## DETACH FROM THE INSTANCE: %s #####\n\n", + nodeName); + + /* detach from an instance */ + sqledtin(&sqlca); + DB2_API_CHECK("instance -- detach"); + } + + return 0; +} /* InstanceDetach */ + diff --git a/sqlpl/utilapi.h b/sqlpl/utilapi.h new file mode 100644 index 0000000..2833486 --- /dev/null +++ b/sqlpl/utilapi.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilapi.h +** +** SAMPLE: Checks for and prints to the screen SQL warnings and errors +** +** This is the header file for the utilapi.c error-checking utility +** file. The utilapi.c file is compiled and linked in as an object +** module with non-embedded SQL sample programs by the supplied +** makefile and build files. +** +** Macros defined: +** DB2_API_CHECK(MSG_STR) +** EXPECTED_ERR_CHECK(MSG_STR) +** EXPECTED_WARN_CHECK(MSG_STR) +** +** Functions declared: +** SqlInfoPrint - prints to the screen SQL warnings and errors +** CmdLineArgsCheck1 - checks the command line arguments, version 1 +** CmdLineArgsCheck2 - checks the command line arguments, version 2 +** CmdLineArgsCheck3 - checks the command line arguments, version 3 +** CmdLineArgsCheck4 - checks the command line arguments, version 4 +** InstanceAttach - attach to instance +** InstanceDetach - detach from instance +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For more information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILAPI_H +#define UTILAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef max +#define max(A, B) ((A) > (B) ? (A) : (B)) +#endif +#ifndef min +#define min(A, B) ((A) > (B) ? (B) : (A)) +#endif + +#define USERID_SZ 128 +#define PSWD_SZ 14 + +#if (defined(DB2NT)) +#define PATH_SEP "\\" +#else /* UNIX */ +#define PATH_SEP "/" +#endif + +/* macro for DB2_API checking */ +#define DB2_API_CHECK(MSG_STR) \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ +if (sqlca.sqlcode < 0) \ +{ \ + return 1; \ +} + +/* macro for expected error checking and message */ +#define EXPECTED_ERR_CHECK(MSG_STR) \ +printf("\n-- The following error report is expected! --"); \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ + +/* macro for expected warning */ +#define EXPECTED_WARN_CHECK(MSG_STR) \ +printf("\n-- The following warning report is expected! --"); \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ + +/* functions used in ..._CHECK macros */ +void SqlInfoPrint(char *, struct sqlca *, int, char *); + +/* other functions */ +int CmdLineArgsCheck1(int, char * argv[], char *, char *, char *); +int CmdLineArgsCheck2(int, char * argv[], char *, char *, char *); +int CmdLineArgsCheck3(int, char * argv[], char *, char *, char *, char *); +int CmdLineArgsCheck4(int, char * argv[], char *, char *, + char *, char *, char *, char *); +int InstanceAttach(char * , char *, char *); +int InstanceDetach(char *); + +#ifdef __cplusplus +} +#endif + +#endif /* UTILAPI_H */ + diff --git a/sqlpl/utilcli.c b/sqlpl/utilcli.c new file mode 100644 index 0000000..215ae80 --- /dev/null +++ b/sqlpl/utilcli.c @@ -0,0 +1,563 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilcli.c +** +** SAMPLE: Utility functions used by CLI samples +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLColAttribute -- Return a Column Attribute +** SQLConnect -- Connect to a Data Source +** SQLDescribeCol -- Return a Set of Attributes for a Column +** SQLDisconnect -- Disconnect from a Data Source +** SQLEndTran -- End Transactions of a Connection +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLFreeStmt -- Free (or Reset) a Statement Handle +** SQLGetDiagRec -- Get Multiple Field Settings of Diagnostic Record +** SQLNumResultCols -- Get Number of Result Columns +** SQLSetConnectAttr -- Set Connection Attributes +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures, see the Application +** Development Guide. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilcli.h" + +/* local functions for utilcli.c */ +void HandleLocationPrint(SQLRETURN, int, char *); +void HandleDiagnosticsPrint(SQLSMALLINT, SQLHANDLE); + +/* outputs to screen unexpected occurrences with CLI functions */ +int HandleInfoPrint(SQLSMALLINT htype, /* handle type identifier */ + SQLHANDLE hndl, /* handle used by the CLI function */ + SQLRETURN cliRC, /* return code of the CLI function */ + int line, + char *file) +{ + int rc = 0; + + switch (cliRC) + { + case SQL_SUCCESS: + rc = 0; + break; + case SQL_INVALID_HANDLE: + printf("\n-CLI INVALID HANDLE-----\n"); + HandleLocationPrint(cliRC, line, file); + rc = 1; + break; + case SQL_ERROR: + printf("\n--CLI ERROR--------------\n"); + HandleLocationPrint(cliRC, line, file); + HandleDiagnosticsPrint(htype, hndl); + rc = 2; + break; + case SQL_SUCCESS_WITH_INFO: + rc = 0; + break; + case SQL_STILL_EXECUTING: + rc = 0; + break; + case SQL_NEED_DATA: + rc = 0; + break; + case SQL_NO_DATA_FOUND: + rc = 0; + break; + default: + printf("\n--default----------------\n"); + HandleLocationPrint(cliRC, line, file); + rc = 3; + break; + } + + return rc; +} /* HandleInfoPrint */ + +void HandleLocationPrint(SQLRETURN cliRC, int line, char *file) +{ + printf(" cliRC = %d\n", cliRC); + printf(" line = %d\n", line); + printf(" file = %s\n", file); +} /* HandleLocationPrint */ + +void HandleDiagnosticsPrint(SQLSMALLINT htype, /* handle type identifier */ + SQLHANDLE hndl /* handle */ ) +{ + SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; + SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER sqlcode; + SQLSMALLINT length, i; + + i = 1; + + /* get multiple field settings of diagnostic record */ + while (SQLGetDiagRec(htype, + hndl, + i, + sqlstate, + &sqlcode, + message, + SQL_MAX_MESSAGE_LENGTH + 1, + &length) == SQL_SUCCESS) + { + printf("\n SQLSTATE = %s\n", sqlstate); + printf(" Native Error Code = %ld\n", sqlcode); + printf("%s\n", message); + i++; + } + + printf("-------------------------\n"); +} /* HandleDiagnosticsPrint */ + +/* free statement handles and print unexpected occurrences */ +/* this function is used in STMT_HANDLE_CHECK */ +int StmtResourcesFree(SQLHANDLE hstmt) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + /* free the statement handle */ + cliRC = SQLFreeStmt(hstmt, SQL_UNBIND); + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, cliRC, __LINE__, __FILE__); + if (rc != 0) + { + return 1; + } + + /* free the statement handle */ + cliRC = SQLFreeStmt(hstmt, SQL_RESET_PARAMS); + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, cliRC, __LINE__, __FILE__); + if (rc != 0) + { + return 1; + } + + /* free the statement handle */ + cliRC = SQLFreeStmt(hstmt, SQL_CLOSE); + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, cliRC, __LINE__, __FILE__); + if (rc != 0) + { + return 1; + } + + return 0; +} /* StmtResourcesFree */ + +/* rollback transactions on a single connection */ +/* this function is used in HANDLE_CHECK */ +void TransRollback(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + rc = HandleInfoPrint(SQL_HANDLE_DBC, hdbc, cliRC, __LINE__, __FILE__); + if (rc == 0) + { + printf(" The transaction rolled back.\n"); + } +} /* TransRollback */ + +/* rollback transactions on mutiple connections */ +/* this function is used in HANDLE_CHECK */ +void MultiConnTransRollback(SQLHANDLE henv) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + printf("\n Rolling back the transactions...\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_ENV, henv, SQL_ROLLBACK); + rc = HandleInfoPrint(SQL_HANDLE_ENV, henv, cliRC, __LINE__, __FILE__); + if (rc == 0) + { + printf(" The transactions are rolled back.\n"); + } +} /* MultiConnTransRollback */ + +/* check command line arguments */ +int CmdLineArgsCheck1(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd]]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck1 */ + +/* check command line arguments */ +int CmdLineArgsCheck2(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[], + char remoteNodeName[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + strcpy(remoteNodeName, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + strcpy(remoteNodeName, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + strcpy(remoteNodeName, ""); + break; + case 5: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + strcpy(remoteNodeName, argv[4]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd [remoteNodeName]]]\n", + argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck2 */ + +/* check command line arguments */ +int CmdLineArgsCheck3(int argc, + char *argv[], + char dbAlias1[], + char dbAlias2[], + char user1[], + char pswd1[], + char user2[], + char pswd2[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias1, "sample"); + strcpy(dbAlias2, "sample2"); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 3: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 5: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[3]); + strcpy(pswd2, argv[4]); + break; + case 7: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[5]); + strcpy(pswd2, argv[6]); + break; + default: + printf("\nUSAGE: %s " + "[dbAlias1 dbAlias2 [user1 pswd1 [user2 pswd2]]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck3 */ + +/* initialize a CLI application by: + o allocating an environment handle + o allocating a connection handle + o setting AUTOCOMMIT + o connecting to the database */ +int CLIAppInit(char dbAlias[], + char user[], + char pswd[], + SQLHANDLE *pHenv, + SQLHANDLE *pHdbc, + SQLPOINTER autocommitValue) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + /* allocate an environment handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, pHenv); + if (cliRC != SQL_SUCCESS) + { + printf("\n--ERROR while allocating the environment handle.\n"); + printf(" cliRC = %d\n", cliRC); + printf(" line = %d\n", __LINE__); + printf(" file = %s\n", __FILE__); + return 1; + } + + /* allocate a database connection handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_DBC, *pHenv, pHdbc); + ENV_HANDLE_CHECK(*pHenv, cliRC); + + /* set AUTOCOMMIT off or on */ + cliRC = SQLSetConnectAttr(*pHdbc, + SQL_ATTR_AUTOCOMMIT, + autocommitValue, + SQL_NTS); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + + printf("\n Connecting to %s...\n", dbAlias); + + /* connect to the database */ + cliRC = SQLConnect(*pHdbc, + (SQLCHAR *)dbAlias, + SQL_NTS, + (SQLCHAR *)user, + SQL_NTS, + (SQLCHAR *)pswd, + SQL_NTS); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + printf(" Connected to %s.\n", dbAlias); + + return 0; +} /* CLIAppInit */ + +/* terminate a CLI application by: + o disconnecting from the database + o freeing the connection handle + o freeing the environment handle */ +int CLIAppTerm(SQLHANDLE * pHenv, SQLHANDLE * pHdbc, char dbAlias[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + printf("\n Disconnecting from %s...\n", dbAlias); + + /* disconnect from the database */ + cliRC = SQLDisconnect(*pHdbc); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + + printf(" Disconnected from %s.\n", dbAlias); + + /* free connection handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_DBC, *pHdbc); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + + /* free environment handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_ENV, *pHenv); + ENV_HANDLE_CHECK(*pHenv, cliRC); + + return 0; +} /* CLIAppTerm */ + +/* output result sets */ +int StmtResultPrint(SQLHANDLE hstmt, SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + SQLSMALLINT i; /* index */ + SQLSMALLINT nResultCols; /* variable for SQLNumResultCols */ + SQLCHAR colName[32]; /* variables for SQLDescribeCol */ + SQLSMALLINT colNameLen; + SQLSMALLINT colType; + SQLUINTEGER colSize; + SQLSMALLINT colScale; + SQLINTEGER colDataDisplaySize; /* maximum size of the data */ + SQLINTEGER colDisplaySize[MAX_COLUMNS]; /* maximum size of the column */ + + struct + { + SQLCHAR *buff; + SQLINTEGER len; + SQLINTEGER buffLen; + } + outData[MAX_COLUMNS]; /* variable to read the results */ + + /* identify the output columns */ + cliRC = SQLNumResultCols(hstmt, &nResultCols); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\n"); + for (i = 0; i < nResultCols; i++) + { + + /* return a set of attributes for a column */ + cliRC = SQLDescribeCol(hstmt, + (SQLSMALLINT)(i + 1), + colName, + sizeof(colName), + &colNameLen, + &colType, + &colSize, + &colScale, + NULL); + + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* get display size for column */ + cliRC = SQLColAttribute(hstmt, + (SQLSMALLINT)(i + 1), + SQL_DESC_DISPLAY_SIZE, + NULL, + 0, + NULL, + &colDataDisplaySize); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* set "column display size" to max of "column data display size", + and "column name length", plus at least one space between columns */ + colDisplaySize[i] = max(colDataDisplaySize, colNameLen) + 1; + + /* print the column name */ + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], colName); + + /* set "output data buffer length" to "column data display size" + plus one byte for the null terminator */ + outData[i].buffLen = colDataDisplaySize + 1; + + /* allocate memory to bind column */ + outData[i].buff = (SQLCHAR *)malloc((int)outData[i].buffLen); + + /* bind columns to program variables, converting all types to CHAR */ + cliRC = SQLBindCol(hstmt, + (SQLSMALLINT)(i + 1), + SQL_C_CHAR, + outData[i].buff, + outData[i].buffLen, + &outData[i].len); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + printf("\n"); + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + + while (cliRC == SQL_SUCCESS || cliRC == SQL_SUCCESS_WITH_INFO) + { + for (i = 0; i < nResultCols; i++) + { + /* check for NULL data */ + if (outData[i].len == SQL_NULL_DATA) + { + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], "NULL"); + } + else + { + /* print outData for this column */ + printf("%-*.*s", + (int)colDisplaySize[i], + (int)colDisplaySize[i], outData[i].buff); + } + } /* for all columns in this row */ + + printf("\n"); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } /* while rows to fetch */ + + /* free data buffers */ + for (i = 0; i < nResultCols; i++) + { + free(outData[i].buff); + } + + return rc; +} /* StmtResultPrint */ + + diff --git a/sqlpl/utilcli.h b/sqlpl/utilcli.h new file mode 100644 index 0000000..44f8a60 --- /dev/null +++ b/sqlpl/utilcli.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilcli.h +** +** SAMPLE: Declaration of utility functions used by CLI samples +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures, see the Application +** Development Guide. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILCLI_H +#define UTILCLI_H + +#define MAX_UID_LENGTH 18 +#define MAX_PWD_LENGTH 30 +#define MAX_STMT_LEN 255 +#define MAX_COLUMNS 255 +#ifdef DB2WIN +#define MAX_TABLES 50 +#else +#define MAX_TABLES 255 +#endif + +#ifndef max +#define max(a,b) (a > b ? a : b) +#endif + +/* macro for environment handle checking */ +#define ENV_HANDLE_CHECK(henv, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_ENV, henv, \ + cliRC, __LINE__, __FILE__); \ + if (rc != 0) return rc; \ +} + +/* macro for connection handle checking */ +#define DBC_HANDLE_CHECK(hdbc, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_DBC, hdbc, \ + cliRC, __LINE__, __FILE__); \ + if (rc != 0) return rc; \ +} + +/* macro for statement handle checking */ +#define STMT_HANDLE_CHECK(hstmt, hdbc, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, \ + cliRC, __LINE__, __FILE__); \ + if (rc == 2) StmtResourcesFree(hstmt); \ + if (rc != 0) TransRollback(hdbc); \ + if (rc != 0) return rc; \ +} + +/* macro for statement handle checking in + applications with multiple connections */ +#define MC_STMT_HANDLE_CHECK(hstmt, henv, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, \ + cliRC, __LINE__, __FILE__); \ + if (rc == 2) StmtResourcesFree(hstmt); \ + if (rc != 0) MultiConnTransRollback(henv); \ + if (rc != 0) return rc; \ +} + +/* functions used in ...CHECK_HANDLE macros */ +int HandleInfoPrint(SQLSMALLINT, SQLHANDLE, SQLRETURN, int, char *); +void CLIAppCleanUp(SQLHANDLE *, SQLHANDLE a_hdbc[], int); +int StmtResourcesFree(SQLHANDLE); +void TransRollback(SQLHANDLE); +void MultiConnTransRollback(SQLHANDLE); + +/* functions to check the number of command line arguments */ +int CmdLineArgsCheck1(int, char *argv[], char *, char *, char *); +int CmdLineArgsCheck2(int, char *argv[], char *, char *, char *, char *); +int CmdLineArgsCheck3(int, char *argv[], char *, char *, + char *, char *, char *, char *); + +/* other utility functions */ +int CLIAppInit(char *, char *, char *, SQLHANDLE *, SQLHANDLE *, SQLPOINTER); +int CLIAppTerm(SQLHANDLE *, SQLHANDLE *, char *); +int StmtResultPrint(SQLHANDLE, SQLHANDLE); + +#endif + diff --git a/sqlpl/utilemb.h b/sqlpl/utilemb.h new file mode 100644 index 0000000..b880329 --- /dev/null +++ b/sqlpl/utilemb.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilemb.h +** +** SAMPLE: Checks for and prints to the screen SQL warnings and errors +** +** This is the header file for the utilemb.sqc error-checking utility +** file. The utilemb.sqc file is compiled and linked in as an object +** module with embedded SQL sample programs by the supplied makefile +** and build files. +** +** Macro defined: +** EMB_SQL_CHECK(MSG_STR) +** +** Functions declared: +** TransRollback - rolls back the transaction +** DbConn - connects to the database +** DbDisconn - disconnects from the database +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILEMB_H +#define UTILEMB_H + +#include "utilapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_UID_LENGTH 18 +#define MAX_PWD_LENGTH 30 + +#ifndef max +#define max(A, B) ((A) > (B) ? (A) : (B)) +#endif +#ifndef min +#define min(A, B) ((A) > (B) ? (B) : (A)) +#endif + +#define LOBLENGTH 29 + +/* macro for embedded SQL checking */ +#define EMB_SQL_CHECK(MSG_STR) \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ +if (sqlca.sqlcode < 0) \ +{ \ + TransRollback(); \ + return 1; \ +} + +/* function used in EMB_SQL_CHECK macro */ +void TransRollback(void); + +/* other useful functions with self-explanatory names */ +int DbConn(char * , char *, char *); +int DbDisconn(char *); + +#ifdef __cplusplus +} +#endif + +#endif /* UTILEMB_H */ + diff --git a/sqlpl/utilemb.sqc b/sqlpl/utilemb.sqc new file mode 100644 index 0000000..0601e2a --- /dev/null +++ b/sqlpl/utilemb.sqc @@ -0,0 +1,129 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilemb.sqc +** +** SAMPLE: Checks for and prints to the screen SQL warnings and errors +** +** This utility file is compiled and linked in as an object module +** with embedded SQL sample programs by the supplied makefile and +** build files. +** +** SQL STATEMENTS USED: +** BEGIN DECLARE SECTION +** END DECLARE SECTION +** ROLLBACK +** CONNECT +** +** Included functions: +** TransRollback - rolls back the transaction +** DbConn - connects to the database +** DbDisconn - disconnects from the database +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "utilapi.c" +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char dbAlias[15]; + char user[129]; + char pswd[15]; +EXEC SQL END DECLARE SECTION; + +void TransRollback() +{ + struct sqlca sqlca; + + /* rollback the transaction */ + printf("\n Rolling back the transaction...\n"); + + EXEC SQL ROLLBACK; + SqlInfoPrint("ROLLBACK", &sqlca, __LINE__, __FILE__); + if (sqlca.sqlcode == 0) + { + printf(" The transaction was rolled back.\n"); + } +} /* TransRollback */ + +int DbConn(char paramDbAlias[], char paramUser[], char paramPswd[]) +{ + struct sqlca sqlca; + int rc = 0; + + strcpy(dbAlias, paramDbAlias); + strcpy(user, paramUser); + strcpy(pswd, paramPswd); + + printf("\n Connecting to '%s' database...\n", dbAlias); + if (strlen(user) == 0) + { + EXEC SQL CONNECT TO :dbAlias; + EMB_SQL_CHECK("CONNECT"); + } + else + { + EXEC SQL CONNECT TO :dbAlias USER :user USING :pswd; + EMB_SQL_CHECK("CONNECT"); + } + printf(" Connected to '%s' database.\n", dbAlias); + + return 0; +} /* DbConn */ + +int DbDisconn(char *dbAlias) +{ + struct sqlca sqlca; + int rc = 0; + + printf("\n Disconnecting from '%s' database...\n", dbAlias); + + /* Commit all non-committed transactions to release database locks */ + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + + printf(" Disconnected from '%s' database.\n", dbAlias); + + return 0; +} /* DbDisconn */ + diff --git a/sqlpl/whiles.db2 b/sqlpl/whiles.db2 new file mode 100644 index 0000000..0253784 --- /dev/null +++ b/sqlpl/whiles.db2 @@ -0,0 +1,94 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: whiles.db2 +-- +-- SAMPLE: To create the DEPT_MEDIAN SQL procedure +-- +-- To create the SQL procedure: +-- 1. Connect to the database +-- 2. Enter the command "db2 -td@ -vf whiles.db2" +-- +-- To call the SQL procedure from the command line: +-- 1. Connect to the database +-- 2. Enter the following command: +-- db2 "CALL dept_median (51, ?)" +-- +-- You can also call this SQL procedure by compiling and running the +-- C embedded SQL client application, "whiles", using the whiles.sqc +-- source file available in the sqlpl samples directory. +----------------------------------------------------------------------------- +-- +-- For more information on the sample scripts, see the README file. +-- +-- For information on creating SQL procedures, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CREATE PROCEDURE dept_median +(IN deptNumber SMALLINT, OUT medianSalary DOUBLE) +LANGUAGE SQL +BEGIN + DECLARE SQLCODE INTEGER; + DECLARE SQLSTATE CHAR(5); + DECLARE v_numRecords INT DEFAULT 1; + DECLARE v_counter INT DEFAULT 0; + DECLARE v_mod INT DEFAULT 0; + DECLARE v_salary1 DOUBLE DEFAULT 0; + DECLARE v_salary2 DOUBLE DEFAULT 0; + + DECLARE c1 CURSOR FOR + SELECT CAST(salary AS DOUBLE) FROM staff + WHERE DEPT = deptNumber + ORDER BY salary; + DECLARE EXIT HANDLER FOR NOT FOUND + SET medianSalary = 6666; + + -- initialize OUT parameter + SET medianSalary = 0; + + SELECT COUNT(*) INTO v_numRecords FROM staff + WHERE DEPT = deptNumber; + + OPEN c1; + + SET v_mod = MOD(v_numRecords, 2); + + CASE v_mod + WHEN 0 THEN + WHILE v_counter < (v_numRecords / 2 + 1) DO + SET v_salary1 = v_salary2; + FETCH c1 INTO v_salary2; + SET v_counter = v_counter + 1; + END WHILE; + SET medianSalary = (v_salary1 + v_salary2)/2; + WHEN 1 THEN + WHILE v_counter < (v_numRecords / 2 + 1) DO + FETCH c1 INTO medianSalary; + SET v_counter = v_counter + 1; + END WHILE; + END CASE; +END @ diff --git a/sqlpl/whiles.sqc b/sqlpl/whiles.sqc new file mode 100644 index 0000000..254d424 --- /dev/null +++ b/sqlpl/whiles.sqc @@ -0,0 +1,167 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: whiles.sqc +** +** SAMPLE: To call the DEPT_MEDIAN SQL procedure +** +** There are two parts to this program: +** 1. the whiles executable (placed on the client) +** 2. the DEPT_MEDIAN SQL procedure (created on the +** server with the whiles.db2 CLP script) +** +** whiles calls the DEPT_MEDIAN SQL procedure by preparing +** and executing a dynamic CALL statement: +** +** sprintf(stmt, "CALL %s (?,?)", procname); +** EXEC SQL prepare st from :stmt; +** EXEC SQL execute st INTO :sal:salind USING :dept:deptind; +** +** When the CALL with Host Variable is used, +** the precompiler allocates and initializes an internal two +** variable SQLDA for both input and output. +** +** The DEPT_MEDIAN procedure obtains the median salary of +** employees in a department identified by the dept IN parameter +** from the "staff" table of the "sample" database. +** The median value is assigned to the salary OUT parameter and +** returned to the whiles executable. The whiles routine +** then prints the median salary. +** +** SQL STATEMENTS USED: +** CONNECT +** CALL +** +** OUTPUT FILE: whiles.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on creating SQL procedures and developing C applications, +** see the Application Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + + +int main(int argc, char *argv[]) { + + EXEC SQL BEGIN DECLARE SECTION; + char database[9]; + char userid[9]; + char passwd[19]; + + /* Declare a Local Variable for Holding the Procedure's Name */ + char procname[254] = "DEPT_MEDIAN"; + + /* Declare a statement strings to call the procedure dynamically */ + char stmt[1200]; + + /* Declare local variables for holding returned values */ + double sal = 0; + sqlint16 salind = 0; + + /* Declare local variables for holding IN parameter */ + sqlint16 dept = 0; + sqlint16 deptind = 0; + EXEC SQL END DECLARE SECTION; + + + /* Declare the output SQLDA */ + struct sqlda *inout_sqlda = (struct sqlda *) + malloc(SQLDASIZE(1)); + + /* Declare the SQLCA */ + struct sqlca sqlca; + + char eBuffer[1024]; /* error message buffer */ + + if (argc != 4) { + printf ("\nUSAGE: whiles remote_database userid passwd\n\n"); + return 1; + } + strcpy (database, argv[1]); + strcpy (userid, argv[2]); + strcpy (passwd, argv[3]); + /* Connect to Remote Database */ + printf("CONNECT TO Remote Database.\n"); + EXEC SQL CONNECT TO :database USER :userid USING :passwd; + EMB_SQL_CHECK("CONNECT TO RSAMPLE"); + + /********************************************************\ + * Call the Remote Procedure via CALL with Host Variables * + \********************************************************/ + printf("Use CALL with Host Variables to invoke the Server Procedure " + "named %s\n", procname); + dept = 51; /* get median for dept. 51 */ + deptind = 0; /* dept is an IN parameter */ + salind = -1; /* sal is an OUT parameter */ + sprintf(stmt, "CALL %s (?,?)", procname); + + EXEC SQL prepare st from :stmt; + EMB_SQL_CHECK("PREPARE CALL STATEMENT"); + + EXEC SQL execute st INTO :sal:salind USING :dept:deptind; + EMB_SQL_CHECK("EXECUTE CALL STATEMENT"); + + /********************************************************\ + * Display the returned median salary information * + \********************************************************/ + + printf("\nThe median salary of department %d = %.2lf\n", dept, sal); + + /* COMMIT or ROLLBACK the transaction */ + if (SQLCODE == 0) + { /* Rollback the changes to the database */ + EXEC SQL ROLLBACK; + printf("Server Procedure Complete.\n"); + } + else + { /* print the error message, roll back the transaction and return */ + sqlaintp (eBuffer, 1024, 80, &sqlca); + printf("\n%s\n", eBuffer); + + EXEC SQL ROLLBACK; + printf("Server Procedure Transaction Rolled Back.\n\n"); + return 1; + } + + /* Free allocated memory */ + free( inout_sqlda ); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} +/* end of program : whiles.sqc */ + diff --git a/webservices/soapsample.sql b/webservices/soapsample.sql new file mode 100644 index 0000000..1a267e3 --- /dev/null +++ b/webservices/soapsample.sql @@ -0,0 +1,152 @@ +---------------------------------------------------------------------------- +-- Licensed Materials - Property of IBM +-- Governed under the terms of the IBM Public License +-- +-- (C) COPYRIGHT International Business Machines Corp. 1995, 2002 +-- All Rights Reserved. +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: soapsample.sql +-- +-- SAMPLE: How to define and invoke DB2 Web Service functions. +-- +-- SQL STATEMENTS USED: +-- CREATE FUNCTION +-- VALUES +-- SELECT +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For more information about SQL, see the "SQL Reference". +-- +-- For the latest information on programming, compiling, and running DB2 +-- applications, refer to the DB2 application development website at +-- http://www.software.ibm.com/data/db2/udb/ad +-- +-- List of Examples (for DB2 Version UDB Version 8) +-- * getQuote - retrieve 20 minute delayed stock quote +-- * getRate - returns the exchange rate between any two currencies +-- +-- Due to the nature of these web services being changed, we cannot guarantee +-- them working all the time. + +---------------------------------------------------------------------------- + +-- *************************************************************************** +-- +-- getQuote: for company name retrieve stock quote. +-- +-- *************************************************************************** + +-- for DB2 UDB Version 8.2 using SQL/XML: + +VALUES substr(DB2XML.SOAPHTTPV ('http://64.124.140.30:9090/soap', '', + XML2CLOB( + XMLELEMENT(NAME "nrs:getQuote", + XMLNAMESPACES('urn:xmethods-delayed-quotes' as "nrs", + 'http://schemas.xmlsoap.org/soap/encoding/' AS "SOAP-ENV_encodingStyle"), + XMLELEMENT(NAME "symbol", 'IBM')))), 1, 200); + + +-- Create a SOAP UDF + +DROP FUNCTION getQuote; + +CREATE FUNCTION GetQuote (symbol VARCHAR(5)) + RETURNS VARCHAR(40) + LANGUAGE SQL CONTAINS SQL + EXTERNAL ACTION NOT DETERMINISTIC + RETURN + WITH + +--1. Perform type conversions and prepare SQL input parameters for SOAP envelope + + soap_input (in) + AS + (VALUES VARCHAR(XML2CLOB( + XMLELEMENT(NAME "ns:getQuote", + XMLNAMESPACES('urn:xmethods-delayed-quotes' as "ns"), + XMLELEMENT(NAME "symbol", symbol))))), + +--2. Submit SOAP request with input parameter and receive SOAP response + + soap_output (out) + AS + (VALUES DB2XML.SOAPHTTPV ('http://64.124.140.30:9090/soap','', + (SELECT in FROM soap_input))) + +--3. Shred SOAP response and perform type conversions to get SQL output parameters + + SELECT SUBSTR (out, + POSSTR(out,'float">')+7, + POSSTR(out,'') -7) + FROM soap_output; + +DROP TABLE COMPANY; +CREATE TABLE COMPANY(name VARCHAR(40), stock_symbol VARCHAR(5)); +INSERT INTO COMPANY + VALUES ('International Business Machines', 'IBM'), + ('MOTOROLA', 'MOT'), + ('ORACLE', 'ORCL'), + ('YAHOO INC', 'YHOO'); + + +SELECT name, stock_symbol,GetQuote(stock_symbol) AS stock_quote +FROM COMPANY where stock_symbol='IBM'; + + +-- *************************************************************************** +-- +-- getRate - returns the exchange rate between any two currencies +-- +-- *************************************************************************** + + +VALUES substr(DB2XML.SOAPHTTPV ('http://services.xmethods.net:80/soap', '', + XML2CLOB( XMLELEMENT(NAME "ns:getRate", + XMLNAMESPACES('urn:xmethods-CurrencyExchange' as "ns"), + XMLELEMENT(NAME "country1", 'united states'), + XMLELEMENT(NAME "country2", 'korea')))), 1, 160); + +-- Create SOAP UDF + +DROP FUNCTION getrate; + +CREATE FUNCTION GetRate (from VARCHAR(32), to VARCHAR(32)) + RETURNS VARCHAR(40) + LANGUAGE SQL READS SQL DATA + EXTERNAL ACTION NOT DETERMINISTIC + RETURN + WITH + +--1. Perform type conversions and prepare SQL input parameters for SOAP envelope + soap_input (in) + AS + (VALUES VARCHAR(XML2CLOB( + XMLELEMENT(NAME "ns:getRate", XMLNAMESPACES('urn:xmethods-CurrencyExchange' as "ns"), + XMLELEMENT(NAME "country1", from), + XMLELEMENT(NAME "country2", to))))), + +--2. Submit SOAP request with input parameter and receive SOAP response + + soap_output (out) + AS + (VALUES DB2XML.SOAPHTTPV('http://services.xmethods.net:80/soap','', + (SELECT in FROM soap_input))) + + +--3. Shred SOAP response and perform type conversions to get SQL output parameters + + SELECT SUBSTR (out, + POSSTR(out,'float">')+7, + POSSTR(out,'') -7) + FROM soap_output; + + +VALUES GetRate('united states', 'korea'); + + diff --git a/wrappers/wrapper_sdk/cc_plugin/README b/wrappers/wrapper_sdk/cc_plugin/README new file mode 100644 index 0000000..abe3b0b --- /dev/null +++ b/wrappers/wrapper_sdk/cc_plugin/README @@ -0,0 +1,11 @@ +***************************************************************************** +* +* README for Sample wrapper plugin +* +* Last updated: +* +* This sample wrapper plugin demonstrates concrete discovery function. +* +* WARNING: +* +***************************************************************************** diff --git a/wrappers/wrapper_sdk/cc_plugin/makefile b/wrappers/wrapper_sdk/cc_plugin/makefile new file mode 100644 index 0000000..c884a26 --- /dev/null +++ b/wrappers/wrapper_sdk/cc_plugin/makefile @@ -0,0 +1,32 @@ +# Makefile for the Sample Wrapper Discovery +# +# +# To build this wrapper discovery routine, issue the following command: +# On Windows : nmake -if makefile +# On AIX : gnumake +# +# Variables: (Change as appropriate) +# +# INSTHOME: Absolute path of the DB2 Instance (WARNING: NO WHITESPACES ALLOWED) +# +# JAVAHOME: Absolute path of the jdk bin directory +# + +INSTHOME = "c:\Sqllib\" + +JAVAHOME = "c:\sqllib\java\jdk\bin\" + +# +# Steps: +# compile java class for the concrete discovery +# create the sampleSP.jar and put the java class inside +# move the sampleSP.jar to SQLLIB/tools +# + +all: + $(JAVAHOME)javac sample.java + $(JAVAHOME)jar cf sampleSP.jar sample.class + copy sampleSP.jar $(INSTHOME)tools + + + \ No newline at end of file diff --git a/wrappers/wrapper_sdk/cc_plugin/sample.db2 b/wrappers/wrapper_sdk/cc_plugin/sample.db2 new file mode 100644 index 0000000..1527067 --- /dev/null +++ b/wrappers/wrapper_sdk/cc_plugin/sample.db2 @@ -0,0 +1,34 @@ +----------------------------------------------------------------------------- +-- Licensed Materials - Property of IBM +-- +-- Governed under the terms of the International +-- License Agreement for Non-Warranted Sample Code. +-- +-- (C) COPYRIGHT International Business Machines Corp. 1995 - 2002 +-- All Rights Reserved. +-- +-- US Government Users Restricted Rights - Use, duplication or +-- disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +----------------------------------------------------------------------------- +-- +-- Installs sampleSP.jar to the database and creates +-- the java stored procedure for the SampleWrapper nickname discovery. +-- +-- PLEASE CHANGE ALL OCCURENCES OF SCHEMA to the intended user name +-- PLEASE CHANGE THE JARPATH to the location of the jar file +-- example: on Windows, it might be c:\sqllib\tools\ +-- so the CALL sqlj.install_jar command like: +-- CALL sqlj.install_jar('file:///c:\Sqllib\tools\sampleSP.jar', 'sampleSP') +-- on AIX, it might be /home/userid/sqllib/tools/ +-- CALL sqlj.install_jar('file:/home/userid/sqllib/tools/sampleSP.jar', 'sampleSP') +-- +-- To run this file enter in command line: db2 -tvf sample.db2 +-- + +CALL sqlj.remove_jar('sampleSP'); + +DROP PROCEDURE SCHEMA.SAMPLE(VARCHAR(4000), VARCHAR(4000), VARCHAR(10), VARCHAR(1)); + +CALL sqlj.install_jar('file:JARPATH\sampleSP.jar', 'sampleSP'); + +CREATE PROCEDURE SCHEMA.SAMPLE (IN WrapperName VARCHAR(4000),IN directory VARCHAR(4000),IN extension VARCHAR(10),IN subfolder VARCHAR(1) ) SPECIFIC SAMPLE DYNAMIC RESULT SETS 1 NOT DETERMINISTIC LANGUAGE Java EXTERNAL NAME 'sample!get_Nicknames' FENCED NOT THREADSAFE PARAMETER STYLE JAVA; \ No newline at end of file diff --git a/wrappers/wrapper_sdk/cc_plugin/sample.java b/wrappers/wrapper_sdk/cc_plugin/sample.java new file mode 100644 index 0000000..5825636 --- /dev/null +++ b/wrappers/wrapper_sdk/cc_plugin/sample.java @@ -0,0 +1,135 @@ + + /* JDBC Stored Procedure SSKORSE.sample + * + * param directory + * @param extension + * @param subfolder + * @param File_List + */ + +import java.util.*; +import java.sql.*; +import java.io.*; +import java.io.File; + +public class sample +{ + /** + * + * @param WrapperName + * @param directory + * @param extension + * @param subfolder + * @param rs1 + * @exception SQLException + * @exception Exception + */ + public static void get_Nicknames (String WrapperName, + String directory, + String extension, + String subfolder, + ResultSet[] rs1 ) throws SQLException, Exception + { + Connection con = DriverManager.getConnection("jdbc:default:connection"); // database connection + PreparedStatement stmt = null; + String info = null; // for the user message + String sql = null; // SQL - Statement + Vector files = new Vector(); // stores the files + Stack dirs = new Stack(); // stores the directories + File startdir = new File(directory); // start directory + String result = null; // xml - document for the files + + + if ( startdir.isDirectory() ){ // if startdirectory exists + dirs.push( new File(directory) ); // add directory to the stack + } else { + info = "Directory <" + directory + "> does not exist!"; // else build message for the user + } + + while ( dirs.size() > 0 ) { // gets all the files and put them into the vector files + File dirFiles = (File) dirs.pop(); + String s[] = dirFiles.list(); + if ( s != null ){ + for ( int i = 0; i < s.length; i++ ) { + File file = new File( dirFiles.getAbsolutePath() + File.separator + s[i] ); + if ( subfolder.equalsIgnoreCase("Y") && file.isDirectory() ){ // if parameter 'subfolder' = 'Y' search subfolders + dirs.push( file ); + } + else if ( (s[i].length() >= extension.length() && s[i].substring(s[i].length() - extension.length(), s[i].length()).equalsIgnoreCase(extension)) ){ + files.addElement( file ); // if file is valid, add to the vector containing the files + } + } + } + } + if (files.size() > 0) { // if files found, build XML - Document valid to FederatedFromXML.dtd + result = XMLBuild(files); + } + else if (info == null) // else build message for the user + info = "No files with extension <" + extension + "> found in directory <" + directory + ">!"; + if (result != null) { // if files were found - build SQL-Query to pass them + sql = "WITH T(XMLDocument, UserInfo) AS (VALUES(CAST('" + result + "' AS BLOB), CAST(NULL AS VARCHAR(100)))) SELECT * FROM T"; + }else{ // else - build SQL-Query to pass message for user + sql = "WITH T(XMLDocument, UserInfo) AS (VALUES(CAST(NULL AS BLOB), CAST('" + info + "' AS VARCHAR(100)))) SELECT * FROM T"; + } + stmt = con.prepareStatement( sql ); // Connection prepare Statement + rs1[0] = stmt.executeQuery(); // execute Query + con.close(); // close Statement + } + + private static String XMLBuild(Vector files) { // builds the xml document for the files + + StringBuffer xml = new StringBuffer("\n\n"); + xml.append(" \n"); // start with XML-Version + federatedObject tag + + for ( int i = 0; i < files.size(); i++ ) { // for all found files do + + StringBuffer column = new StringBuffer(""); // StringBuffer for the column tag + + try { + FileReader in = new FileReader((File)files.elementAt(i)); // build FileReader for the file + BufferedReader br = new BufferedReader(in); // build BufferedReader for the file + String colContent = null; // build String for the content of the columns + int x = 1; // add iterator for the number of columns + try { + + String line = br.readLine(); // read the first line of the file + if (line != null) { + while (line.indexOf(',') != -1) { // if there's still more then one column left + colContent = line.substring(0, line.indexOf(',')); // get content of the column + build column tag + + column = column.append("\n\t\t\n\t\t\tColumn_" + x + "\n\t\t"); + + line = line.substring(line.indexOf(',') + 1); // get the columns which are left + x++; // iterate number of columns + } + x++; + } + if (x > 1) { // build column tag for the last column + + column = column.append("\n\t\t\n\t\t\tColumn_" + (x-1) + "\n\t\t"); + } + + }catch (IOException io) { // if IOException appears + System.out.println("Input/Output Exception while reading files for XMLBuild"); + } + } catch (FileNotFoundException fnfw) { // if FileNotFoundExcsption appears + System.err.println("File not found Exception in Method XMLBuild()"); + } + + xml.append("\t \n\t\t"); // build nickname tag + String h = (files.elementAt(i).toString()); // add name + xml.append(h.substring(h.lastIndexOf(File.separator) + 1, h.lastIndexOf("."))); + xml.append(" \n\t\t" + column.toString() + "\n\t\n"); // add column tag + + } + + xml.append(""); // close federatedObject tag + return xml.toString(); // return XML - Document as String + } +} diff --git a/wrappers/wrapper_sdk/cc_plugin/sample.properties b/wrappers/wrapper_sdk/cc_plugin/sample.properties new file mode 100644 index 0000000..5d685d6 --- /dev/null +++ b/wrappers/wrapper_sdk/cc_plugin/sample.properties @@ -0,0 +1,8 @@ +SAMPLE_SVRKIND = Sample Wrapper +SAMPLE_WRAPPER_DESC = The sample wrapper is a restricted version of the falt-file wrapper. It wraps a table-structured file with following properties: each line in data file maps to a row in a table, and columns in each line are comma separated. +SAMPLE_WRPOPT_DB2_FENCED_DESC = Specifies if the wrapper runs in the fenced mode or trusted mode. +SAMPLE_WRPOPT_DB2_FENCED_HINT = Valid values are 'Y' and 'N'. The default for this wrapper is 'N', the wrapper runs in the trusted mode. +SAMPLE_NNOPT_FILE_PATH_DESC = The fully qualified path to the table-structured file being accessed. +SAMPLE_GUIOPT_DIRECTORY_DESC = The directory to search for. +SAMPLE_GUIOPT_EXTENSION_DESC = The file extension to search for. +SAMPLE_GUIOPT_SUB_DIRECTORY_DESC = Specify "Y" to search sub directory. diff --git a/wrappers/wrapper_sdk/cc_plugin/sample.xml b/wrappers/wrapper_sdk/cc_plugin/sample.xml new file mode 100644 index 0000000..b3056aa --- /dev/null +++ b/wrappers/wrapper_sdk/cc_plugin/sample.xml @@ -0,0 +1,57 @@ + + + + + + SAMPLE_WRAPPER_DESC + + + + + + + + + + + CHARACTER + VARCHAR + INTEGER + DECIMAL + DOUBLE + + + Nickname + SAMPLE + + + + + + + + + diff --git a/wrappers/wrapper_sdk/makefile b/wrappers/wrapper_sdk/makefile new file mode 100644 index 0000000..5309c21 --- /dev/null +++ b/wrappers/wrapper_sdk/makefile @@ -0,0 +1,117 @@ +# NOTE: +# 1. This is a gnumake makefile. +# 2. Use a g++ version 3.2 or newer when building the wrapper +# + +# +# Location of UDB instance. Change as appropriate. +# +INSTHOME = /home/${DB2INSTANCE} + +# +# Wrapper library definitions. Change these as appropriate +# + +# Object files that make up the sample wrapper +UNFENCED_WRAPPER_OBJ_FILES = sample_wrapper.o \ + sample_server.o \ + sample_user.o \ + sample_nickname.o \ + sample_utilities.o + +FENCED_WRAPPER_OBJ_FILES = sample_connection.o \ + sample_operation.o \ + sample_fenced_wrapper.o \ + sample_fenced_server.o \ + sample_fenced_nickname.o \ + sample_utilities.o + +# Name of wrapper library to be created. Change name as appropriate +WRAPPER_ARCHIVE_NAME = libsample + +# These macros shouldn't be changed +WRAPPER_ARCHIVE_LIB = $(WRAPPER_ARCHIVE_NAME).$(SHARED_LIB_EXT) +FENCED_WRAPPER_ARCHIVE_LIB = $(WRAPPER_ARCHIVE_NAME)F.$(SHARED_LIB_EXT) +UNFENCED_WRAPPER_ARCHIVE_LIB = $(WRAPPER_ARCHIVE_NAME)U.$(SHARED_LIB_EXT) + +# +# Tools and Macros. These are platform specific. +# The following is for Linux + +SHARED_LIB_EXT = so +CCC = g++ +CCC_LIB = g++ +COPTS = -c -D SQLLinux -D SQLUNIX -g -mpentiumpro -fcheck-new -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -DNO_64K_MSGS -D__NO_MATH_INLINES -DSIGPRE=SIGURG -D__STDC_LIMIT_MACROS -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_REENTRANT -fpic +LDFLAGS = -shared -g -lpthread -lm -lc + + +# +# UDB definitions. These should not need to be changed. +# + +# Location of the wrapper include files and public include files +UDB_INCLUDE_DIR = ${INSTHOME}/sqllib/include + + +### Start 64-bit settings ### + +# Use the following if building on a 64-bit system + +# Location of the DB2 UDB libraries +UDB_LIB_DIR = ${INSTHOME}/sqllib/lib64 + +### End 64-bit settings ### + + +### Start 32-bit settings ### + +# Use the following if building on a 32-bit system + +# Location of the DB2 UDB libraries +# UDB_LIB_DIR = ${INSTHOME}/sqllib/lib32 + +# Enforce INT32 to INT mapping +# UDB_FLAGS = -DDB2_FORCE_INT32_TYPES_TO_INT + +#### End 32-bit settings ### + + +all: ${UNFENCED_WRAPPER_ARCHIVE_LIB} ${FENCED_WRAPPER_ARCHIVE_LIB} move + +$(UNFENCED_WRAPPER_ARCHIVE_LIB): $(UNFENCED_WRAPPER_OBJ_FILES) + $(CCC_LIB) \ + -eUnfencedWrapper_Hook \ + $(filter %.o, $^) \ + ${LDFLAGS} \ + -o $@ + +${FENCED_WRAPPER_ARCHIVE_LIB}: ${FENCED_WRAPPER_OBJ_FILES} ${UDB_EXPORTS} + ${CCC_LIB} \ + -eFencedWrapper_Hook \ + $(filter %.o, $^) \ + $(LDFLAGS) \ + -o $@ + +move: + -rm -f ${UDB_LIB_DIR}/${UNFENCED_WRAPPER_ARCHIVE_LIB} + -rm -f ${UDB_LIB_DIR}/${FENCED_WRAPPER_ARCHIVE_LIB} + cp ${UNFENCED_WRAPPER_ARCHIVE_LIB} ${UDB_LIB_DIR} + cp ${FENCED_WRAPPER_ARCHIVE_LIB} ${UDB_LIB_DIR} + cp ${UDB_LIB_DIR}/libdb2sqqgtop.$(SHARED_LIB_EXT) ${UDB_LIB_DIR}/$(WRAPPER_ARCHIVE_LIB) + +# +# Pattern rules +# +%.o : %.C + ${CCC} ${COPTS} ${UDB_FLAGS} -I${UDB_INCLUDE_DIR} -c $< + +# +# Useful targets +# +depend: $(wildcard *.u) + -cat $^ /dev/null | egrep -v "/usr/" > $@ + +clean: + rm -f *.o *.u *.map depend ${UNFENCED_WRAPPER_ARCHIVE_LIB} ${FENCED_WRAPPER_ARCHIVE_LIB} + +include depend diff --git a/wrappers/wrapper_sdk/sample_connection.C b/wrappers/wrapper_sdk/sample_connection.C new file mode 100755 index 0000000..6b6f3be --- /dev/null +++ b/wrappers/wrapper_sdk/sample_connection.C @@ -0,0 +1,242 @@ +/********************************************************************** +* +* Source File Name = sample_connction.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for sample connection class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_connection.h" +#include "sample_operation.h" +#include "sample_error_reporting.h" + +#include "sqlqg_catalog.h" +#include "sqlcodes.h" + + +////////////////////////////////////////////////////////////////////////////////// +// Sample_Connection class. +////////////////////////////////////////////////////////////////////////////////// + +/************************************************************************** +* +* Function Name = Sample_Connection::Sample_Connection() +* +* Function: Constructor for Sample_Connection class +* +* Dependencies: +* +* Restrictions: +* +* Input: FencedServer* server: server to which connection is desired +* FencedRemote_User* user: user info for connection +* +* Output: sqlint32 *rc: return code to indicate a problem +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +Sample_Connection::Sample_Connection(FencedServer* server, FencedRemote_User *user, + sqlint32 *rc) + :Remote_Connection(server, user, one_phase_kind, rc) +{ + Wrapper_Utilities::fnc_entry(40,"Sample_Connection::Sample_Connection"); + Wrapper_Utilities::fnc_exit(40,"Sample_Connection::Sample_Connection", *rc); +} + +/************************************************************************** +* +* Function Name = Sample_Connection::~Sample_Connection() +* +* Function: Destructor for Sample_Connection class +* +* Dependencies: +* +* Restrictions: +* +* Input: none. +* +* Output: none. +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +Sample_Connection::~Sample_Connection() +{ + Wrapper_Utilities::fnc_entry(41,"Sample_Connection::~Sample_Connection"); + Wrapper_Utilities::fnc_exit(41,"Sample_Connection::~Sample_Connection", 0); +} + +/************************************************************************** +* +* Function name: Sample_Connection::connect() +* +* Function: establish connection to the remote server +* +* Input: none +* +* Output: none +* +**************************************************************************/ +sqlint32 Sample_Connection::connect() +{ + sqlint32 rc=0; + Wrapper_Utilities::fnc_entry(42,"Sample_Connection::connect"); + + Wrapper_Utilities::fnc_exit(42,"Sample_Connection::connect", rc); + return rc; +} + +/************************************************************************** +* +* Function name: Sample_Connection::disconnect() +* +* Function: disconnect from the server. +* +* Input: none +* +* Output: none +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Connection::disconnect() +{ + sqlint32 rc=0; + Wrapper_Utilities::fnc_entry(43,"Sample_Connection::disconnect"); + + Wrapper_Utilities::fnc_exit(43,"Sample_Connection::disconnect", rc); + return rc; +} + +/************************************************************************** +* +* Function Name = Sample_Connection::create_remote_query() +* +* Function: create a Remote_Query object with all +* necessary state information for executing a query. +* +* Input: remoteQuery* runtime_query: pointer to runtime query operator +* +* Output: Remote_Query** query: newly created Remote_Query object +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Connection::create_remote_query(Runtime_Operation* runtime_query, + Remote_Query** query) +{ + sqlint32 rc=0; + Wrapper_Utilities::fnc_entry(44,"Sample_Connection::create_remote_query"); + + *query = new (&rc) Sample_Query(this, runtime_query, &rc); + if(rc!=0) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", + 10, "SC_CRQ"); + Wrapper_Utilities::trace_error(44,"Sample_Connection::create_remote_query", + 10, sizeof(rc), &rc); + } + + Wrapper_Utilities::fnc_exit(44,"Sample_Connection::create_remote_query", rc); + return rc; +} + +/************************************************************************** +* +* Function Name = Sample_Connection::create_remote_passthru() +* +* Function: create a Remote_Passthru object with all +* necessary state information for establishing passthru session. +* +* Input: Runtime_Operation* runtime_passthru: pointer to runtime passthru operator +* +* Output: Remote_Passthru** passthru: newly created Remote_Passthru object +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Connection:: + create_remote_passthru(Runtime_Operation* runtime_passthru, + Remote_Passthru** passthru) +{ + sqlint32 rc=0; + Wrapper_Utilities::fnc_entry(45,"Sample_Connection::create_remote_passthru"); + + *passthru = new (&rc) Sample_Passthru(this, runtime_passthru, &rc); + if(rc!=0) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", + 20, "SC_CRP"); + Wrapper_Utilities::trace_error(45,"Sample_Connection::create_remote_passthru", + 20, sizeof(rc), &rc); + } + + Wrapper_Utilities::fnc_exit(45,"Sample_Connection::create_remote_passthru", rc); + return rc; +} + +/************************************************************************** +* +* Function Name = Sample_Connection::commit() +* +* Function: commit a transaction. +* +* Input: +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Connection::commit() +{ + sqlint32 rc=0; + + Wrapper_Utilities::fnc_entry(46,"Sample_Connection::commit"); + // No transaction supported by this wrapper + + Wrapper_Utilities::fnc_exit(46,"Sample_Connection::commit", rc); + return rc; +} + +/************************************************************************** +* +* Function Name = Sample_Connection::rollback() +* +* Function: rollback a transaction. +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Connection::rollback() +{ + sqlint32 rc=0; + Wrapper_Utilities::fnc_entry(47,"Sample_Connection::rollback"); + + // No transaction supported by this wrapper + + Wrapper_Utilities::fnc_exit(47,"Sample_Connection::rollback", rc); + return rc; +} + diff --git a/wrappers/wrapper_sdk/sample_connection.h b/wrappers/wrapper_sdk/sample_connection.h new file mode 100755 index 0000000..11ccbb3 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_connection.h @@ -0,0 +1,67 @@ +/********************************************************************** +* +* Source File Name = sample_connction.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: sample_connection subclass +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_CONNECTION_H__ +#define __SAMPLE_CONNECTION_H__ + +#include "sqlxa.h" +#include "sqlqg_connection.h" + +////////////////////////////////////////////////////////////////////////////// +// sample_connection subclass +////////////////////////////////////////////////////////////////////////////// + +class Sample_Connection : public Remote_Connection { +public: + + // Constructor. + Sample_Connection(FencedServer* server, FencedRemote_User *user, sqlint32* rc); + + // Destructor. + virtual ~Sample_Connection(); + + // Connect and disconnect. + sqlint32 connect(); + sqlint32 disconnect(); + + // Remote operation suppport routines. These methods will create + // the appropriate remote operation subclass objects for use by the + // UDB runtime to control the execution of a remote operation such as + // a query or an insert/update/delete operation. + sqlint32 create_remote_query(Runtime_Operation* runtime_query, + Remote_Query** query); + sqlint32 create_remote_passthru(Runtime_Operation *runtime_passthru, + Remote_Passthru **passthru); + +protected: + + //////////////// + // Data. + //////////////// + + //////////////// + // Methods. + //////////////// + + // Transaction support routines. + + sqlint32 commit(); + sqlint32 rollback(); + +}; + + +#endif diff --git a/wrappers/wrapper_sdk/sample_error_reporting.h b/wrappers/wrapper_sdk/sample_error_reporting.h new file mode 100644 index 0000000..b24372b --- /dev/null +++ b/wrappers/wrapper_sdk/sample_error_reporting.h @@ -0,0 +1,39 @@ +/********************************************************************** +* +* Source File Name = sample_error_reporting.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining:General error functions +* +* Operating System = All +* +***********************************************************************/ +#ifndef _ERROR_REPORTING_ +#define _ERROR_REPORTING_ + +#include "sqlqg_utils.h" +#include "sqlcodes.h" +#include +#include + +inline sqlint32 sample_report_error_1822(sqlint32 rc, sqlint8* error_str, + sqlint32 trace_point, sqlint8* func_name) +{ + char trace_point_str[25]; + sprintf(trace_point_str, "%d", trace_point); + rc = Wrapper_Utilities::report_error((char* ) func_name, SQL_RC_E1822, 3, + strlen(trace_point_str), trace_point_str, + strlen("Sample Wrapper"), "Sample Wrapper", + strlen(error_str), error_str); + printf("Error in %s: %s, Trace point %d; rc= %d\n",func_name, error_str, trace_point, rc); + return rc; + +} + +#endif diff --git a/wrappers/wrapper_sdk/sample_fenced_nickname.C b/wrappers/wrapper_sdk/sample_fenced_nickname.C new file mode 100644 index 0000000..31ebf22 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_fenced_nickname.C @@ -0,0 +1,213 @@ +/********************************************************************** +* +* Source File Name = sample_fenced_nickname.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for fenced sample nickname class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_fenced_nickname.h" +#include "sample_fenced_server.h" +#include "sample_error_reporting.h" +#include "sample_utilities.h" +#include "sqlqg_utils.h" +#include "sqlcodes.h" +#include + +/************************************************************************** +* +* Function Name = FencedSample_Nickname::FencedSample_Nickname +* +* Function: FencedSample_Nickname class constructor +* +* Dependencies: +* +* Restrictions: +* +* Input: sqluint8* schema_name: Scehma name +* sqluint8* nickname_name: Nickname name +* FencedServer* nickname_server: server associated with nickname +* +* Output: (required) sqlint32 *rc - return code +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +FencedSample_Nickname::FencedSample_Nickname(sqluint8 * schema, + sqluint8* nickname_name, FencedServer* nickname_server, + sqlint32 *rc) + :Fenced_Generic_Nickname(schema, nickname_name, nickname_server, rc) +{ + Wrapper_Utilities::fnc_entry(80,"FencedSample_Nickname::FencedSample_Nickname"); + Wrapper_Utilities::fnc_exit(80,"FencedSample_Nickname::FencedSample_Nickname", *rc); +} + +/************************************************************************** +* +* Function Name = FencedSample_Nickname::~FencedSample_Nickname +* +* Function: FencedSample_Nickname class destructor +* +* Dependencies: +* +* Restrictions: +* +* Input: none +* +* Output: none +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +FencedSample_Nickname::~FencedSample_Nickname() +{ + Wrapper_Utilities::fnc_entry(81,"FencedSample_Nickname::~FencedSample_Nickname"); + Wrapper_Utilities::fnc_exit(81,"FencedSample_Nickname::~FencedSample_Nickname", 0); +} + +/************************************************************************** +* +* Function Name = FencedSample_Nickname::verify_my_register_nickname_info +* +* Function: Checks nickname information on a CREATE NICKNAME DDL statement. +* +* Restrictions: +* +* Input: Nickname_Info *nickname_info: catalog information about nickname. +* +* Output: Nickname_Info **delta_info: any additional information about nickname +* added as a result of the registration process. +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 +FencedSample_Nickname::verify_my_register_nickname_info( Nickname_Info* nickname_info, + Nickname_Info** delta_info) +{ + sqlint32 rc = 0; + Catalog_Option *catalog_option = NULL; + myboolean option_found = NO; + sqluint8 *nickname_name = NULL; + + Wrapper_Utilities::fnc_entry(82,"FencedSample_Nickname::verify_my_register_nickname_info"); + FencedSample_Server *srv = (FencedSample_Server *)get_server(); + sqluint8 *serverName = srv->get_name(); + + rc = Sample_Utilities::verify_column_type_and_options(this, nickname_info, serverName); + if (rc) + { + Wrapper_Utilities::trace_error(82,"FencedSample_Nickname::verify_my_register_nickname_info", + 10, sizeof(rc), &rc); + goto exit; + } + + + //---------------------------------------------------------------------- + // + // This nickname must be registered with the FILE_PATH option. + // + // ---------------------------------------------------------------------- + + // Walk through the list of options supplied in the DDL. If an option is found that + // and it is not known to this wrapper or to DB2, report an error. + + if (nickname_info != NULL) + { + catalog_option = nickname_info->get_first_option(); + } + + while (catalog_option != NULL) + { + const char *catalog_option_name = (const char*) catalog_option->get_name(); + + // Compare the user supplied option (in DDL) to our options + + if (strcmp(FILE_PATH_OPTION, catalog_option_name) == 0) + { + option_found = YES; + } + // The option found in the catalog (specified in ddl)might be DB2 (reserved) option + // if not, complain + else + if (!is_reserved_nickname_option((sqluint8 *)catalog_option_name)) + { + // This option is not valid - report an error + + // Get the nickname name + nickname_info->get_nickname(&nickname_name); + + rc = Wrapper_Utilities::report_error("FSN_VMR", SQL_RC_E1881, 3, + strlen(catalog_option_name), catalog_option_name, + strlen("Nickname"), "Nickname", + strlen((const char *) nickname_name), nickname_name); + + Wrapper_Utilities::fnc_data2(82,"FencedSample_Nickname::verify_my_register_nickname_info", 20, + strlen((char *)catalog_option_name), (char *)catalog_option_name, + strlen((const char *)nickname_name), (const char *)nickname_name); + + Wrapper_Utilities::trace_error(82,"FencedSample_Nickname::verify_my_register_nickname_info", + 20, sizeof(rc), &rc); + goto exit; + } + + catalog_option = nickname_info->get_next_option(catalog_option); + } + + // If we the FILE_PATH_OPTION is not found, go complaing. + + if (option_found == NO ) + { + + nickname_info->get_nickname(&nickname_name); + rc = Wrapper_Utilities::report_error("FSN_VMR", SQL_RC_E1883, 3, + strlen(FILE_PATH_OPTION), FILE_PATH_OPTION, + strlen("Nickname"), "Nickname", + strlen((const char*) nickname_name), (const char*) nickname_name); + + Wrapper_Utilities::fnc_data2(82,"FencedSample_Nickname::verify_my_register_nickname_info", 30, + strlen(FILE_PATH_OPTION), FILE_PATH_OPTION, + strlen((const char *)nickname_name), (const char *)nickname_name); + + Wrapper_Utilities::trace_error(82,"FencedSample_Nickname::verify_my_register_nickname_info", + 30, sizeof(rc), &rc); + goto exit; + } + + // For the time being, all generic nicknames are marked as read_only.. + if (*delta_info == NULL) + { + *delta_info = new (&rc) Nickname_Info; + if(rc!=0) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", + 40, "SW_CS"); + Wrapper_Utilities::trace_error(82,"FencedSample_Nickname::verify_my_register_nickname_info", + 40, sizeof(rc), &rc); + goto exit; + } + } + rc = (*delta_info)->add_option ((sqluint8*)"READ_ONLY", + strlen("READ_ONLY"), + (sqluint8*)"Y", 1); + +exit: + + Wrapper_Utilities::fnc_exit(82,"FencedSample_Nickname::verify_my_register_nickname_info", rc); + return rc; +} + diff --git a/wrappers/wrapper_sdk/sample_fenced_nickname.h b/wrappers/wrapper_sdk/sample_fenced_nickname.h new file mode 100644 index 0000000..5f6dda0 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_fenced_nickname.h @@ -0,0 +1,41 @@ +/********************************************************************** +* +* Source File Name = sample_fenced_nickname.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: sample fenced nickname class +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_FENCED_NICKNAME_H__ +#define __SAMPLE_FENCED_NICKNAME_H__ + +#include "sqlqg_catalog.h" +#include "sqlqg_fenced_generic_nickname.h" +#include "sample_typedefs.h" + +class FencedSample_Nickname : public Fenced_Generic_Nickname +{ +public: + + // Constructor. + FencedSample_Nickname(sqluint8 * schema, sqluint8* nickname_name, + FencedServer* nickname_server, sqlint32 *rc); + + // Destructor. + virtual ~FencedSample_Nickname(); + + // Verify options specified on CREATE nickname object. + virtual sqlint32 verify_my_register_nickname_info(Nickname_Info *nickname_info, + Nickname_Info **delta_info); +}; + + +#endif // __SAMPLE_FENCED_NICKNAME_H__ diff --git a/wrappers/wrapper_sdk/sample_fenced_server.C b/wrappers/wrapper_sdk/sample_fenced_server.C new file mode 100644 index 0000000..1c79d75 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_fenced_server.C @@ -0,0 +1,151 @@ +/********************************************************************** +* +* Source File Name = sample_fenced_server.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for fenced sample server class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_fenced_server.h" +#include "sample_fenced_nickname.h" +#include "sample_connection.h" +#include "sample_error_reporting.h" +#include "sqlqg_utils.h" +#include "sqlcodes.h" + + +/************************************************************************** +* +* Function Name = FencedSample_Server::FencedSample_Server +* +* Function: Sample Server Constructor +* +* Dependencies: +* +* Restrictions: +* +* Input: sqluint8 *server_name +* FencedWrapper *server_wrapper +* +* Output: sqlint32 *rc +* +* Normal Return = rc = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +FencedSample_Server::FencedSample_Server(sqluint8* server_name, + FencedWrapper* server_wrapper, sqlint32* rc) + : Fenced_Generic_Server(server_name, server_wrapper, rc) +{ + Wrapper_Utilities::fnc_entry(60,"FencedSample_Server::FencedSample_Server"); + Wrapper_Utilities::fnc_exit(60,"FencedSample_Server::FencedSample_Server", *rc); +} + +/************************************************************************** +* +* Function Name = FencedSample_Server::~FencedSample_Server +* +* Function: FencedSample_Server Destructor +* +* Dependencies: +* +* Restrictions: +* +* Input: N/A +* +* Output: N/A +* +* Normal Return = N/A +* +* Error Return = N/A +* +**************************************************************************/ +FencedSample_Server::~FencedSample_Server() +{ + Wrapper_Utilities::fnc_entry(61,"FencedSample_Server::~FencedSample_Server"); + Wrapper_Utilities::fnc_exit(61,"FencedSample_Server::~FencedSample_Server", 0); +} + +/************************************************************************** +* +* Function Name = FencedSample_Server::create_nickname() +* +* Function: Method to construct new nickname for a server. +* +* Input: sqluint8* name: name of nickname +* Server* server: server with which nickame is associated. +* +* Output: FencedNickname** nickname: newly created fenced nickname +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +Nickname* +FencedSample_Server::create_nickname(sqluint8 *schema_name, + sqluint8 * nickname_name, + sqlint32 *rc) +{ + FencedSample_Nickname *nickname=NULL; + Wrapper_Utilities::fnc_entry(62,"FencedSample_Server::create_nickname"); + + // Create an instance of the FencedSample_Nickname subclass + nickname = new (rc) FencedSample_Nickname(schema_name, nickname_name, this, + rc); + if(*rc!=0) + { + *rc = sample_report_error_1822(*rc, "Memory allocation error.", + 10, "FS_CN"); + Wrapper_Utilities::trace_error(62,"FencedSample_Server::create_nickname", + 10, sizeof(*rc), rc); + } + Wrapper_Utilities::fnc_exit(62,"FencedSample_Server::create_nickname", *rc); + return(nickname); +} + + +/************************************************************************** +* +* Function Name = Sample_Server::create_remote_connection() +* +* Function: Method to construct new connection for a server. +* +* Input: FencedRemote_User* user: user name accessing remote source +* +* Output: Remote_Connection** connection: newly created connection +* +* Normal Return = 0 +* +* Error Return =!0 +* +**************************************************************************/ +sqlint32 FencedSample_Server::create_remote_connection(FencedRemote_User* user, + Remote_Connection** connection) +{ + sqlint32 rc=0; + + Wrapper_Utilities::fnc_entry(63,"FencedSample_Server::create_remote_connection"); + // Create an instance of the Sample Remote_Connection subclass + *connection = new (&rc) Sample_Connection(this, user, &rc); + if(rc!=0) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", + 20, "FS_CRX"); + Wrapper_Utilities::trace_error(63,"FencedSample_Server::create_remote_connection", + 20, sizeof(rc), &rc); + } + + Wrapper_Utilities::fnc_exit(63,"FencedSample_Server::create_remote_connection", rc); + return rc; +} + diff --git a/wrappers/wrapper_sdk/sample_fenced_server.h b/wrappers/wrapper_sdk/sample_fenced_server.h new file mode 100644 index 0000000..26a3b77 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_fenced_server.h @@ -0,0 +1,44 @@ +/********************************************************************** +* +* Source File Name = sample_fenced_server.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: sample fenced server class +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_FENCED_SERVER_H__ +#define __SAMPLE_FENCED_SERVER_H__ + +#include "sample_typedefs.h" +#include "sqlqg_catalog.h" +#include "sqlqg_fenced_generic_server.h" + +class FencedSample_Server : public Fenced_Generic_Server { +public: + + // Constructors + FencedSample_Server(sqluint8* server_name, FencedWrapper* server_wrapper, + sqlint32* rc); + + virtual ~FencedSample_Server(); + + // Create instance of FencedSample_Nickname subclass. + virtual Nickname* create_nickname(sqluint8 *schema_name, sqluint8 *name, + sqlint32 *rc); + +protected: + + // Create instance of Sample_Connection subclass. + sqlint32 create_remote_connection(FencedRemote_User* user, + Remote_Connection** connection); +}; + +#endif // __SAMPLE_FENCED_SERVER_H__ diff --git a/wrappers/wrapper_sdk/sample_fenced_user.C b/wrappers/wrapper_sdk/sample_fenced_user.C new file mode 100644 index 0000000..1da6f5d --- /dev/null +++ b/wrappers/wrapper_sdk/sample_fenced_user.C @@ -0,0 +1,67 @@ +/********************************************************************** +* +* Source File Name = sample_fenced_user.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for fenced sample user class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_fenced_user.h" +#include "sqlqg_utils.h" + +/************************************************************************** +* +* Function Name = FencedSample_User::FencedSample_User +* +* Function: FencedSample_User class constructor +* +* Dependencies: +* +* Restrictions: +* +* Input: sqluint8* local_user_name: local authid of user. +* FencedServer* user_server: server associated with user +* +* Output: (required) sqlint32 *rc - return code +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +FencedSample_User::FencedSample_User(sqluint8* local_user_name, + FencedServer* user_server, sqlint32 *rc) + : Fenced_Generic_User(local_user_name, user_server, rc) +{ + Wrapper_Utilities::fnc_entry(70,"FencedSample_User::FencedSample_User"); + Wrapper_Utilities::fnc_exit(70,"FencedSample_User::FencedSample_User", *rc); +} + +/************************************************************************** +* +* Function Name = FencedSample_User::~FencedSample_User +* +* Function: FencedSample_User class destructor +* +* Dependencies: +* +* Restrictions: +* +* Input: none +* +* Output: none +* +**************************************************************************/ +FencedSample_User::~FencedSample_User() +{ + Wrapper_Utilities::fnc_entry(71,"FencedSample_User::~FencedSample_User"); + Wrapper_Utilities::fnc_exit(71,"FencedSample_User::~FencedSample_User", 0); +} diff --git a/wrappers/wrapper_sdk/sample_fenced_user.h b/wrappers/wrapper_sdk/sample_fenced_user.h new file mode 100644 index 0000000..bbdbcbd --- /dev/null +++ b/wrappers/wrapper_sdk/sample_fenced_user.h @@ -0,0 +1,35 @@ +/********************************************************************** +* +* Source File Name = sample_fenced_user.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: sample fenced user class +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_FENCED_USER_H__ +#define __SAMPLE_FENCED_USER_H__ + +#include "sqlqg_fenced_generic_user.h" + +class FencedSample_User : public Fenced_Generic_User +{ +public: + + // Constructor. + FencedSample_User(sqluint8* local_user_name, FencedServer* user_server, + sqlint32 *rc); + + // Destructor. + virtual ~FencedSample_User(); +}; + + +#endif // __SAMPLE_FENCED_USER_H__ diff --git a/wrappers/wrapper_sdk/sample_fenced_wrapper.C b/wrappers/wrapper_sdk/sample_fenced_wrapper.C new file mode 100644 index 0000000..ab31ba8 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_fenced_wrapper.C @@ -0,0 +1,162 @@ +/********************************************************************** +* +* Source File Name = sample_fenced_wrapper.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for fenced sample wrapper class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_fenced_wrapper.h" +#include "sample_fenced_server.h" +#include "sample_error_reporting.h" + +#include "sqlqg_utils.h" +#include "sqlcodes.h" +#include +#include + +/************************************************************************** +* +* Function Name = FencedSample_Wrapper::FencedSample_Wrapper() +* +* Function: Constructor for FencedSample_Wrapper class +* +* Dependencies: +* +* Restrictions: +* +* Input: (required) sqlint32* rc: return code to indicate errors. +* +* Output: N/A +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +FencedSample_Wrapper::FencedSample_Wrapper(sqlint32 *rc ) + : Fenced_Generic_Wrapper(rc, SAMPLE_WRAPPER_VERSION) +{ + Wrapper_Utilities::fnc_entry(50,"FencedSample_Wrapper::FencedSample_Wrapper"); + Wrapper_Utilities::fnc_exit(50,"FencedSample_Wrapper::FencedSample_Wrapper", *rc); +} + +/************************************************************************** +* +* Function Name = FencedSample_Wrapper::~FencedSample_Wrapper() +* +* Function: Destructor for FencedSample_Wrapper class +* +* Dependencies: +* +* Restrictions: +* +* Input: none +* +* Output: N/A +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +FencedSample_Wrapper::~FencedSample_Wrapper() +{ + Wrapper_Utilities::fnc_entry(51,"FencedSample_Wrapper::~FencedSample_Wrapper"); + Wrapper_Utilities::fnc_exit(51,"FencedSample_Wrapper::~FencedSample_Wrapper", 0); +} + +/************************************************************************** +* +* Function Name = FencedSample_Wrapper::create_server() +* +* Function: routine to create a new instance of FencedSample_Server in the fenced side +* +* Dependencies: +* +* Restrictions: +* +* Input: (required) sqluint8* server_name: name of server for which instance +* should be instantiated. +* +* Output: (optional) FencedServer* server: newly instantiated FencedSample_Server instance. +* +* Normal Return = 0 +* +* Error Return = != 0 +* +**************************************************************************/ + +Server* FencedSample_Wrapper::create_server(sqluint8* server_name, sqlint32 *rc) +{ + FencedSample_Server *server=NULL; + + Wrapper_Utilities::fnc_entry(52,"FencedSample_Wrapper::create_server"); + server = new(rc) FencedSample_Server(server_name, this, rc); + if(*rc!=0) + { + *rc = sample_report_error_1822(*rc, "Memory allocation error.", + 10, "SF_CS"); + Wrapper_Utilities::trace_error(52,"FencedSample_Wrapper::create_server", + 10, sizeof(*rc), rc); + } + + Wrapper_Utilities::fnc_exit(52,"FencedSample_Wrapper::create_server", *rc); + return server; +} + +/************************************************************************** +* +* Function Name = FencedWrapper_Hook() +* +* Function: Hook function to get a handle on FencedSample_Wrapper instance. +* +* Dependencies: +* +* Restrictions: +* +* Input: none +* +* Output: N/A +* +* Normal Return = FencdedWrapper*: a pointer to instantiated Wrapper instance +* +* Error Return = rc != 0 +* +**************************************************************************/ +extern "C" FencedWrapper* FencedWrapper_Hook() +{ + FencedWrapper* wrapper=NULL; + sqlint32 rc=0; + + Wrapper_Utilities::fnc_entry(53,"FencedWrapper_Hook"); + wrapper = new(&rc) FencedSample_Wrapper(&rc); + + if(rc || wrapper == NULL) + { + rc = Wrapper_Utilities::report_error("FW_Hook", + SQL_RC_E1822, 3, strlen("-1"), "-1", + strlen(SQLQG_WRAPPER_OPTION), SQLQG_WRAPPER_OPTION, + strlen(NULL_WRAPPER), NULL_WRAPPER); + + Wrapper_Utilities::trace_error(53,"FencedWrapper_Hook", + 20, sizeof(rc), &rc); + + if (wrapper) + { + delete wrapper; + wrapper = NULL; + } + } + + Wrapper_Utilities::fnc_exit(53,"FencedWrapper_Hook", rc); + return wrapper; +} diff --git a/wrappers/wrapper_sdk/sample_fenced_wrapper.h b/wrappers/wrapper_sdk/sample_fenced_wrapper.h new file mode 100644 index 0000000..cde08be --- /dev/null +++ b/wrappers/wrapper_sdk/sample_fenced_wrapper.h @@ -0,0 +1,44 @@ +/********************************************************************** +* +* Source File Name = sample_fenced_wrapper.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: sample fenced wrapper class +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_FENCED_WRAPPER_H__ +#define __SAMPLE_FENCED_WRAPPER_H__ + +#include "sample_typedefs.h" +#include "sqlqg_catalog.h" +#include "sqlqg_fenced_generic_wrapper.h" + +class Server; + +class FencedSample_Wrapper : public Fenced_Generic_Wrapper +{ +public: + + // Constructor. + FencedSample_Wrapper(sqlint32 *rc); + + // Destructor. + virtual ~FencedSample_Wrapper(); + +protected: + + // create_server() allows a wrapper subclass instance to + // create an instance of its own remote server subclass. + + virtual Server* create_server(sqluint8* server_name, sqlint32 *rc); +}; + +#endif // __SAMPLE_FENCED_WRAPPER_H__ diff --git a/wrappers/wrapper_sdk/sample_nickname.C b/wrappers/wrapper_sdk/sample_nickname.C new file mode 100755 index 0000000..ce07f50 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_nickname.C @@ -0,0 +1,345 @@ +/********************************************************************** +* +* Source File Name = sample_nickname.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for unfenced sample nickname class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_nickname.h" +#include "sample_server.h" +#include "sample_utilities.h" +#include "sqlcli.h" +#include "sqlqg_catalog.h" +#include "sqlqg_utils.h" +#include "sqlcodes.h" + +/************************************************************************** +* +* Function Name = Sample_Nickname::Sample_Nickname +* +* Function: Sample_Nickname base class constructor +* +* Dependencies: +* +* Restrictions: +* +* Input: sqluint8* schema_name: Scehma name +* sqluint8* nickname_name: Nickname name +* UnfencedServer* nickname_server: server associated with nickname +* +* Output: (required) sqlint32 *rc - return code +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +Sample_Nickname::Sample_Nickname(sqluint8 *schema_name, sqluint8 *nickname_name, + UnfencedServer* nickname_server, sqlint32 *rc) + :Unfenced_Generic_Nickname(schema_name, nickname_name, + (Unfenced_Generic_Server*)nickname_server, rc), + mFilePath(NULL), mNickname_Info (NULL) +{ + Wrapper_Utilities::fnc_entry(30,"Sample_Nickname::Sample_Nickname"); + Wrapper_Utilities::fnc_exit(30,"Sample_Nickname::Sample_Nickname", *rc); +} + +/************************************************************************** +* +* Function Name = Sample_Nickname::~Sample_Nickname +* +* Function: Sample_Nickname base class destructor +* +* Dependencies: +* +* Restrictions: +* +* Input: none +* +* Output: none +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +Sample_Nickname::~Sample_Nickname() +{ + Wrapper_Utilities::fnc_entry(31,"Sample_Nickname::~Sample_Nickname"); + if (mFilePath != NULL) + { + Wrapper_Utilities::deallocate(mFilePath); + mFilePath = NULL; + } + + delete mNickname_Info; + mNickname_Info = NULL; + Wrapper_Utilities::fnc_exit(31,"Sample_Nickname::~Sample_Nickname", 0); +} + +/************************************************************************** +* +* Function Name = Sample_Nickname::initialize_my_nickame() +* +* Function: This method performs nickname specific initialization. +* +* Restrictions: +* +* Input: Nickname_Info *nickname_info: catalog information about nickname. +* +* Output: none. +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Nickname::initialize_my_nickname(Nickname_Info* nickname_info) +{ + sqlint32 rc=0; + + Wrapper_Utilities::fnc_entry(32,"Sample_Nickname::initialize_my_nickname"); + + rc = Sample_Utilities::save_option_value(nickname_info, FILE_PATH_OPTION, &mFilePath); + if (rc) + { + Wrapper_Utilities::trace_error(32,"Sample_Nickname::initialize_my_nickname", + 10, sizeof(rc), &rc); + goto exit; + } + + if (mNickname_Info == NULL) + { + rc = nickname_info->copy(&mNickname_Info); + if (rc) + { + Wrapper_Utilities::trace_error(32,"Sample_Nickname::initialize_my_nickname", + 20, sizeof(rc), &rc); + goto exit; + } + } + +exit: + Wrapper_Utilities::fnc_exit(32,"Sample_Nickname::initialize_my_nickname", rc); + return rc; +} + +/************************************************************************** +* +* Function Name = Sample_Nickname::verify_my_register_nickname_info +* +* Function: NONE, this is done on the fenced side +* +* Restrictions: +* +* Input: Nickname_Info *nickname_info: catalog information about nickname. +* +* Output: Nickname_Info **delta_info: any additional information about nickname +* added as a result of the registration process. +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Nickname::verify_my_register_nickname_info(Nickname_Info* nickname_info, + Nickname_Info** delta_info) +{ + sqlint32 rc=0; + + Wrapper_Utilities::fnc_entry(33,"Sample_Nickname::verify_my_register_nickname_info"); + + // We want an implementation that does *nothing*, because everything + // should have been checked on the fenced side. We don't want the + // default implementation of this method, because it will will get + // upset about any options appearing. + + Wrapper_Utilities::fnc_exit(33,"Sample_Nickname::verify_my_register_nickname_info", rc); + return rc; +} + +/************************************************************************** +* +* Function Name = Sample_Nickname::verify_my_alter_nickname_info +* +* Function: Checks nickname information on ALTER DDL statement for validity. +* +* Restrictions: +* +* Input: Nickname_Info *nickname_info: catalog information about nickname. +* +* Output: Nickname_Info **nickname_info: any additional information about nickname +* added as a result of the registration process. +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Nickname::verify_my_alter_nickname_info(Nickname_Info* nickname_info, + Nickname_Info** delta_info) +{ + sqlint32 rc = 0; + Column_Info *columnInfo = NULL; + Catalog_Option *catalog_option = NULL; + sqluint8 *nickname_name = NULL; + Sample_Server *srv = NULL; + sqluint8 *serverName = NULL; + + Wrapper_Utilities::fnc_entry(34,"Sample_Nickname::verify_my_alter_nickname_info"); + + columnInfo = nickname_info->get_first_column(); + + if (columnInfo != NULL) + { + // Some columns are being altered.. Check for unsupported data types. + + srv = (Sample_Server *) get_server(); + serverName = srv->get_name(); + rc = Sample_Utilities::verify_column_type_and_options(this, nickname_info, serverName); + if (rc) + { + Wrapper_Utilities::trace_error(34,"Sample_Nickname::verify_my_alter_nickname_info", + 30, sizeof(rc), &rc); + goto exit; + } + } + + //---------------------------------------------------------------------- + // + // This nickname must be registered with the FILE_PATH option. + // + // ---------------------------------------------------------------------- + + + // Walk through the list of options supplied in the DDL to : + // 1. Check to see if the user is not trying to drop the FILE_PATH option + // 2. Check to see if the user is not trying to alter an unknown option + + if (nickname_info != NULL) + { + catalog_option = nickname_info->get_first_option(); + } + + while (catalog_option != NULL) + { + const char *catalog_option_name = (const char*) catalog_option->get_name(); + + // Compare the user supplied option (in DDL) to our options + + if (strcmp(FILE_PATH_OPTION, catalog_option_name) == 0) + { + // Get the action on this option to make sure that the + // user is not trying to drop this required option + + Catalog_Option::Action action = catalog_option->get_action(); + if (action == Catalog_Option::sqlqg_Drop) + { + // A required option cannot be dropped + + nickname_name = this->get_local_name(); + rc = Wrapper_Utilities::report_error("SN_VMA", SQL_RC_E1883, 3, + strlen(catalog_option_name), catalog_option_name, + strlen("Nickname"), "Nickname", + strlen((const char*) nickname_name), (const char*) nickname_name); + + Wrapper_Utilities::fnc_data2(34,"Sample_Nickname::verify_my_alter_nickname_info", 40, + strlen((char *)catalog_option_name), (char *)catalog_option_name, + strlen((const char *)nickname_name), (const char *)nickname_name); + + Wrapper_Utilities::trace_error(34,"Sample_Nickname::verify_my_alter_nickname_info", + 40, sizeof(rc), &rc); + goto exit; + } + + } + + // The option found in the catalog (specified in ddl) might be DB2 (reserved) option + // if not, complain + + else + if (!is_reserved_nickname_option((sqluint8 *)catalog_option_name)) + { + // This option is not valid - report an error + + nickname_name = this->get_local_name(); + rc = Wrapper_Utilities::report_error("SN_VMA", SQL_RC_E1881, 3, + strlen(catalog_option_name), catalog_option_name, + strlen("Nickname"), "Nickname", + strlen((const char *) nickname_name), nickname_name); + + Wrapper_Utilities::fnc_data2(34,"Sample_Nickname::verify_my_alter_nickname_info", 50, + strlen((char *)catalog_option_name), (char *)catalog_option_name, + strlen((const char *)nickname_name), (const char *)nickname_name); + + Wrapper_Utilities::trace_error(34,"Sample_Nickname::verify_my_alter_nickname_info", + 50, sizeof(rc), &rc); + goto exit; + } + + catalog_option = nickname_info->get_next_option(catalog_option); + } + +exit: + + Wrapper_Utilities::fnc_exit(34,"Sample_Nickname::verify_my_alter_nickname_info", rc); + return rc; +} + +/************************************************************************** +* +* Function Name = Sample_Nickname::get_file_path() +* +* Function: Return the full path to the file. +* +* Input: +* +* Output: file_path - pointer to the full path of the file. +* +* Normal Return = 0 +* +* Error Return = !0 +* +**************************************************************************/ +sqlint32 Sample_Nickname::get_file_path(sqluint8 **file_path) const +{ + sqlint32 rc = 0; + + *file_path = mFilePath; + + return rc; +} + + +/************************************************************************** +* +* Function Name = Sample_Nickname::get_nickname_info() +* +* Function: Returns a copy of the Nickname_Info object +* +* Input: +* +* Output: nickname_info - pointer to a Nickname_Info object copy +* +* Normal Return = 0 +* +* Error Return = !0 +* +**************************************************************************/ +sqlint32 Sample_Nickname::get_nickname_info(Nickname_Info **nickname_info) const +{ + sqlint32 rc = 0; + + *nickname_info = mNickname_Info; + + return rc; +} diff --git a/wrappers/wrapper_sdk/sample_nickname.h b/wrappers/wrapper_sdk/sample_nickname.h new file mode 100755 index 0000000..8f4bd34 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_nickname.h @@ -0,0 +1,71 @@ +/********************************************************************** +* +* Source File Name = sample_nickname.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: unfenced sample nickname subclass +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_NICKNAME_H__ +#define __SAMPLE_NICKNAME_H__ + +#include "sqlqg_unfenced_generic_nickname.h" + +////////////////////////////////////////////////////////////////////////////// +// Nickname base class (used to represent remote tables) +////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////// +// Base class. +//////////////////////////////// +class Sample_Nickname : public Unfenced_Generic_Nickname +{ +public: + // Constructor. + Sample_Nickname(sqluint8 *schema_name, sqluint8* nickname_name, + UnfencedServer* nickname_server, sqlint32 *rc); + + // Destructor. + virtual ~Sample_Nickname(); + + // Initialization hook. Invoked after creating a nickname object + // to intialize state from catalog information. + virtual sqlint32 initialize_my_nickname(Nickname_Info* catalog_info); + + // Verify options specified on CREATE nickname object. + virtual sqlint32 verify_my_register_nickname_info(Nickname_Info* nick_info, + Nickname_Info** delta_info); + // Verify options specified on ALTER nickname object. + virtual sqlint32 verify_my_alter_nickname_info(Nickname_Info *nickname_info, + Nickname_Info **delta_info); + + // Returns a pointer to the file path + sqlint32 get_file_path(sqluint8 **file_path) const; + + // Returns a pointer to the Nickname_Info object + sqlint32 get_nickname_info(Nickname_Info **nickname_info) const; + + +protected: + + //////////////// + // Data. + //////////////// + + // Full path to the data file + sqluint8 *mFilePath; + + // Copy of Nickname_Info object + Nickname_Info *mNickname_Info; + +}; + +#endif diff --git a/wrappers/wrapper_sdk/sample_operation.C b/wrappers/wrapper_sdk/sample_operation.C new file mode 100755 index 0000000..c80da19 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_operation.C @@ -0,0 +1,2616 @@ +/********************************************************************** +* +* Source File Name = sample_operation.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for sample operation class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_operation.h" +#include "sample_portability.h" +#include "sample_utilities.h" +#include "sample_error_reporting.h" +#include "sample_fenced_server.h" +#include + +/**************************************************************************** +* Function Name = Sample_Query::Sample_Query +* +* Function: Constructor for new Sample query +* +* Input: active_connection: connection to server +* runtime_query: UDB runtime operator info for query +* +* Output: Remote_Query != NULL : Success +* Remote_Query == NULL : failure +* +*****************************************************************************/ +Sample_Query::Sample_Query(Remote_Connection *active_connection, + Runtime_Operation *runtime_query, sqlint32 *rc) + :Remote_Query(active_connection, runtime_query, rc), + mColumnVector (NULL), mData (NULL), mFile (NULL), mNumColumns (0), + mExecDesc(NULL), mFinished (NO), mTokens (NULL) +{ + char *func_name = "SQSQC"; + + Wrapper_Utilities::fnc_entry(100,"Sample_Query::Sample_Query"); + + mPredOperator = ALL_ROWS; + mKeyVector=-1; + mResult = NO_MATCH; + mSearchTerm = NULL; + mFilePath = NULL; + mBindIndex = -1; + memset(mSearchTermBind, '\0', MAX_VARCHAR_LENGTH); + + // Bail out if an error occure in the base class constructor + if (*rc) goto exit; + + *rc = Wrapper_Utilities::allocate(MAX_LINE_SIZE, (void**) &mBuffer); + if (*rc) + { + *rc = sample_report_error_1822(*rc, "Memory allocation error.", 10, func_name); + Wrapper_Utilities::trace_error(100,"Sample_Query::Sample_Query", + 10, sizeof(*rc), rc); + goto exit; + } + +exit: + Wrapper_Utilities::fnc_exit(100,"Sample_Query::Sample_Query", *rc); +} + +/**************************************************************************** +* Function Name = Sample_Query::~Sample_Query +* +* Function: Destructor for Sample_Query class +* +* Input: None +* +* Output: None +*****************************************************************************/ +Sample_Query::~Sample_Query() +{ + + sqlint32 i = 0 ; + + Wrapper_Utilities::fnc_entry(101,"Sample_Query::~Sample_Query"); + // Close the data file + + if (mFile != NULL) + { + CLOSE_FILE(mFile); + mFile = NULL; + } + + // Release allocated memory back to the system. + if (mTokens != NULL) + { + // If any tokens exist release the memory back to DB2 + for (i = 0; i < mNumColumns; i++) + { + if (mTokens[i] != NULL) + { + Wrapper_Utilities::deallocate(mTokens[i]); + mTokens[i] = NULL; + } + } + Wrapper_Utilities::deallocate(mTokens); + mTokens = NULL; + } + + if (mBuffer != NULL) + { + Wrapper_Utilities::deallocate(mBuffer); + mBuffer = NULL; + } + + for ( i = 0; i < mNumColumns; i++) + { + if (mData[i].data != NULL) + { + Wrapper_Utilities::deallocate(mData[i].data); + mData[i].data = NULL; + } + } + + if (mExecDesc != NULL) + { + Wrapper_Utilities::deallocate(mExecDesc); + mExecDesc = NULL; + } + + Wrapper_Utilities::fnc_exit(101,"Sample_Query::~Sample_Query", 0); +} + +/**************************************************************************** +* Function Name = Sample_Query::open() +* +* Function: Open a query to be executed. +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::open() +{ + Runtime_Data_List *queryInput = NULL; + Runtime_Data *rt_data = NULL; + sqlint32 rc = 0; + sqlint32 trace_error = 0; + struct stat statBuffer; + int i = 0; + char *ptr = NULL; + char *exec_desc = NULL; + Sample_Exec_Descriptor *fedsP = NULL; + char errorMessage[80]; + char errnoBuffer[20]; + FencedSample_Server *srv = (FencedSample_Server *)get_server(); + sqluint8 *serverName = srv->get_name(); + + Wrapper_Utilities::fnc_entry(102,"Sample_Query::open"); + + memset(errorMessage, '\0', sizeof(errorMessage)); + memset(errnoBuffer, '\0', sizeof(errnoBuffer)); + + //unpack from the execution descriptor + get_exec_desc((void **)&exec_desc, &i); + + //Get a copy of the execution descriptor locally + rc = Wrapper_Utilities::allocate(i ,(void**)&mExecDesc); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 10, "SQOpen"); + trace_error = 10; + goto error; + } + + memcpy(mExecDesc, exec_desc, i); + fedsP = (Sample_Exec_Descriptor *)mExecDesc; + + // sanity check! + if (fedsP == NULL) + { + sample_report_error_1822(rc,"Internal error: Cannot get the plan.", 20, "SQOpen"); + trace_error = 20; + goto error; + } + + //fixed size items + mNumColumns = fedsP->mNumColumns; + //Can only handle column='cst' or'cst'=column or column = unbound or unbound = column predicates + mPredOperator = fedsP->mPredOperator; + mKeyVector = fedsP->mKeyVector; + + //variable size items + mColumnVector = (int *) ((char*)mExecDesc + sizeof(Sample_Exec_Descriptor)); + mData = (columnData *) ((char *)mColumnVector + (sizeof(int) * (mNumColumns +1))); + mFilePath = (char *)mData + (sizeof(columnData) * mNumColumns); + mBindIndex = fedsP->mBindIndex; + + if (mFilePath == NULL) + { + rc = Wrapper_Utilities::report_error("SQOpen", + SQL_RC_E901, 1,strlen(NULL_PATH), NULL_PATH); + trace_error = 30; + goto error; + } + + //get the constant + if(mPredOperator == SQL_EQ) + { + //constant: extract the value from the execution descriptor + if(mBindIndex == -1) + { + mSearchTerm = mFilePath + strlen(mFilePath) +1; + } + //parameter (bind var or host var): get the value from the input + else + { + queryInput = get_input_data(); + rt_data = queryInput->get_ith_value(fedsP->mBindIndex); + + if( !rt_data->is_data_null() ) + { + sqlint32 mSearchTermLength = 0; + mSearchTerm = mSearchTermBind; + + rc = Sample_Utilities::convert_data( + rt_data->get_data_type (), + rt_data->get_data (), + rt_data->get_actual_length (), + rt_data->get_precision (), + rt_data->get_scale (), + mSearchTerm, + &mSearchTermLength); + } + if( rc ) + { + trace_error = 35; + goto error; + } + } + } + + // Check to see if we can read the file, if not return an error to DB2 + + if (NOT_READABLE_FILE(mFilePath)) + { + BUILD_ERROR_MESSAGE(errorMessage); + rc = Wrapper_Utilities::report_error("SQOpen", + SQL_RC_E1822, 3, strlen(errorMessage), errorMessage, + strlen((const char *)serverName), (const char *)serverName, + strlen(ACCESS_ERROR),ACCESS_ERROR); + + Wrapper_Utilities::fnc_data(102,"Sample_Query::open", 40, + strlen((const char *)serverName), (const char *)serverName); + trace_error = 40; + goto error; + } + + // lstat the file, check to see if it is a non standard type file + //(a directory, a pipe/fifo, or a socket), if so return an error to DB2 + if (CHECK_FILE_TYPE(mFilePath) < 0) + { + BUILD_ERROR_MESSAGE(errnoBuffer); + strcpy(errorMessage, LSTAT_ERROR); + strcat(errorMessage, ". "); + strcat(errorMessage,errnoBuffer); + rc = Wrapper_Utilities:: report_error("SQOpen", + SQL_RC_E901, 1, strlen(errorMessage), errorMessage); + trace_error = 50; + goto error; + } + + if (NON_STANDARD_FILE) + { + rc = Wrapper_Utilities::report_error("SQOpen", + SQL_RC_E1822, 3, strlen(DATA_ERROR), DATA_ERROR, + strlen((const char *)serverName), (const char *)serverName, + strlen(NOT_FILE_ERROR), NOT_FILE_ERROR); + + Wrapper_Utilities::fnc_data(102,"Sample_Query::open", 60, + strlen((const char *)serverName), (const char *)serverName); + trace_error = 60; + goto error; + } + + // Open the data file for reading only. If we can't open the file return an + // error to DB2. + OPEN_FILE(mFilePath,mFile); + + if (OPEN_FAILED(mFile)) + { + BUILD_ERROR_MESSAGE(errorMessage); + rc = Wrapper_Utilities::report_error("SQOpen", + SQL_RC_E1822, 3, strlen(errorMessage), errorMessage, + strlen((const char *)serverName), (const char *)serverName, + strlen(OPEN_ERROR), OPEN_ERROR); + + Wrapper_Utilities::fnc_data(102,"Sample_Query::open", 70, + strlen((const char *)serverName), (const char *)serverName); + trace_error = 70; + goto error; + } + + // Allocate space for the tokens array. We initially use a temporary pointer + // for the allocation because passing allocate a pure ** rather than the address + // of a pointer triggers an abend in the allocate method. + + rc = Wrapper_Utilities::allocate((sizeof(char *) * mNumColumns),(void**)&ptr); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 80, "SQOpen"); + trace_error = 80; + goto error; + } + + mTokens = (char **)ptr; + + // Build the columnData array. This array will hold information describing each + // column in the data source along with a void pointer to the any fetched data. + rc = build_data_area(mNumColumns, mData); + if(rc) + { + trace_error = 90; + goto error; + } + +exit: + Wrapper_Utilities::fnc_exit(102,"Sample_Query::open", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(102,"Sample_Query::open", + trace_error, sizeof(rc), &rc); + + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::reopen() +* +* Function: Re-opens a query to be executed again. +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::reopen(sqlint16 action) +{ + // This function is called to re-open a query that was previously executed. It gets called + // when the query has a bind var (host var) in the query. Every time the bind var changes, + // this function is called. + + sqlint32 rc = 0; + Runtime_Data_List *queryInput = NULL; + Runtime_Data *rt_data = NULL; + mSearchTerm = NULL; + memset(mSearchTermBind, '\0', MAX_VARCHAR_LENGTH); + mResult = NO_MATCH; + mFinished = NO; + sqlint32 trace_error= 0; + char errorMessage[80]; + memset(errorMessage, '\0', sizeof(errorMessage)); + FencedSample_Server *srv = (FencedSample_Server *)get_server(); + sqluint8 *serverName = srv->get_name(); + + Wrapper_Utilities::fnc_entry(103,"Sample_Query::reopen"); + + + OPEN_FILE(mFilePath,mFile); + + if (OPEN_FAILED(mFile)) + { + BUILD_ERROR_MESSAGE(errorMessage); + rc = Wrapper_Utilities::report_error("SQReOpen", + SQL_RC_E1822, 3, strlen(errorMessage), errorMessage, + strlen((const char *)serverName), (const char *)serverName, + strlen(OPEN_ERROR), OPEN_ERROR); + + Wrapper_Utilities::fnc_data(103,"Sample_Query::reopen", 10, + strlen((const char *)serverName), (const char *)serverName); + trace_error = 10; + goto error; + } + + if ( mBindIndex >= 0 ) + { + queryInput = get_input_data(); + rt_data = queryInput->get_ith_value(mBindIndex); + + if( ! rt_data->is_data_null() ) + { + sqlint32 mSearchTermLength = 0; + mSearchTerm = mSearchTermBind; + rc = Sample_Utilities::convert_data( + rt_data->get_data_type (), + rt_data->get_data (), + rt_data->get_actual_length (), + rt_data->get_precision (), + rt_data->get_scale (), + mSearchTerm, + &mSearchTermLength + ); + } + if( rc ) + { + trace_error = 20; + goto error; + } + } + +exit: + Wrapper_Utilities::fnc_exit(103,"Sample_Query::reopen", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(103,"Sample_Query::reopen", + trace_error, sizeof(rc), &rc); + + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::fetch() +* +* Function: Retrieves the next row. +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::fetch() +{ + sqlint32 rc=0; + sqlint32 trace_error = 0; + Runtime_Data_List *queryOutput = NULL; + Runtime_Data *rt_data = NULL; + sqlint32 runTimeDataCount = 0 , i = 0; + + Wrapper_Utilities::fnc_entry(104,"Sample_Query::fetch"); + rc = table_scan(); + if (rc) + { + trace_error = 100; + goto error; + } + + // If a no eof and no error is encountered when reading the data, + // then get the runtime data object from runtime data list for each requested column. + // Set the runtime data with the data from the selected column array indexed by the + // integer stored in the column vector array. + // If eof is encounted, call report_eof to signal DB2 that we are done returning data. + + if (mFinished == NO) + { + queryOutput = get_output_data(); + if (!queryOutput) + { + rc = sample_report_error_1822(rc, "Internal error: Cannot get output data.", + 110, "SQFetch"); // Sanity check + trace_error = 110; + goto error; + } + + + i = 0; + runTimeDataCount = 0; + + while(mColumnVector[i] != -1) + { + rt_data = queryOutput->get_ith_value(runTimeDataCount); + if (!rt_data) + { + rc = sample_report_error_1822(rc, "Internal error: Cannot get output data.", + 100+i, "SQFetch"); // Sanity check + trace_error = 120; + goto error; + } + + if (mData[mColumnVector[i]].data != NULL) + { + if (mData[mColumnVector[i]].type == SQL_VARCHAR) + { + rt_data->set_data((unsigned char *)mData[mColumnVector[i]].data, + strlen((const char *)mData[mColumnVector[i]].data)); + } + else + if (mData[mColumnVector[i]].type == SQL_DECIMAL) + { + rc = format_packed_decimal(mColumnVector[i], + rt_data->get_precision(), + rt_data->get_scale()); + rt_data->set_data((unsigned char *)mData[mColumnVector[i]].data, + mData[mColumnVector[i]].len); + } + else + { + // all other data types + rt_data->set_data((unsigned char *)mData[mColumnVector[i]].data, + mData[mColumnVector[i]].len); + } + } + else + { + rt_data->set_data_null(); + } + + i++; + runTimeDataCount++; + } + } + else + { + rc = report_eof(); + } + +exit: + Wrapper_Utilities::fnc_exit(104,"Sample_Query::fetch", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(104,"Sample_Query::fetch", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::close() +* +* Function: closes a query. +* +* Function: +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::close(sqlint16 status) +{ + sqlint32 rc=0; + Wrapper_Utilities::fnc_entry(105,"Sample_Query::close"); + + Wrapper_Utilities::fnc_exit(105,"Sample_Query::close", rc); + return rc; +} + +/**************************************************************************** +* Function Name = Sample_Passthru::Sample_Passthru +* +* Function: Constructor for new passthru +* +* Input: active_connection: connection to the remote server +* runtime_passthru: UDB runtime operator info for passthru +* +* Output: Remote_Passthru != NULL : Success +* Remote_Passthru == NULL : failure +*****************************************************************************/ +Sample_Passthru::Sample_Passthru(Remote_Connection *active_connection, + Runtime_Operation *runtime_passthru, + sqlint32 *rc) + :Remote_Passthru(active_connection, runtime_passthru, rc) +{ + + *rc = Wrapper_Utilities::report_error("SP_SPC", SQL_RC_E30090,1,2,"21"); + +} + + +/**************************************************************************** +* Function Name = Sample_Passthru::~Sample_Passthru +* +* Function: Destructor for Sample_Passthru class +* +* Input: None +* +* Output: None +*****************************************************************************/ +Sample_Passthru::~Sample_Passthru() +{ +} + +/**************************************************************************** +* Function Name = Sample_Passthru::prepare(Runtime_Data_Desc_List*) +* +* Function: Prepares a Sample Passthru object. +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Passthru::prepare(Runtime_Data_Desc_List*) +{ + sqlint32 rc=0; + + rc = Wrapper_Utilities::report_error("SPPrep", SQL_RC_E30090,1,2,"21"); + return rc; +} + +/**************************************************************************** +* Function Name = Sample_Passthru::describe() +* +* Function: Describes the results of executing a Sample Passthru object. +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Passthru::describe(Runtime_Data_Desc_List *data_description_list) +{ + sqlint32 rc=0; + + rc = Wrapper_Utilities::report_error("SPDesc", SQL_RC_E30090,1,2,"21"); + return rc; +} + +/**************************************************************************** +* Function Name = Sample_Passthru::execute() +* +* Function: Executes a Sample Passthru object. +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Passthru::execute() +{ + sqlint32 rc=0; + + rc = Wrapper_Utilities::report_error("SPExec", SQL_RC_E30090,1,2,"21"); + return rc; +} + +/**************************************************************************** +* Function Name = Sample_Passthru::open() +* +* Function: Opens a Sample Passthru object. +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Passthru::open() +{ + sqlint32 rc=0; + + rc = Wrapper_Utilities::report_error("SPOpen", SQL_RC_E30090,1,2,"21"); + return rc; +} + +/**************************************************************************** +* Function Name = Sample_Passthru::fetch() +* +* Function: Fetchs a row from a Sample Passthru object. +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Passthru::fetch() +{ + sqlint32 rc=0; + + rc = Wrapper_Utilities::report_error("SPFetch", SQL_RC_E30090,1,2,"21"); + return rc; +} + +/**************************************************************************** +* Function Name = Sample_Passthru::close() +* +* Function: Closes a Sample Passthru object. +* +* Input: (input , required) none +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Passthru::close() +{ + sqlint32 rc=0; + + rc = Wrapper_Utilities::report_error("SPClose", SQL_RC_E30090,1,2,"21"); + return rc; +} + +/**************************************************************************** +* Function Name = Sample_Query::build_data_area() +* +* Function: Allocates the buffers for each column +* +* +* +* Input: +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::build_data_area(int mNumColumns, columnData *mData) +{ + sqlint32 rc = 0; + sqlint32 i = 0; + sqlint32 bsize = 0; + FencedSample_Server *srv = NULL; + sqluint8 *serverName = NULL; + + Wrapper_Utilities::fnc_entry(106,"Sample_Query::build_data_area"); + for(i=0; i < mNumColumns; i++) + { + switch(mData[i].type) + { + case SQL_INTEGER: + bsize = sizeof(int); + break; + case SQL_DOUBLE: + bsize = sizeof(double); + break; + case SQL_DECIMAL: + bsize = sizeof(MAX_DECIMAL_SIZE); + break; + case SQL_CHAR: + case SQL_VARCHAR: + bsize = mData[i].len + 1; + break; + default: + srv = (FencedSample_Server *)get_server(); + serverName = srv->get_name(); + rc = Wrapper_Utilities::report_error("SQBda", SQL_RC_E1823, 2, + strlen((const char *)mData[i].name), (const char *)mData[i].name, + strlen((const char *)serverName), (const char *)serverName); + + Wrapper_Utilities::fnc_data2(106,"Sample_Query::build_data_area", 100, + strlen((const char *)mData[i].name), (const char *)mData[i].name, + strlen((const char *)serverName), (const char *)serverName); + + Wrapper_Utilities::trace_error(106,"Sample_Query::build_data_area", + 100, sizeof(rc), &rc); + goto exit; + } + rc = Wrapper_Utilities::allocate(bsize,(void **)&mData[i].data); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 110, "SQBda"); + Wrapper_Utilities::trace_error(106,"Sample_Query::build_data_area", + 110, sizeof(rc), &rc); + goto exit; + } + } + +exit: + Wrapper_Utilities::fnc_exit(106,"Sample_Query::build_data_area", rc); + return rc; +} + +/**************************************************************************** +* Function Name = Sample_Query::table_scan() +* +* Function: The table_scan function retrieves one row at a time until the end +* of the file is reached. +* When a row is read, we save the selected data elements in the +* column data array and return to the fetch function. The file +* pointer is left pointing to the next row so when fetch is called +* to return the next row the table_scan function will resume +* searching for matches where it had left off previously. +* +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::table_scan() +{ + sqlint32 rc = 0; + sqlint32 i = 0; + + Wrapper_Utilities::fnc_entry(107,"Sample_Query::table_scan"); + // Get and tokenize a row from the data source + rc = get_data(); + if (rc) + { + Wrapper_Utilities::trace_error(107,"Sample_Query::table_scan", + 100, sizeof(rc), &rc); + goto exit; + } + + // If there are no more rows (mFinished set to YES by get_data()) return to fetch. + if (mFinished == YES) return rc; + + mResult = NO_MATCH; + if (mPredOperator == ALL_ROWS) + { + mResult = MATCH; + } + else + { + // Compare the retrieved row key to the search term + rc = do_compare(); + if (rc) + { + Wrapper_Utilities::trace_error(107,"Sample_Query::table_scan", + 110, sizeof(rc), &rc); + goto exit; + } + + // If the retrieved row is not a match and there are more rows available + // then continue retrieving until 1) a match is found, or 2) there are no + // more rows to search + while (mResult != MATCH && !mFinished) + { + // Get and tokenize the next row + rc = get_data(); + if (rc) + { + Wrapper_Utilities::trace_error(107,"Sample_Query::table_scan", + 120, sizeof(rc), &rc); + goto exit; + } + + if (mFinished) + { + goto exit; + } + // Compare the retrieved row to the search term + rc = do_compare(); + if (rc) + { + Wrapper_Utilities::trace_error(107,"Sample_Query::table_scan", + 130, sizeof(rc), &rc); + goto exit; + } + } + } + + // If a match was found then save the request columns in the column + // data array and return to the fetch function. + if (mResult == MATCH) + { + i = 0; + while (mColumnVector[i] != -1) + { + rc = save(mTokens[mColumnVector[i]],mColumnVector[i]); + if (rc) + { + Wrapper_Utilities::trace_error(107,"Sample_Query::table_scan", + 140, sizeof(rc), &rc); + goto exit; + } + i++; + } + } + +exit: + Wrapper_Utilities::fnc_exit(107,"Sample_Query::table_scan", rc); + return rc; +} + +/**************************************************************************** +* Function Name = Sample_Query::save() +* +* Function: The save function takes character representation of the data +* element to be saved, converts it if needed to the proper data +* type, and then stores it in the column data array item indexed +* by the columnVector. +* +* Input: char *fetchedData character representation of the data element to +* be saved. +* +* int columnVector An index into the column data array pointing to +* the appropriate column to save this data. +* +* Output: rc = 0, success +* != 0, failure +* Note: There is no way of knowing if the atoi or atof failed. If +* either fail the return value is undefined, but usually 0. +*****************************************************************************/ +sqlint32 Sample_Query::save(char *fetchedData, int columnVector) +{ + char *func_name = "SQ_Sv"; + sqlint32 rc = 0; + sqlint32 trace_error = 0; + int tempInt = 0; + size_t offset = 0; + double tempDouble = 0; + FencedSample_Server *srv = NULL; + sqluint8 *serverName = NULL; + + // If the data type for this column is INTEGER then convert the fetched + // data to type INT and store it in the previously allocate data area. + Wrapper_Utilities::fnc_entry(108,"Sample_Query::save"); + + if (mData[columnVector].type == SQL_INTEGER) + { + if (fetchedData == NULL) + { + if (mData[columnVector].data != NULL) + { + Wrapper_Utilities::deallocate(mData[columnVector].data); + mData[columnVector].data = NULL; + } + } + else + { + offset = strspn(fetchedData,"+-0123456789"); + if (offset != strlen(fetchedData)) + { + rc = Wrapper_Utilities::report_error("SQSave", SQL_RC_E408,1, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + + Wrapper_Utilities::fnc_data(108,"Sample_Query::save", 100, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + trace_error = 100; + goto error; + } + double intMax = INT_MAX; + double intMin = INT_MIN; + errno = 0; + double value = atof(fetchedData); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQSave", SQL_RC_E405, 1, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + + Wrapper_Utilities::fnc_data(108,"Sample_Query::save", 110, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + trace_error = 110; + goto error; + } + + if ((value < intMin) || (value > intMax)) + { + rc = Wrapper_Utilities::report_error("SQSave", SQL_RC_E405, 1, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + + Wrapper_Utilities::fnc_data(108,"Sample_Query::save", 120, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + trace_error = 120; + goto error; + } + + if (mData[columnVector].data == NULL) + { + rc = Wrapper_Utilities::allocate(sizeof(int),(void **)&mData[columnVector].data); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 130, func_name); + trace_error = 130; + goto error; + } + } + errno = 0; + tempInt = atoi(fetchedData); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQSave", SQL_RC_E405, 1, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + + Wrapper_Utilities::fnc_data(108,"Sample_Query::save", 140, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + trace_error = 140; + goto error; + } + memcpy(mData[columnVector].data, &tempInt, sizeof(int)); + } + } + + // If the data type is DOUBLE then convert the fetched data to type double and + // store it in the previously allocated data area. + else if + (mData[columnVector].type == SQL_DOUBLE) + { + if (fetchedData == NULL) + { + if (mData[columnVector].data != NULL) + { + Wrapper_Utilities::deallocate(mData[columnVector].data); + mData[columnVector].data = NULL; + } + } + else + { + offset = strspn(fetchedData,"+-.0123456789eE"); + if (offset != strlen(fetchedData)) + { + rc = Wrapper_Utilities::report_error("SQSave", SQL_RC_E408,1, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + + Wrapper_Utilities::fnc_data(108,"Sample_Query::save", 150, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + trace_error = 150; + goto error; + } + if (mData[columnVector].data == NULL) + { + rc = Wrapper_Utilities::allocate(sizeof(double),(void **)&mData[columnVector].data); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 160, func_name); + trace_error = 160; + goto error; + } + } + errno = 0; + tempDouble = atof(fetchedData); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQSave", SQL_RC_E405, 1, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + + Wrapper_Utilities::fnc_data(108,"Sample_Query::save", 170, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + trace_error = 170; + goto error; + } + + memcpy(mData[columnVector].data,&tempDouble, sizeof(double)); + } + } + + // If the data type is DECIMAL then convert the fetched data to type decimal and + // store it in the previously allocated data area. + else if + (mData[columnVector].type == SQL_DECIMAL) + { + if (fetchedData == NULL) + { + if (mData[columnVector].data != NULL) + { + Wrapper_Utilities::deallocate(mData[columnVector].data); + mData[columnVector].data = NULL; + } + } + else + { + offset = strspn(fetchedData,"+-.0123456789"); + if (offset != strlen(fetchedData)) + { + rc = Wrapper_Utilities::report_error("SQSave", SQL_RC_E408,1, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + + Wrapper_Utilities::fnc_data(108,"Sample_Query::save", 180, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + trace_error = 180; + goto error; + } + if (mData[columnVector].data == NULL) + { + rc = Wrapper_Utilities::allocate(MAX_DECIMAL_SIZE,(void **)&mData[columnVector].data); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 190, func_name); + trace_error = 190; + goto error; + } + mData[columnVector].len = MAX_DECIMAL_SIZE - 1; // Don't count the null terminator + } + if (mData[columnVector].len < MAX_DECIMAL_SIZE) + { + Wrapper_Utilities::deallocate(mData[columnVector].data); + rc = Wrapper_Utilities::allocate(MAX_DECIMAL_SIZE,(void **)&mData[columnVector].data); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 200, func_name); + trace_error = 200; + goto error; + } + mData[columnVector].len = MAX_DECIMAL_SIZE - 1; + } + + strcpy((char *)mData[columnVector].data, fetchedData); + } + } + + // If the data type was CHARACTER or VARCHAR then copy it to the previously + // allocated data area. Truncation may occur if the fetched data length is + // greater than the defined column size. + + else if + (mData[columnVector].type == SQL_CHAR) + { + if (fetchedData == NULL) + { + if (mData[columnVector].data != NULL) + { + Wrapper_Utilities::deallocate(mData[columnVector].data); + mData[columnVector].data = NULL; + } + } + else + { + if (mData[columnVector].data == NULL) + { + rc = Wrapper_Utilities::allocate(mData[columnVector].len + 1,(void **)&mData[columnVector].data); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 210, func_name); + trace_error = 210; + goto error; + } + } + memset((char *)mData[columnVector].data,' ',mData[columnVector].len); + if ((sqlint32) strlen(fetchedData) > mData[columnVector].len) + { + strncpy((char *)mData[columnVector].data,fetchedData,mData[columnVector].len); + } + else + { + strncpy((char *)mData[columnVector].data,fetchedData,strlen(fetchedData)); + } + } + } + else if + (mData[columnVector].type == SQL_VARCHAR) + { + if (fetchedData == NULL) + { + if (mData[columnVector].data != NULL) + { + Wrapper_Utilities::deallocate(mData[columnVector].data); + mData[columnVector].data = NULL; + } + } + else + { + if (mData[columnVector].data == NULL) + { + rc = Wrapper_Utilities::allocate(mData[columnVector].len + 1,(void **)&mData[columnVector].data); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 220, func_name); + trace_error = 220; + goto error; + } + } + if ( (sqlint32) strlen(fetchedData) > mData[columnVector].len) + { + memcpy((char *)mData[columnVector].data, fetchedData, mData[columnVector].len); + *((char *)mData[columnVector].data + mData[columnVector].len) = '\0'; + } + else + { + strncpy((char *)mData[columnVector].data,fetchedData,strlen(fetchedData)); + *((char *)mData[columnVector].data + strlen(fetchedData)) = '\0'; + } + } + } + // Report and unsupported data type error to DB2 + else + { + srv = (FencedSample_Server *)get_server(); + serverName = srv->get_name(); + rc = Wrapper_Utilities::report_error("SQDcomp", SQL_RC_E1823,2, + strlen((const char *)mData[columnVector].name), (const char *)mData[columnVector].name, + strlen((const char *)serverName), (const char *)serverName); + + Wrapper_Utilities::fnc_data(108,"Sample_Query::save", 230, + strlen((const char *)mData[columnVector].name), + (const char *)mData[columnVector].name); + trace_error = 230; + goto error; + } + +exit: + Wrapper_Utilities::fnc_exit(108,"Sample_Query::save", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(108,"Sample_Query::save", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::build_decimal_string() +* +* Function: This function is used to build a stringified version of a +* decimal number so that it can be used in a comparison. +* +* Input: char **result - location for the stringified decimal number +* char *input - variable size character string of decimal number +* int scale - scale of the decimal number +* int precision - precision of the decimal number +* int *sign - location to store the sign of the number +* +* Output: rc = 0, success +* != 0, failure +* NOTE: There is no way to be sure that the atoi function worked +* properly. If the fuction fails the return result is +* undefined, but usually zero. +*****************************************************************************/ + +sqlint32 Sample_Query::build_decimal_string(char **result, + char *input, + int scale, + int precision, + int *sign) +{ + char decimal[32]; // location to hold the decimal part of the number + char mantissa[32]; // location to hold the mantissa + sqlint32 rc = 0; + sqlint32 trace_error = 0; + char *ptr = NULL; + char *progress = NULL; // pointer for strtok_r + char *tempDec = NULL; // pointer to the decimal part of the number + char *tempMant = NULL; // pointer to the mantissa + char *buffer = NULL; // workarea to hold a copy of the input + + + Wrapper_Utilities::fnc_entry(109,"Sample_Query::build_decimal_string"); + // allocate work area + rc = Wrapper_Utilities::allocate(strlen(input) + 1, (void **)&buffer); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 300, "SQ:BDS"); + trace_error = 300; + goto error; + } + + // Copy decimal number to work area + strcpy(buffer,input); + + // Allocate space for the stringified version of the decimal number. + // Max decimal(31) + max mantissa(31) + sign(1) + radix char(1) + null terminator(1) + rc = Wrapper_Utilities::allocate(65,(void **)result); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 310, "SQ:BDS"); + trace_error = 310; + goto error; + } + + // Get a pointer to the result area + ptr = *result; + + memset(decimal,'0',31); // Set the decimal work area to character zero's + memset(mantissa,'0',31); // Set the mantissa work area to character zero's + decimal[31] = '\0'; // Null terminate the decimal work area + mantissa[31] = '\0'; // Null terminate the mantissa work area + + ptr = buffer; // Point to the work area version of the decimal number + + if (*ptr == '-' || *ptr == '+') // If a sign in present + { + if (*ptr == '-') + { + *sign = -1; // Set the sign to negative + } + else + { + *sign = 1; // set the sign to positive + } + ptr++; // increment past the sign + } + else + { + *sign = 1; // If no sign present assume it's positive + } + + // Get the decimal and mantissa portions of the number +#ifdef SQLUNIX + tempDec = strtok_r(ptr,".",&progress); + tempMant = strtok_r(NULL,".",&progress); +#endif + +#ifdef WIN32 + tempDec = strtok(ptr,"."); + tempMant = strtok(NULL,"."); +#endif + + // Copy the decimal portion of the number to the decimal work area + // Right justifying the number in the work area. + strcpy((char *)&decimal + (strlen(decimal) - strlen(tempDec)),tempDec); + + // Copy the mantissa portion of the number to the mantissa work area + // left justifying the number and possibly truncating. + if (scale < (int) strlen(tempMant)) + { + memcpy((char *)&mantissa,tempMant,scale); + } + else + { + memcpy((char *)&mantissa,tempMant,strlen(tempMant)); + } + + ptr = *result; // Point to the result area + + strcpy(ptr,(char *)&decimal); // copy the decimal portion of the number to the result + strcat(ptr,(char *)&mantissa); // copy the matissa portion of the number to the result + + Wrapper_Utilities::deallocate(buffer); // Free the work area + +exit: + Wrapper_Utilities::fnc_exit(109,"Sample_Query::build_decimal_string", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(109,"Sample_Query::build_decimal_string", + trace_error, sizeof(rc), &rc); + goto exit; + +} + +/**************************************************************************** +* Function Name = Sample_Query::get_data() +* +* Function: This function reads a record from the data file and tokenizes +* the data. +* +* +* Input: +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::get_data() +{ + char *func_name = "SQdta"; + sqlint32 rc = 0; + sqlint32 trace_error = 0; + FencedSample_Server *srv = (FencedSample_Server *)get_server(); + sqluint8 *serverName = srv->get_name(); + + Wrapper_Utilities::fnc_entry(110,"Sample_Query::get_data"); + + for (int j = 0; j < mNumColumns; j++) + { + if (mTokens[j] != NULL) + { + Wrapper_Utilities::deallocate(mTokens[j]); + mTokens[j] = NULL; + } + } + + // Get a record into the input buffer. + GET_A_RECORD(mBuffer,mFile); + + // If we are at eof then set the finished indicator and return + if (END_OF_FILE(mFile)) + { + mFinished = YES; + goto exit; + } + + // Checking to see if the record we read is longer than the buffer + // we allocated (more than MAX_LINE_SIZE) + if ((*(mBuffer + (strlen(mBuffer) - 1)) != '\n') && (mFinished == NO)) + { + rc = Wrapper_Utilities::report_error(func_name, SQL_RC_E1822, 3, + strlen(DATA_ERROR), DATA_ERROR, + strlen((const char *)serverName), (const char *)serverName, + strlen(FILE_SIZE_ERROR), FILE_SIZE_ERROR); + CLOSE_FILE(mFile); + trace_error = 100; + goto error; + } + + // Break the line up into the appropriate columns + rc = tokenize((sqluint8 *)mBuffer,mNumColumns,(sqluint8 **)mTokens); + if (rc) + { + CLOSE_FILE(mFile); + trace_error = 110; + goto error; + } + +exit: + Wrapper_Utilities::fnc_exit(110,"Sample_Query::get_data", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(110,"Sample_Query::get_data", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/************************************************************************** +* +* Function Name = Sample_Query::tokenize(sqluint8 *buffer, +* int colCount, +* sqluint8 **tokens) +* +* Function: This routine tokenizes a buffer based on the comma delimiter +* +* Dependencies: +* +* Restrictions: +* +* Input: sqluint8 *buffer - input line to tokenize +* int colCount - number of columns in pseudo-table +* sqluint8 **tokens - ptrs to the char ptrs that hold the tokens +* +* Output: sqlint32 rc +* +* Normal Return = 0 +* +* Error Return = !0 +* +**************************************************************************/ + +sqlint32 Sample_Query::tokenize(sqluint8 *buffer, int colCount, sqluint8 **tokens) +{ + char *tokStart = (char *)buffer; + char *tokEnd = strchr(tokStart,','); // *tokEnd = NULL if no ',' found + int i = 0; + int columnsFound = 0; + int size = tokEnd - tokStart; + sqlint32 rc = 0; + sqlint32 trace_error = 0; + char *ptr = (char *)buffer + strlen((const char *)buffer) - 1; + + Wrapper_Utilities::fnc_entry(111,"Sample_Query::tokenize"); + + if ((int) strlen((const char *)buffer) < colCount) + { + rc = Wrapper_Utilities::report_error("SQToken", SQL_RC_E1822, 2, + strlen("Remote Data Error"),"Remote Data Error", + strlen("Invalid Data File"),"Invalid Data File"); + trace_error = 340; + goto error; + } + + // Check for invalid delimter or nicknames with only one column defined + if (tokEnd == NULL) + { + // Check to make sure that this nickname has more than 1 column defined + if (colCount != 1) + { + // Delimiter (comma) not found in the line we read; hence wrong delimiter! + + rc = Wrapper_Utilities::report_error("SQToken", SQL_RC_E1822, 2, + strlen("Remote Data Error"),"Remote Data Error", + strlen("Invalid Column Delimiter"),"Invalid Column Delimiter"); + trace_error = 350; + goto error; + } + } + + // Replace the newline with a null terminator + if (*ptr == '\n') + { + *ptr = '\0'; + } + + // Release any previously allocated tokens + for (i = 0; i < colCount; i++) + { + if (tokens[i] != NULL) + Wrapper_Utilities::deallocate(tokens[i]); + tokens[i] = NULL; + } + + i = 0; + + /**************************************************************************/ + /* Tokenize the line. We had to write our own tokenizer rather than */ + /* use strtok_r because strtok_r did not handle the NULL column condition */ + /* (where two delimiters where back to back) correctly. */ + /**************************************************************************/ + + // We will go inside this loop only if there is more than one column defined + if (colCount > 1) + { + for (;;) + { + if (columnsFound == colCount) + { + rc = Wrapper_Utilities::report_error("SQToken", SQL_RC_E1822, 2, + strlen("Remote Data Error"),"Remote Data Error", + strlen("Too many columns"), "Too many columns"); + trace_error = 360; + goto error; + } + + if (size == 0) // NULL column condition + { + tokens[i] = NULL; + } + else + { // allocate space for the token and copy it there + rc = Wrapper_Utilities::allocate(size + 1,(void **)&tokens[i]); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 370, "SQ:TOK"); + trace_error = 370; + goto error; + } + memcpy(tokens[i],tokStart,size); + } + + columnsFound++; + + tokStart = tokEnd + 1; // Find the start of the next token + tokEnd = strchr(tokStart,','); // Find the end of the next token + + if (tokEnd == NULL) // Is this the last token? + { + // If we found too many tokens signal an error + if (columnsFound == colCount) + { + rc = Wrapper_Utilities::report_error("SQToken",SQL_RC_E1822, 2, + strlen("Remote Data Error"),"Remote Data Error", + strlen("Too many columns"),"Too many columns"); + trace_error = 380; + goto error; + } + i++; // Yes increment the counter and break + columnsFound++; + break; + } + + size = tokEnd - tokStart; // calculate the size of the token + i++; + } + + // If we didn't find all the columns signal an error + if (columnsFound != colCount) + { + rc = Wrapper_Utilities::report_error("SQToken", SQL_RC_E1822, 2, + strlen("Remote Data Error"),"Remote Data Error", + strlen("Data file missing columns"),"Data file missing columns"); + trace_error = 390; + goto error; + } + + } // end if (colCount !=1) + + // Process the last token + if (strlen(tokStart) > 0) // Is the token not null? + { + // allocate space for the token and copy it there + size = strlen(tokStart) + 1; + rc = Wrapper_Utilities::allocate(size, (void **)&tokens[i]); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 400, "SQ:TOK"); + trace_error = 400; + goto error; + } + strcpy((char *)tokens[i],tokStart); + } + else // Last token NULL + { + tokens[i] = NULL; + } + +exit: + Wrapper_Utilities::fnc_exit(111,"Sample_Query::tokenize", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(111,"Sample_Query::tokenize", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::pack() +* +* Function: The pack function takes a character string representation of a +* number and converts it to packed decimal. +* +* Input: number - char* representation of a number. +* packed - char ** location for packed decimal representation of number +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::pack(char *number, char **packed) +{ + int negative = NO; // Negative number indicator + char *ptr = number; // pointer to first character of number + char *packedPtr = NULL; // pointer to the first byte of the packed number + int digitCount = 0; // digit counter + char nible = 0x00; // indicator used to denote which nible is being constructed + char digit = 0x00; // packed digit workarea + int rc = 0; // return code + + Wrapper_Utilities::fnc_entry(112,"Sample_Query::pack"); + packedPtr = *packed; // point to first byte of packed number + + digitCount = strlen(number); // Count the number of characters in the number + // to be converted + + if (*number == '-') // If the number is negative decrement the digit counter + { // set the negative indicator, and move the pointer to the + digitCount--; // first digit of the number + negative = YES; + ptr++; + } + + if (strstr(number,".") != NULL) // If there is a decimal point in the number + digitCount--; // decrement the digit count. + + if (digitCount % 2 == 0) // If the number of digits to be packed is even + nible ^= 0x01; // then begin constructing the packed number at the + // second nible of the byte. + + while (digitCount != 0) // while there are digits to pack do... + { + digit = *ptr; // copy the digit into the work area + + if (digit == '.') // if the digit is actually a decimal point + { // go to the next digit and restart the loop + ptr++; + continue; + } + + if (nible == 0x01) // If we are working with the second nible + { // then clear the first nible. Next OR the + digit &= 0x0f; // second nible to the second nible of the + *packedPtr |= digit; // packed number. Move the next packed byte + packedPtr++; + } + else // If we are working with the first nible of + { // of the packed number then shift the numeric + digit <<= 4; // bits to the first nible of the workarea and + *packedPtr = (digit & 0xf0); // OR them to the first nible of the packed digit + } + + ptr++; // Move to the next digit to be packed + + digitCount--; // Decrement the digit counter + + nible ^= 0x01; // flip flop the nible indicator + + } + + if (negative) // If the number being packed is negative then + *packedPtr |= 0x0d; // OR the sign nible negative, otherwise OR the + else // sign nible positive + *packedPtr |= 0x0c; + + Wrapper_Utilities::fnc_exit(112,"Sample_Query::tokenize", rc); + return rc; + +} + +/**************************************************************************** +* Function Name = Sample_Query::format_packed_decimal() +* +* Function: This function converts a decimal number, temporarily stored as +* a double, into the proper sized packed decimal number. +* +* Input: int vector - index to the data structure for the decimal number +* int precision - the precision of the column +* int scale - the scale of the column +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::format_packed_decimal(int vector,int precision,int scale) +{ + sqlint32 rc = 0; // Return code + sqlint32 trace_error = 0; + char buffer[100]; // work area + char *pd = NULL; // area to hold the packed number + int pdSize = (precision / 2) + 1; // size in bytes of pd number + char *ptr = &buffer[0]; // pointer to workarea + char *decimal = NULL; // pointer to decimal part of number + char *mantissa = NULL; // pointer to the mantissa + int negative = NO; // negative indicator + char *progress = NULL; // place holder for strtok_r + int decSize = precision - scale; // size of decimal portion + char *decBuffer = NULL; // ptr to decimal workarea + char *scaleBuffer = NULL; // ptr to mantissa workarea + char *rawNumber = NULL; // ptr to unpacked reconstructed number + + Wrapper_Utilities::fnc_entry(113,"Sample_Query::format_packed_decimal"); + // Allocate space for the packed decimal number, the decimal, mantissa, and + // reconstructed number work areas + rc = Wrapper_Utilities::allocate(pdSize,(void **)&pd); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 410, "SQ:TOK"); + trace_error = 410; + goto error; + } + + rc = Wrapper_Utilities::allocate((decSize + 1),(void **)&decBuffer); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 420, "SQ:TOK"); + trace_error = 420; + goto error; + } + + rc = Wrapper_Utilities::allocate((scale + 1), (void **)&scaleBuffer); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 430, "SQ:TOK"); + trace_error = 430; + goto error; + } + + rc = Wrapper_Utilities::allocate((precision + 3),(void **)&rawNumber); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 440, "SQ:TOK"); + trace_error = 440; + goto error; + } + + // Convert the double into the character representation of the number + + strcpy(buffer,(const char *)mData[vector].data); + + if (*ptr == '-') // If the number is negative point past the minus sign + { // and set the negative indicator + negative = YES; + ptr++; + } + + if (*ptr == '+') // If a plus sign is on the number than point past the sign + { + ptr++; + } + + // parse the decimal and mantissa portions of the number + if (buffer[0] == '.') + { +#ifdef SQLUNIX + mantissa = strtok_r(ptr,".",(char **)&progress); +#endif +#ifdef WIN32 + mantissa = strtok(ptr,"."); +#endif + } + else + { +#ifdef SQLUNIX + decimal = strtok_r(ptr,".",(char **)&progress); + mantissa = strtok_r((char *)NULL,".",(char **)&progress); +#endif +#ifdef WIN32 + decimal = strtok(ptr,"."); + mantissa = strtok(NULL,"."); +#endif + } + + if (decimal != NULL) + { + if (decSize < (int) strlen(decimal)) // If the decimal part of the number is too + { // large for the column signal an error to DB2 + rc = Wrapper_Utilities::report_error("SQFpd",SQL_RC_E405,1, + strlen((const char *)mData[vector].name), + (const char *)mData[vector].name); + + Wrapper_Utilities::fnc_data(113,"Sample_Query::format_packed_decimal", 450, + strlen((const char *)mData[vector].name), + (const char *)mData[vector].name); + trace_error =450; + goto error; + } + else // If decimal part of number is smaller than max size + if (decSize > (int) strlen(decimal)) // left fill the decimal buffer with zeros and copy + { // the number into the buffer + memset(decBuffer,'0',decSize); + memcpy(decBuffer + (decSize - strlen(decimal)),decimal,strlen(decimal)); + } + else // copy the number into the buffer + { + memcpy(decBuffer,decimal,strlen(decimal)); + } + } + else + { + memset(decBuffer,'0',decSize); + } + + if (scale <= (int) strlen(mantissa)) // If the mantissa is LE the size available then + { // copy the mantissa into the buffer possible truncating data + memcpy(scaleBuffer,mantissa,scale); + } + else // Right pad the mantissa buffer and copy the mantissa into + { // the buffer + memset(scaleBuffer,'0',scale); + memcpy(scaleBuffer,mantissa,strlen(mantissa)); + } + + ptr = rawNumber; // point to the unformatted buffer + + if (negative) // If it's a negative number then insert the minus sign + { + *ptr = '-'; + ptr++; + } + + strcat(ptr,decBuffer); // cat the decimal part of the number to the unformatted buffer + strcat(ptr,"."); // cat the decimal point + strcat(ptr,scaleBuffer); // cat the mantissa + + rc = pack(rawNumber,&pd); // pack the number + if (rc) + { + trace_error =460; + goto error; + } + + Wrapper_Utilities::deallocate(mData[vector].data); // free the char representation of the data + + mData[vector].data = NULL; // set the data ptr to null + + // allocate space for the packed decimal number + rc = Wrapper_Utilities::allocate(pdSize,&mData[vector].data); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 470, "SQ:TOK"); + trace_error = 470; + goto error; + } + + + memcpy(mData[vector].data,pd,pdSize); // Copy the packed decimal number to the data field + + mData[vector].len = pdSize; // Store the size + + Wrapper_Utilities::deallocate(pd); + Wrapper_Utilities::deallocate(decBuffer); + Wrapper_Utilities::deallocate(scaleBuffer); + Wrapper_Utilities::deallocate(rawNumber); + +exit: + Wrapper_Utilities::fnc_exit(113,"Sample_Query::format_packed_decimal", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(113,"Sample_Query::format_packed_decimal", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::do_compare() +* +* Function: This function is used to control the comparison of the search term +* to the key field. The actual compare function is overloaded +* and varies by the argument type being used in the compare. +* +* Input: +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::do_compare() +{ + sqlint32 rc = 0; + sqlint32 trace_error = 0; + int tmpInt = 0; + short tmpShort = 0; + float tmpFloat = 0.0; + double tmpDouble = 0.0; + int scale = 0; + int precision = 0; + double intMax = INT_MAX; + double intMin = INT_MIN; + double value = 0; + FencedSample_Server *srv = NULL; + sqluint8 *serverName = NULL; + + + Wrapper_Utilities::fnc_entry(114,"Sample_Query::do_compare"); + + // Select which compare to call based upon the sql type of the key field + switch(mData[mKeyVector].type) + { + case SQL_INTEGER: + // For integer compares, convert the fetched data to an + // integer and call the compare function. + errno = 0; + value = atof(mTokens[mKeyVector]); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcomp", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 01; + goto error; + } + + if ((value < intMin) || (value > intMax)) + { + rc = Wrapper_Utilities::report_error("SQdcomp", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 10; + goto error; + } + + errno = 0; + tmpInt = atoi(mTokens[mKeyVector]); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcomp", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 20; + goto error; + } + rc = compare(tmpInt); + if( rc ) + { + trace_error = 30; + goto error; + } + break; + + case SQL_SMALLINT: + // For short compares, convert the fetched data to an + // integer. Verify that the data is valid for a short. + // Assign the data to a short and call the compare function. + errno = 0; + tmpInt = atoi(mTokens[mKeyVector]); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcomp", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 40; + goto error; + } + if ((tmpInt > SHRT_MAX) || (tmpInt < SHRT_MIN)) + { + rc = Wrapper_Utilities::report_error("SQdcomp",SQL_RC_E405,1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 50; + goto error; + } + tmpShort = (short)tmpInt; + rc = compare(tmpShort); + if( rc ) + { + trace_error = 60; + goto error; + } + break; + + case SQL_DECIMAL: + // Decimal range checking will be done in the format_packed_data + // function that is used to build the decimal comparison terms + + rc = compare(mTokens[mKeyVector],mData[mKeyVector].scale,mData[mKeyVector].precision); + if( rc ) + { + trace_error = 70; + goto error; + } + break; + + case SQL_DOUBLE: + // For double compares, convert the fetched data to a double and + // call the compare fuction. + errno = 0; + tmpDouble = atof(mTokens[mKeyVector]); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcomp", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 80; + goto error; + } + + rc = compare(tmpDouble); + if( rc ) + { + trace_error = 90; + goto error; + } + break; + + case SQL_REAL: + // For real compares, convert the fetched data to a double and + // verify that the data is a valid single precision number. Then + // assign the data to a float and call the compare function. + errno = 0; + tmpDouble = atof(mTokens[mKeyVector]); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcomp", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 100; + goto error; + } + + if ((tmpDouble != 0.0) && + ((fabs(tmpDouble) < FLT_MIN) || + (fabs(tmpDouble) > FLT_MAX))) + { + rc = Wrapper_Utilities::report_error("SQdcomp", SQL_RC_E405,1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 110; + goto error; + } + + tmpFloat = (float)tmpDouble; + rc = compare(tmpFloat); + + if( rc ) + { + trace_error = 120; + goto error; + } + break; + + case SQL_CHAR: + case SQL_VARCHAR: + // For Character and VARCHAR compares call the compare function + rc = compare(mTokens[mKeyVector]); + if( rc ) + { + trace_error = 130; + goto error; + } + + break; + default: + // We don't support other data types to signal an error to DB2 + + srv = (FencedSample_Server *)get_server(); + serverName = srv->get_name(); + rc = Wrapper_Utilities::report_error("SQdcomp", + SQL_RC_E1823,2,strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name, + strlen((const char *)serverName), (const char *)serverName); + + trace_error = 140; + goto error; + } + +exit: + Wrapper_Utilities::fnc_exit(114,"Sample_Query::do_compare", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(114,"Sample_Query::do_compare", + trace_error, sizeof(rc), &rc); + goto exit; +} + + + +/**************************************************************************** +* Function Name = Sample_Query::compare() +* +* Function: This function is used to compare the search term to the key +* element selected from the current row. This is called when +* the key is an int. +* +* Input: int compareTerm key element from the current row +* +* Output: rc = 0, success +* != 0, failure +* NOTE: There is no way to be sure that the atoi function worked +* properly. If the fuction fails the return result is +* undefined, but usually zero. +*****************************************************************************/ +sqlint32 Sample_Query::compare(int compareTerm) +{ + sqlint32 rc = 0; + sqlint32 trace_error = 0; + int searchTerm = 0; + double intMax = INT_MAX; + double intMin = INT_MIN; + double value = 0; + + Wrapper_Utilities::fnc_entry(115,"Sample_Query::compare(int)"); + + // errno is a global var in libc.a + errno = 0; + value = atof(mSearchTerm); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcompi", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 10; + goto error; + } + + if ((value < intMin) || (value > intMax)) + { + rc = Wrapper_Utilities::report_error("SQdcompi", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 20; + goto error; + } + + // Convert the search term to an integer. + errno = 0; + searchTerm = atoi(mSearchTerm); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcompi", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 30; + goto error; + } + + // Set mResult based upon the predicate operator. + switch (mPredOperator) + { + //only support '=' + case SQL_EQ: + + if (searchTerm == compareTerm) + { + mResult = MATCH; + } + else + { + mResult = NO_MATCH; + } + break; + + default: + { + rc = Wrapper_Utilities::report_error("SQdcompi", + SQL_RC_E901,1,strlen(BAD_PRED_OP),BAD_PRED_OP); + trace_error = 40; + goto error; + } + } + +exit: + Wrapper_Utilities::fnc_exit(115,"Sample_Query::compare(int)", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(115,"Sample_Query::compare(int)", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::compare() +* +* Function: This function is used to compare the search term to the key +* element selected from the current row. This is called when +* the key is a short. +* +* +* Output: rc = 0, success +* != 0, failure +* NOTE: There is no way to be sure that the atoi function worked +* properly. If the fuction fails the return result is +* undefined, but usually zero. +*****************************************************************************/ +sqlint32 Sample_Query::compare(short compareTerm) +{ + sqlint32 rc = 0; + sqlint32 trace_error = 0; + int tmpInt = 0; + short searchTerm = 0; + int compTerm = 0; + + Wrapper_Utilities::fnc_entry(116,"Sample_Query::compare(short)"); + + // Convert the search term to an integer + + errno = 0; + tmpInt = atoi(mSearchTerm); + + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcomps", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 10; + goto error; + } + + // Verify that it is a valid short value + if ((tmpInt > SHRT_MAX) || (tmpInt < SHRT_MIN)) + { + rc = Wrapper_Utilities::report_error("SQdcomps", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 20; + goto error; + } + + searchTerm = (short)tmpInt; + + // Set the result based upon the predicate operator. + switch (mPredOperator) + { + //only support '=' + case SQL_EQ: + if (searchTerm == compareTerm) + { + mResult = MATCH; + } + else + { + mResult = NO_MATCH; + } + break; + default: + rc = Wrapper_Utilities::report_error("SQdcomps", + SQL_RC_E901,1,strlen(BAD_PRED_OP),BAD_PRED_OP); + trace_error = 30; + goto error; + } + +exit: + Wrapper_Utilities::fnc_exit(116,"Sample_Query::compare(short)", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(116,"Sample_Query::compare(short)", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::compare() +* +* Function: This function is used to compare the search term to the key +* element from the selected row. This function is called when +* the key element is a double. +* +* +* Output: rc = 0, success +* != 0, failure +* NOTE: There is no way to be sure that the atof function worked +* properly. If the fuction fails the return result is +* undefined, but usually zero. +*****************************************************************************/ +sqlint32 Sample_Query::compare(double compareTerm) +{ + sqlint32 rc = 0; + sqlint32 trace_error = 0; + double searchTerm = 0; + + Wrapper_Utilities::fnc_entry(117,"Sample_Query::compare(double)"); + + // Convert the search term to a double + errno = 0; + searchTerm = atof(mSearchTerm); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcompd", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 10; + goto error; + } + + + // Set the result based upon the predicate operator + switch (mPredOperator) + { + //only support '=' + case SQL_EQ: + if (searchTerm == compareTerm) + { + mResult = MATCH; + } + else + { + mResult = NO_MATCH; + } + break; + + default: + rc = Wrapper_Utilities::report_error("SQdcompd", + SQL_RC_E901, 1, strlen(BAD_PRED_OP),BAD_PRED_OP); + trace_error = 20; + goto error; + } + +exit: + Wrapper_Utilities::fnc_exit(117,"Sample_Query::compare(double)", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(117,"Sample_Query::compare(double)", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query:compare() +* +* Function: This function is used to compare the search term to the key +* element from the selected row. This function is called when +* the key element is a string. +* +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Query::compare(char *compareTerm) +{ + sqlint32 rc = 0; + sqlint32 trace_error = 0; + int result = 0, size = 0; + char *searchTerm = NULL; + char *currentValue = NULL; + sqlint32 compare_length = 0; + + + Wrapper_Utilities::fnc_entry(118,"Sample_Query::compare(char*)"); + + compare_length = strlen(compareTerm); + + if (compare_length > strlen(mSearchTerm)) + { + size = compare_length + 1; + } + else + { + size = strlen(mSearchTerm) + 1; + } + + rc = Wrapper_Utilities::allocate(size,(void **)&searchTerm); + if (rc) + { + trace_error = 10; + goto error; + } + + memset(searchTerm, ' ',(size -1)); + + memcpy(searchTerm,mSearchTerm,strlen(mSearchTerm)); + + rc = Wrapper_Utilities::allocate(size,(void **)¤tValue); + if (rc) + { + trace_error = 20; + goto error; + } + + memset(currentValue, ' ',(size - 1)); + if (compare_length > mData[mKeyVector].len) + { + memcpy(currentValue,compareTerm,mData[mKeyVector].len); + } + else + { + memcpy(currentValue,compareTerm,compare_length); + } + + // Compare the search term to the compare time + result = strcoll(searchTerm,currentValue); + + Wrapper_Utilities::deallocate(searchTerm); + Wrapper_Utilities::deallocate(currentValue); + + + // Set the result based upon the predicate operator + switch (mPredOperator) + { + //only support '=' + case SQL_EQ: + if (result == 0) + { + mResult = MATCH; + } + else + { + mResult = NO_MATCH; + } + break; + default: + rc = Wrapper_Utilities::report_error("FFQcmpst", + SQL_RC_E901, 1,strlen(BAD_PRED_OP),BAD_PRED_OP); + trace_error = 30; + goto error; + } + +exit: + Wrapper_Utilities::fnc_exit(118,"Sample_Query::compare(char*)", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(118,"Sample_Query::compare(char*)", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::compare() +* +* Function: This function is used to compare the search term to the key +* element from the selected row. This function is called when +* the key element is a decimal. +* +* Input: (nickname* , required) +* +* Output: rc = 0, success +* != 0, failure +* NOTE: +* +*****************************************************************************/ + +sqlint32 Sample_Query::compare(char *compareTerm, + int searchTermScale, + int searchTermPrecision) +{ + sqlint32 rc = 0; + sqlint32 trace_error = 0; + int compareTermScale = mData[mKeyVector].scale; + int compareTermPrecision = mData[mKeyVector].precision; + char *searchString = NULL; + char *compareString = NULL; + int searchSign = 0; + int compareSign = 0; + int result = 0; + + Wrapper_Utilities::fnc_entry(119,"Sample_Query::compare(decimal)"); + + // Build a stringified representation of the decimal number from the query + rc = Sample_Query::build_decimal_string(&searchString, mSearchTerm, searchTermScale, + searchTermPrecision, &searchSign); + if (rc) + { + trace_error = 10; + goto error; + } + + // Build a stringified representation of the decimal number from the data file + rc = Sample_Query::build_decimal_string(&compareString, compareTerm, compareTermScale, + compareTermPrecision, &compareSign); + if (rc) + { + trace_error = 20; + goto error; + } + + // if the signs of the two terms are not equal... + if (searchSign != compareSign) + { + switch(mPredOperator) + { + //only support '=' + case SQL_EQ: + mResult = NO_MATCH; + break; + default: + rc = Wrapper_Utilities::report_error("SQdcompde",SQL_RC_E901, 1, + strlen(BAD_PRED_OP),BAD_PRED_OP); + trace_error = 30; + goto error; + } + } + else // Both terms have the same sign + { // compare the query term with the data file term + result = strcoll(searchString,compareString); + + if (searchSign > 0) // If both are positive numbers... + { + switch(mPredOperator) + { + //only support '=' + case SQL_EQ: + if (result == 0) + { + mResult = MATCH; + } + else + { + mResult = NO_MATCH; + } + break; + default: + rc = Wrapper_Utilities::report_error("SQdcompde",SQL_RC_E901, 1, + strlen(BAD_PRED_OP),BAD_PRED_OP); + trace_error = 40; + goto error; + } + } + else // Both terms are negative numbers + { + //only supply '=' + switch(mPredOperator) + { + case SQL_EQ: + if (result == 0) + { + mResult = MATCH; + } + else + { + mResult = NO_MATCH; + } + break; + + default: + rc = Wrapper_Utilities::report_error("SQdcompde",SQL_RC_E901,1, + strlen(BAD_PRED_OP),BAD_PRED_OP); + trace_error = 50; + goto error; + } + } + } + + // Release the stringified versions of the numbers back to the system + Wrapper_Utilities::deallocate(searchString); + Wrapper_Utilities::deallocate(compareString); + +exit: + Wrapper_Utilities::fnc_exit(119,"Sample_Query::compare(decimal)", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(119,"Sample_Query::compare(decimal)", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/**************************************************************************** +* Function Name = Sample_Query::compare() +* +* Function: This function is used to compare the search term to the key +* element from the selected row. This function is called when +* the key element is a float. +* +* Input: (nickname* , required) +* +* Output: rc = 0, success +* != 0, failure +* NOTE: There is no way to be sure that the atof function worked +* properly. If the fuction fails the return result is +* undefined, but usually zero. +*****************************************************************************/ +sqlint32 Sample_Query::compare(float compareTerm) +{ + sqlint32 rc = 0; + sqlint32 trace_error = 0; + double tmpSearchTerm = 0.0; + float searchTerm = 0.0; + + Wrapper_Utilities::fnc_entry(120,"Sample_Query::compare(float)"); + + // Convert the search term to a double + errno = 0; + tmpSearchTerm = atof(mSearchTerm); + if ((errno == ERANGE) || (errno == EINVAL)) + { + rc = Wrapper_Utilities::report_error("SQdcompf", SQL_RC_E405, 1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 10; + goto error; + } + + //Verify that the search term is a valid single precision floating point + // number. + + if ((tmpSearchTerm != 0.0) && + ((fabs(tmpSearchTerm) < FLT_MIN) || (fabs(tmpSearchTerm) > FLT_MAX))) + { + rc = Wrapper_Utilities::report_error("SQdcompf", SQL_RC_E405,1, + strlen((const char *)mData[mKeyVector].name), + (const char *)mData[mKeyVector].name); + trace_error = 20; + goto error; + } + + searchTerm = (float)tmpSearchTerm; + + // Set the result based upon the predicate operator + switch (mPredOperator) + { + //only support '=' + case SQL_EQ: + if (searchTerm == compareTerm) + { + mResult = MATCH; + } + else + { + mResult = NO_MATCH; + } + break; + default: + rc = Wrapper_Utilities::report_error("SQdcompf", + SQL_RC_E901, 1,strlen(BAD_PRED_OP),BAD_PRED_OP); + trace_error = 30; + goto error; + break; + } + +exit: + Wrapper_Utilities::fnc_exit(120,"Sample_Query::compare(float)", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(120,"Sample_Query::compare(float)", + trace_error, sizeof(rc), &rc); + goto exit; +} + diff --git a/wrappers/wrapper_sdk/sample_operation.h b/wrappers/wrapper_sdk/sample_operation.h new file mode 100755 index 0000000..b5ab1aa --- /dev/null +++ b/wrappers/wrapper_sdk/sample_operation.h @@ -0,0 +1,134 @@ +/********************************************************************** +* +* Source File Name = sample_operation.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: sample operation related classes +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_OPERATION_H__ +#define __SAMPLE_OPERATION_H__ + +#include "sample_typedefs.h" + +#include "sqlqg_operation.h" +#include "sqlqg_utils.h" +#include "sqlqg_catalog.h" +#include "sqlcodes.h" +#include "sqlcli.h" +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// +// Sample_Query subclass +////////////////////////////////////////////////////////////////////////////// +enum result {NO_MATCH,MATCH}; + +class Sample_Query : public Remote_Query { +public: + // Constructor. + Sample_Query(Remote_Connection *active_connection, + Runtime_Operation *runtime_query, + sqlint32 *rc); + + // Destructor. + virtual ~Sample_Query(); + + // Runtime routines. + virtual sqlint32 open(); // opens a query. + virtual sqlint32 reopen(sqlint16 status); // reopens a query. + virtual sqlint32 fetch(); // fetches a row. + virtual sqlint32 close(sqlint16 status); // closes a query. + +protected: + + //////////////// + // Data. + //////////////// + int *mColumnVector; // Pointer to an array of integers + // that contain the offset to the + // selected data elements + columnData *mData; // Pointer to an array of columnData structures. + FILE *mFile; // File pointer for flat file + int mNumColumns; // Number of columns in the table + myboolean mFinished; // Used to signal the end of the search + char **mTokens; // Array to hold the tokenized column data + char *mBuffer; // Buffer hold a line of data. + void* mExecDesc; // To keep a copy of exec descriptor at open + + char *mSearchTerm; // Used to hold the predicate term + char mSearchTermBind[MAX_VARCHAR_LENGTH]; //Buffer to hold predicate term for unbound + relOperator mPredOperator; // Predicate operator '=' + int mKeyVector; // To record the column number + char* mFilePath; // Indicate the path of the file data + int mBindIndex; // To record the unbound index + result mResult; // Result of the search comparison. + + + //////////////// + // Methods. + //////////////// + sqlint32 build_data_area(int mNumColumns, columnData *mData); + sqlint32 table_scan(); + sqlint32 do_compare(); + sqlint32 compare(int); + sqlint32 compare(short); + sqlint32 compare(float); + sqlint32 compare(double); + sqlint32 compare(char *); + sqlint32 compare(char *,int,int); + sqlint32 save(char *, int); + sqlint32 build_decimal_string(char **, char *, int, int, int *); + sqlint32 get_data(); + sqlint32 pack(char *, char **); + sqlint32 format_packed_decimal(int,int,int); + sqlint32 tokenize(sqluint8 *buffer, int colCount, sqluint8 **tokens); + +}; + +////////////////////////////////////////////////////////////////////////////// +// Sample_Passthru subclass +////////////////////////////////////////////////////////////////////////////// + +class Sample_Passthru : public Remote_Passthru { +public: + // Constructor. + Sample_Passthru(Remote_Connection *active_connection, + Runtime_Operation* runtime_passthru, sqlint32 *rc); + // Destructor. + virtual ~Sample_Passthru(); + + // Runtime routines. + sqlint32 prepare(Runtime_Data_Desc_List*); // prepares a passthru + // session at a remote source. + sqlint32 describe(Runtime_Data_Desc_List *); // describes result set of a + // statement executed via a + // passthru session. + sqlint32 execute(); // executes a statement + // via a passthru session. + sqlint32 open(); // opens a cursor for + // a passthru session. + sqlint32 fetch(); // fetches a row from a + // passthru cursor. + sqlint32 close(); // closes a passthru cursor. + +protected: + + //////////////// + // Data. + //////////////// +}; + + + +#endif diff --git a/wrappers/wrapper_sdk/sample_portability.h b/wrappers/wrapper_sdk/sample_portability.h new file mode 100644 index 0000000..03a2dbf --- /dev/null +++ b/wrappers/wrapper_sdk/sample_portability.h @@ -0,0 +1,72 @@ +/********************************************************************** +* +* Source File Name = sample_portability.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: Macros used for portability +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_PORTABILITY_H__ +#define __SAMPLE_PORTABILITY_H__ + +#include +#define MAX_LINE_SIZE 32768 + +#ifdef SQLUNIX + +#include +#include +#include +#include + +#define NOT_READABLE_FILE(PATH) (access(PATH,R_OK) != 0) +#define CHECK_FILE_TYPE(PATH) (stat(PATH,&statBuffer)) +#define NON_STANDARD_FILE (S_ISDIR(statBuffer.st_mode) ||\ + S_ISFIFO(statBuffer.st_mode) ||\ + S_ISSOCK(statBuffer.st_mode)) +#define OPEN_FILE(PATH,FILE_PTR) (FILE_PTR = fopen(PATH,"r")) +#define OPEN_FAILED(FILE_PTR) (FILE_PTR == NULL ? 1 : 0) +#define FILE_SIZE (statBuffer.st_size); +#define END_OF_FILE(FILE_PTR) (feof(FILE_PTR)) +#define GET_A_RECORD(BUFFER, FILE_PTR) (fgets(BUFFER, MAX_LINE_SIZE, FILE_PTR)) +#define BUILD_ERROR_MESSAGE(MSG) (sprintf(MSG,"ERRNO = %d\0",errno)) +#define CLOSE_FILE(FILE_PTR) (fclose(FILE_PTR)) + + +#elif WIN32 + +#include +#include +#include +#include + +#define R_OK 4 + +#define NOT_READABLE_FILE(PATH) (access(PATH,R_OK) != 0) +#define CHECK_FILE_TYPE(PATH) (stat(PATH,&statBuffer)) +#define NON_STANDARD_FILE (((_S_IFDIR)&(statBuffer.st_mode)) ||\ + ((_S_IFIFO)&(statBuffer.st_mode)) ||\ + ((_S_IFCHR)&(statBuffer.st_mode))) +#define OPEN_FILE(PATH, FILE_PTR) (FILE_PTR = fopen(PATH,"r")) +#define OPEN_FAILED(FILE_PTR) (FILE_PTR == NULL ? 1 : 0) +#define FILE_SIZE (statBuffer.st_size); +#define END_OF_FILE(FILE_PTR) (feof(FILE_PTR)) +#define GET_A_RECORD(BUFFER,FILE_PTR) (fgets(BUFFER, MAX_LINE_SIZE, FILE_PTR)) +#define BUILD_ERROR_MESSAGE(MSG) (sprintf(MSG,"ERRNO = %d\0",errno)) +#define CLOSE_FILE(FILE_PTR) (fclose(FILE_PTR)) + +#endif + +#if defined (WIN32) || defined (SQLSUN) || defined (SQLLinux) || defined (HPUX) +#include +#endif + +#endif diff --git a/wrappers/wrapper_sdk/sample_server.C b/wrappers/wrapper_sdk/sample_server.C new file mode 100755 index 0000000..db9d6d1 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_server.C @@ -0,0 +1,1054 @@ +/********************************************************************** +* +* Source File Name = sample_server.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for unfenced sample server class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_server.h" +#include "sample_wrapper.h" +#include "sample_utilities.h" +#include "sample_error_reporting.h" + +#include "sqlqg_catalog.h" +#include "sqlqg_utils.h" +#include "sqlcodes.h" +#include "sqlqg_request.h" +#include "sqlqg_runtime_data_operation.h" +#include +#include + +class Unfenced_Generic_Nickname; + +/************************************************************************** +* +* Function Name = Sample_Server::Sample_Server +* +* Function: Sample Server Constructor +* +* Dependencies: +* +* Restrictions: +* +* Input: sqluint8 *server_name +* Wrapper *server_wrapper +* +* Output: sqlint32 *rc +* +* Normal Return = rc = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +Sample_Server::Sample_Server(sqluint8* server_name, UnfencedWrapper* server_wrapper, + sqlint32* rc) + : Unfenced_Generic_Server(server_name, server_wrapper, rc) +{ + Wrapper_Utilities::fnc_entry(10,"Sample_Server::Sample_Server"); + Wrapper_Utilities::fnc_exit(10,"Sample_Server::Sample_Server", *rc); +} + +/************************************************************************** +* +* Function Name = Sample_Server::~Sample_Server +* +* Function: Sample Server Destructor +* +* Dependencies: +* +* Restrictions: +* +* Input: N/A +* +* Output: N/A +* +* Normal Return = N/A +* +* Error Return = N/A +* +**************************************************************************/ +Sample_Server::~Sample_Server() +{ + Wrapper_Utilities::fnc_entry(11,"Sample_Server::~Sample_Server"); + Wrapper_Utilities::fnc_exit(11,"Sample_Server::~Sample_Server", 0); +} + +/************************************************************************** +* +* Function Name = Sample_Server::verify_my_register_server_info() +* +* Function: Check server info for validity for servers. +* This function verifies that info specified on a CREATE SERVER +* DDL statement is correct. +* This wrapper accepts only the following for of CREATE SERVER: +* CREATE SERVER WRAPPER +* No type and no version are allowed for this wrapper +* +* Dependencies: +* +* Restrictions: +* +* Input: Server_Info *server_info: catalog information about server. +* +* Output: Server_Info **delta_info: any additional information to be +* stored about the server. +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Server::verify_my_register_server_info(Server_Info* server_info, + Server_Info** delta_info) +{ + sqlint32 rc = 0; + char *func_name = "SS_VMR"; // for the error macro + sqluint8 *server_type = NULL; + sqluint8 *serverVersion = NULL; + Catalog_Option *option = NULL; + sqluint8 *option_name = NULL; + sqluint8 *server_name = NULL; + + Wrapper_Utilities::fnc_entry(12,"Sample_Server::verify_my_register_server_info"); + // The sample wrapper doesn't require any option of its own but might accept an option + // if it is known to be a DB2 option. + + // Get the TYPE of server + rc = server_info->get_server_type(&server_type); + + // The sample wrapper doesn't require the server_type when creating the server. + // an rc of SQLQG_NOVALUE means that the srever_type wasn't set. + + switch (rc) + { + case SQLQG_NOVALUE : + { + rc = 0; + break; + } + default : + { + Wrapper *wrapper = this->get_wrapper(); + sqluint8 *wrapperName = wrapper->get_name(); + + rc = Wrapper_Utilities::report_error(func_name, SQL_RC_E1816, 3, + strlen((const char *)wrapperName),(const char *)wrapperName, + strlen("type"),"type", + strlen((const char *)server_type),(const char *)server_type); + + Wrapper_Utilities::fnc_data2(12,"Sample_Server::verify_my_register_server_info", 10, + strlen((char *)wrapperName), (char *)wrapperName, + strlen((const char *)server_type), (const char *)server_type); + + Wrapper_Utilities::trace_error(12,"Sample_Server::verify_my_register_server_info", + 10, sizeof(rc), &rc); + goto exit; + } + } + + // Get the VERSION of server + rc = server_info->get_server_version(&serverVersion); + + // The sample wrapper doesn't require the serverVersion when creating the server. + // an rc of SQLQG_NOVALUE means that the sreverVersion wasn't set. + + switch (rc) + { + case SQLQG_NOVALUE : + { + rc = 0; + break; + } + default : + { + Wrapper *wrapper = this->get_wrapper(); + sqluint8 *wrapperName = wrapper->get_name(); + + rc = Wrapper_Utilities::report_error(func_name, SQL_RC_E1816, 3, + strlen((const char *)wrapperName),(const char *)wrapperName, + strlen("version"),"version", + strlen((const char *)serverVersion),(const char *)serverVersion); + Wrapper_Utilities::fnc_data2(12,"Sample_Server::verify_my_register_server_info", 20, + strlen((char *)wrapperName), (char *)wrapperName, + strlen((char *)serverVersion), (char *)serverVersion); + + Wrapper_Utilities::trace_error(12,"Sample_Server::verify_my_register_server_info", + 20, sizeof(rc), &rc); + + goto exit; + } + } + + // verify that the options are known to db2. + + option = server_info->get_first_option(); + while (option != NULL) + { + option_name = option->get_name(); + if (!is_reserved_server_option(option_name)) + { + server_info->get_server_name(&server_name); + rc = Wrapper_Utilities::report_error(func_name, SQL_RC_E1881, 3, + strlen((char *)option_name), option_name, + strlen(SQLQG_SERVER_OPTION), SQLQG_SERVER_OPTION, + strlen((char *)server_name), server_name); + + Wrapper_Utilities::fnc_data2(12,"Sample_Server::verify_my_register_server_info", 30, + strlen((char *)option_name), (char *)option_name, + strlen((char *)server_name), (char *)server_name); + + Wrapper_Utilities::trace_error(12,"Sample_Server::verify_my_register_server_info", + 30, sizeof(rc), &rc); + + goto exit; + } + option = server_info->get_next_option(option); + } + +exit: + Wrapper_Utilities::fnc_exit(12,"Sample_Server::verify_my_register_server_info", rc); + return rc; + +} + +/************************************************************************** +* +* Function Name = Sample_Server::verify_my_alter_server_info() +* +* Function: Check server info for validity for server. +* This function verifies that info specified on a CREATE SERVER +* DDL statement is correct. +* +* Dependencies: +* +* Restrictions: +* +* Input: Server_Info *server_info: catalog information about server. +* +* Output: Server_Info **delta_info: any additional information to be +* stored about the server. +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +sqlint32 Sample_Server::verify_my_alter_server_info(Server_Info* server_info, + Server_Info** delta_info) +{ + sqlint32 rc = 0; + char *func_name = "SS_VMA"; // for the error macro + sqluint8 *server_type = NULL; + sqluint8 *serverVersion = NULL; + Catalog_Option *option = NULL; + sqluint8 *option_name=NULL; + sqluint8 *server_name=NULL; + + Wrapper_Utilities::fnc_entry(13,"Sample_Server::verify_my_alter_server_info"); + // The sample wrapper doesn't require any option of its own but might accept an option + // if it is known to be a DB2 option. + + // Get the TYPE of server + + rc = server_info->get_server_type(&server_type); + + // The sample wrapper doesn't require the server_type when creating the server. + // an rc of SQLQG_NOVALUE means that the srever_type wasn't set. + + switch (rc) + { + case SQLQG_NOVALUE : + { + rc = 0; + break; + } + default : + { + Wrapper *wrapper = this->get_wrapper(); + sqluint8 *wrapperName = wrapper->get_name(); + + rc = Wrapper_Utilities::report_error(func_name, SQL_RC_E1816, 3, + strlen((const char *)wrapperName), (const char *)wrapperName, + strlen("type"),"type", + strlen((const char *)server_type),(const char *)server_type); + + Wrapper_Utilities::fnc_data2(13,"Sample_Server::verify_my_alter_server_info", 40, + strlen((char *)wrapperName), (char *)wrapperName, + strlen((char *)server_type), (char *)server_type); + + Wrapper_Utilities::trace_error(13,"Sample_Server::verify_my_alter_server_info", + 40, sizeof(rc), &rc); + goto exit; + } + } + + // Get the VERSION of server + rc = server_info->get_server_version(&serverVersion); + + // The sample wrapper doesn't require the serverVersion when creating the server. + // an rc of SQLQG_NOVALUE means that the sreverVersion wasn't set. + + switch (rc) + { + case SQLQG_NOVALUE : + { + rc = 0; + break; + } + default : + { + Wrapper *wrapper = this->get_wrapper(); + sqluint8 *wrapperName = wrapper->get_name(); + + rc = Wrapper_Utilities::report_error(func_name, SQL_RC_E1816, 3, + strlen((const char *)wrapperName),(const char *)wrapperName, + strlen("version"),"version", + strlen((const char *)serverVersion),(const char *)serverVersion); + + Wrapper_Utilities::fnc_data2(13,"Sample_Server::verify_my_alter_server_info", 50, + strlen((char *)wrapperName), (char *)wrapperName, + strlen((char *)serverVersion), (char *)serverVersion); + + Wrapper_Utilities::trace_error(13,"Sample_Server::verify_my_alter_server_info", + 50, sizeof(rc), &rc); + goto exit; + + } + } + + // verify that the options are known to db2. + + option = server_info->get_first_option(); + while (option != NULL) + { + option_name = option->get_name(); + if (!is_reserved_server_option(option_name)) + { + server_info->get_server_name(&server_name); + rc = Wrapper_Utilities::report_error(func_name, SQL_RC_E1881, 3, + strlen((char *)option_name), option_name, + strlen(SQLQG_SERVER_OPTION), SQLQG_SERVER_OPTION, + strlen((char *)server_name), server_name); + + Wrapper_Utilities::fnc_data2(13,"Sample_Server::verify_my_alter_server_info", 60, + strlen((char *)option_name), (char *)option_name, + strlen((char *)server_name), (char *)server_name); + + Wrapper_Utilities::trace_error(13,"Sample_Server::verify_my_alter_server_info", + 60, sizeof(rc), &rc); + goto exit; + } + option = server_info->get_next_option(option); + } + +exit: + Wrapper_Utilities::fnc_exit(13,"Sample_Server::verify_my_alter_server_info", rc); + return rc; + +} + + +/************************************************************************** +* +* Function Name = Sample_Server::create_nickname() +* +* Function: Method to construct new nickname for a server. +* +* Input: sqluint8* name: name of nickname +* Server* server: server with which nickame is associated. +* +* Output: Remote_Nickname** nickname: newly created nickname +* +* Normal Return = 0 +* +* Error Return = +* +**************************************************************************/ +Nickname* Sample_Server::create_nickname(sqluint8 *schema_name, + sqluint8 *nickname_name, + sqlint32 *xrc) +{ + sqlint32 rc=0; + Sample_Nickname *n = NULL; + Wrapper_Utilities::fnc_entry(14,"Sample_Server::create_nickname"); + + // Create an instance of the Sample Nickname subclass + n = new (&rc) Sample_Nickname(schema_name, nickname_name, this, &rc); + if(rc!=0) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", + 70, "SS_CN"); + Wrapper_Utilities::trace_error(14,"Sample_Server::create_nickname", + 70, sizeof(rc), &rc); + } + + *xrc = rc; + Wrapper_Utilities::fnc_exit(14,"Sample_Server::create_nickname", rc); + return(n); +} + + +/************************************************************************** +* +* Function Name = Sample_Server::plan_request() +* +* Function: Generates a reply and execution description +* +* Input: Request +* +* Output: Reply +* +* Normal Return = 0 +* +* Error Return = non 0 +* +**************************************************************************/ +sqlint32 Sample_Server::plan_request(Request *rq, Reply **rep) +{ + sqlint32 rc = 0; + sqlint32 trace_error = 0; + char *column_name = NULL; + char *exec_desc = NULL; + char *curr_ptr = NULL; // these cannot be void - need pointer arithmetics + char *filePath = NULL; + char *token = NULL; + char *SearchTerm = NULL; + char seatch_term_const[MAX_VARCHAR_LENGTH]; + int i = 0; + int l = 0; + int len = 0; + int KeyVector = 0; + char *KeyColumn = NULL; + int KeyColumlen = 0; + int ColumnVectorSize = 0; + int handle = 0; + int index = 0; + int NumColumns = 0; + int NumPredicts = 0; + int *ColumnVector = NULL; + sqlint32 SearchTermLen = 0; + int BindIndex = -1; + int UnboundIndex = 0; + Sample_Nickname *nickname = NULL; + Nickname_Info *nickname_info = NULL; + relOperator PredOperator = ALL_ROWS; + Request_Exp *rExp = NULL; + Request_Exp::kind c1k, c2k, arg_kind, rExp_kind; + Request_Exp *c1p = NULL, *c2p = NULL, *argP = NULL, *columnP = NULL; + Sample_Exec_Descriptor *fedsP = NULL; + Request_Constant *value = NULL; + columnData *Data = NULL; + Unfenced_Generic_Nickname *gu_nickname = NULL; + char *func_name = "SS_PR"; // for the error macro + + + Wrapper_Utilities::fnc_entry(15,"Sample_Server::plan_request"); + *rep = NULL; //No plan done yet + + if (rq == NULL) //sanity check + { + rc = sample_report_error_1822(rc, "Internal error: Request not recieved.", 100, func_name); + trace_error = 100; + goto exit; + + } + + // No parameters and joins! Only 1 nickname at a time + if( rq->get_number_of_quantifiers() > 1) + { + goto exit; //Success - it is not an error when the wrapper returns no plan. + } + + rc = create_reply(rq, rep); //Create new reply + if (rc) + { + trace_error = 110; + goto error; + } + + if (rep == NULL) //sanity check + { + rc = sample_report_error_1822(rc, "Internal error: Create reply failed.", 120, func_name); + trace_error = 120; + goto error; + } + +//////////////////////////////////////////////////////////////////////////////// +// NICKNAMES in the FROM clause, and misc preparations +//////////////////////////////////////////////////////////////////////////////// + +// Take care only of the first quantifier, ignore the rest + rc = rq->get_quantifier_handle(1, &handle); + if (rc) + { + trace_error = 130; + goto error; + } + + rc = rq->get_nickname(handle, &gu_nickname); + if (rc) + { + trace_error = 140; + goto error; + } + + nickname = (Sample_Nickname*) gu_nickname; + if (nickname == NULL) //Table function + { + goto exit; //Cannot handle table functions.. + } + + rc = (*rep)->add_quantifier(handle); + if (rc) + { + trace_error = 150; + goto error; + } + + // Get the path to the data file, if null return an error to DB2 + rc = nickname->get_file_path((sqluint8 **)&filePath); + if (rc) + { + trace_error = 160; + goto error; + } + + if (filePath == NULL) // sanity check + { + rc = Wrapper_Utilities::report_error(func_name, + SQL_RC_E901, 1,strlen(NULL_PATH), NULL_PATH); + trace_error = 170; + goto error; + } + + Wrapper_Utilities::fnc_data(15,"Sample_Server::plan_request", 175, + strlen(filePath), filePath); + // Get a reference for the nickname_info object. This is used to find out + // information about data source. + rc = nickname->get_nickname_info(&nickname_info); + + if ((rc != 0) || (nickname_info == NULL)) //sanity check + { + rc = sample_report_error_1822(rc, "Internal error: Failed in getting nickname info.", + 180, func_name); + trace_error = 180; + goto exit; + } + + // Save the number of columns in this data source. This is used to determine the + // size of the token and columnData arrays. It will also be used to calculate the + // minimum row size which will be used by various searching functions. + NumColumns = nickname_info->get_number_columns(); + + //Prepare the return buffers info - no alloc here, that is done during 'open' + rc = prepare_data_area(nickname_info, Data, NumColumns); + if (rc) + { + trace_error = 190; + goto error; + } + + +//////////////////////////////////////////////////////////////////////////////// +// PREDICATES +//////////////////////////////////////////////////////////////////////////////// + // This wrapper only handle predicates like column='cst' or 'cst'=column + // or column = unbound or unbound = column + // and only support one predicate + NumPredicts=rq->get_number_of_predicates(); + + //We only support one predicate, choose one that is valid for our conditions from all predicates + for( i=1; i <= NumPredicts; i++) + { + //get the predicate + rc = rq->get_predicate_handle(i, &handle); + if (rc) + { + trace_error = 210; + goto error; + } + + rc = rq->get_predicate(handle, &rExp); + if (rc) + { + trace_error = 220; + goto error; + } + + rc = rExp->get_kind(rq, &rExp_kind); + if (rc) + { + trace_error = 230; + goto error; + } + + //We like only predicates that have an operator and 2 children + if (rExp_kind == Request_Exp::oper && rExp->get_number_of_children() == 2) + { + rExp->get_token(&token, &len); + //can be used only in conjunction with '=' operator + if( len == 1 && token[0] == '=' ) + { + //Get the operands + c1p = rExp->get_first_child(); + c2p = c1p->get_next_child(); + + //Get the kinds of the operands + rc = c1p->get_kind(rq, &c1k); + if (rc) + { + trace_error = 250; + goto error; + } + rc = c2p->get_kind(rq, &c2k); + if (rc) + { + trace_error = 260; + goto error; + } + + // predicates of form column = 'cst' or 'cst' = column or unbound = column + // or column = unbound only + if(c1k == Request_Exp::column && + (c2k == Request_Exp::constant || c2k == Request_Exp::unbound)) + { + columnP = c1p; argP = c2p; arg_kind = c2k; + } + else if(c2k == Request_Exp::column && + (c1k == Request_Exp::constant || c1k == Request_Exp::unbound)) + { + columnP = c2p; argP = c1p; arg_kind = c1k; + } + else + { + continue; + } + + KeyVector = -1; + rc = columnP->get_column_name((char **)&KeyColumn,&KeyColumlen); + + if (rc) + { + trace_error = 270; + goto error; + } + + //Get the number of the column + for (i=0; i < NumColumns; i++) + { + if (strncmp(KeyColumn,(const char *)Data[i].name,KeyColumlen) == 0) + { + KeyVector = i; + break; + } + } + + //Can not find the column name + if(KeyVector<0) + { + rc = Wrapper_Utilities::report_error(func_name, + SQL_RC_W206, 1,strlen(BAD_COLUMN), BAD_COLUMN); + trace_error = 280; + goto error; + } + + //Get the value of the constant + if(arg_kind == Request_Exp::constant) //form column = 'cst' or 'cst' = column + { + rc = argP->get_value(&value); + if (rc) + { + trace_error = 290; + goto error; + } + + memset(seatch_term_const,'\0', MAX_VARCHAR_LENGTH); + SearchTerm = seatch_term_const; + rc = Sample_Utilities::convert_data( + value->get_data_type(), + value->get_data(), + value->get_actual_length (), + value->get_precision (), + value->get_scale (), + SearchTerm, + &SearchTermLen); + if (rc) + { + trace_error = 300; + goto error; + } + } + else //form column = unbound or unbound = column + { + BindIndex = UnboundIndex++; + } + + + //Add the predicate to the reply + rc = (*rep)->add_predicate(handle); + if (rc) + { + trace_error = 320; + goto error; + } + + PredOperator = SQL_EQ; + break; + } + } + } +//////////////////////////////////////////////////////////////////////////////// +// HEAD EXPRESSIONS +//////////////////////////////////////////////////////////////////////////////// + + // Allocate space for the column vector array. This is an array of integers. + // Each integer represents the relative position of the column requested by + // DB2 (relative to zero). The array is terminated by -1. + + ColumnVectorSize = NumColumns+1; + + rc = Wrapper_Utilities::allocate(sizeof(int) * (ColumnVectorSize + 1), + (void **)&ColumnVector); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 340, func_name); + trace_error = 340; + goto exit; + } + + // Initialize the column vectors to -1 + for (i = 0; i <= ColumnVectorSize; i++) + { + ColumnVector[i] = -1; + } + + + // Build the column vector array. Get the name of each column request by the DB2 + // query. Loop thru the column data array looking for the matching column name. + // When found store in the column vector the relative position of the requested + // column in the column data array. + + for(i=1; i <= rq->get_number_of_head_exp(); i++) + { + rc = rq->get_head_exp_handle(i, &handle); + if (rc) + { + trace_error = 350; + goto error; + } + rc = rq->get_head_exp(handle, &rExp); + if (rc) + { + trace_error = 360; + goto error; + } + //Take care only of the columns + if(rExp != NULL) + { + rc = rExp->get_kind(rq, &rExp_kind); + if (rc) + { + trace_error = 370; + goto error; + } + } + + if(rExp != NULL && rExp_kind == Request_Exp::column) + { + // add this column to the reply + rc = rq->get_head_exp_handle(i, &handle); + if (rc) + { + trace_error = 380; + goto error; + } + rc = (*rep)->add_head_exp(handle); + if (rc) + { + trace_error = 390; + goto error; + } + + //get the name of the column and its length + rExp->get_column_name(&column_name, &len); + + Wrapper_Utilities::fnc_data2(15,"Sample_Server::plan_request", 400, + strlen(column_name), column_name, + sizeof(len), &len); + + for (l = 0; l < NumColumns; l++) + { + if ( (strncmp(column_name,(char *)Data[l].name, len) == 0) && + (len == (int) strlen((char *)Data[l].name)) ) + { + ColumnVector[i-1] = l; + break; + } + } + if (ColumnVector[i-1] == -1) + { + rc = sample_report_error_1822(rc, BAD_COLUMN, 410, func_name); + trace_error = 410; + goto exit; + } + } + } + +//////////////////////////////////////////////////////////////////////////////// +// PACKING +//////////////////////////////////////////////////////////////////////////////// + + //Packing of the execution descriptor in a continuous memory block + //The fixed length pieces are stored as parts of a structure of + //type Sample_Exec_Descriptor. The variable size pieces are stored after this struct + + + //Determine the total length + len = sizeof(Sample_Exec_Descriptor) + //The Sample_Exec_Descriptor instance + sizeof(int) * (NumColumns + 1) + //The size of mColumnVector + sizeof(columnData) * NumColumns + //Size of the columnData vector + strlen(filePath) + 1 + //The file path string + SearchTermLen + 1; //SearchTermLen string + + //allocate the memory + rc = Wrapper_Utilities::allocate(len, (void**) &exec_desc); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 420, func_name); + trace_error = 420; + goto exit; + } + + (*rep)->set_exec_desc(exec_desc, len); + + //set the fixed length pieces of the execution descriptor + fedsP = (Sample_Exec_Descriptor*) exec_desc; + fedsP->mNumColumns = NumColumns; + fedsP->mPredOperator = PredOperator; + fedsP->mKeyVector = KeyVector; + fedsP->mBindIndex = BindIndex; + + + //store the variable length pieces + curr_ptr = exec_desc + sizeof(Sample_Exec_Descriptor); + store_and_advance(curr_ptr, ColumnVector, sizeof(int) * (NumColumns + 1)); + store_and_advance(curr_ptr, Data, sizeof(columnData) * NumColumns); + store_and_advance(curr_ptr, filePath, strlen(filePath)+1); + + if(SearchTerm) + { + store_and_advance(curr_ptr, SearchTerm, SearchTermLen); + *((char *)curr_ptr) = '\0'; //null terminate SearchTerm + } + + //delete the allocated storage + Wrapper_Utilities::deallocate(ColumnVector); + Wrapper_Utilities::deallocate(Data); + +exit: + //exit + Wrapper_Utilities::fnc_exit(15,"Sample_Server::plan_request", rc); + return rc; + + +error: + //report error and goto exit + Wrapper_Utilities::trace_error(15,"Sample_Server::plan_request", + trace_error, sizeof(rc), &rc); + goto exit; + +} + + +/**************************************************************************** +* Function Name = Sample_Server::store_and_advance() +* +* Function: Stores a memory block into the execution handle descriptor +* +* +* +* Input: source pointer, target pointer and length +* +* Output: the targed pointer advanced for the length +*****************************************************************************/ +inline void +Sample_Server::store_and_advance(char* &curr_ptr, void *source_ptr,int len) +{ + memcpy(curr_ptr, source_ptr, len); + curr_ptr+=len; +} + +/**************************************************************************** +* Function Name = Sample_Server::prepare_data_area() +* +* Function: This function will prepare the column data array based on information +* found in the nickname_info object. At this point no buffers allocated +* +* +* Input: (nickname* , required) +* +* Output: rc = 0, success +* != 0, failure +*****************************************************************************/ +sqlint32 Sample_Server::prepare_data_area(Nickname_Info *nickname_info, columnData* &Data, + int mNumColumns) +{ + Column_Info *columnInfo = NULL; + sqlint32 rc = 0; + sqlint32 trace_error = 0; + sqlint32 i = 0; + sqluint8 *sqlType = NULL; + + Wrapper_Utilities::fnc_entry(16,"Sample_Server::prepare_data_area"); + // Allocate space for an array of columnData items + // (1 for each column in the pseudo-table) + rc = Wrapper_Utilities::allocate((sizeof(columnData) * mNumColumns), + (void **)&Data); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 300, "SS_PDA"); + trace_error = 300; + goto error; + } + + // Get the columnInfo for the first column. Save the column attributes (name, + // length, and sql type in the column data array. Repeat this + // process for each column in the pseudo-table. + columnInfo = nickname_info->get_first_column(); + + if (columnInfo == NULL) + { + rc = Wrapper_Utilities::report_error("SS_PDA", + SQL_RC_E901, 1, strlen(COLUMN_ERROR), COLUMN_ERROR); + trace_error = 310; + goto error; + } + + while (columnInfo != NULL) + { + // Save the column name + rc = columnInfo->get_column_name(&Data[i].name); + if (rc) + { + trace_error = 320; + goto error; + } + // Save the column length + rc = columnInfo->get_org_length(&Data[i].len); + if (rc) + { + trace_error = 330; + goto error; + } + // Get the sql data type name + rc = columnInfo->get_type_name(&sqlType); + if (rc) + { + trace_error = 340; + goto error; + } + Wrapper_Utilities::fnc_data3(16,"Sample_Server::prepare_data_area", 345, + strlen((const char*)Data[i].name), (const char *)Data[i].name, + sizeof(Data[i].len), &Data[i].len, + strlen((const char *)sqlType), (const char *)sqlType); + + // If the data type is INTEGER + if (strcmp((char *)sqlType,"INTEGER") == 0) + { + Data[i].type = SQL_INTEGER; + } + else + // If the data type is DOUBLE + if (strcmp((char *)sqlType,"DOUBLE") == 0) + { + Data[i].type = SQL_DOUBLE; + } + else + // If the data type is DECIMAL + if (strcmp((char *)sqlType,"DECIMAL") == 0) + { + Data[i].type = SQL_DECIMAL; + sqlint16 scale = 0; + rc = columnInfo->get_org_scale(&scale); + if (rc) + { + trace_error = 350; + goto error; + } + Data[i].scale = scale; + rc = columnInfo->get_org_length((sqlint32 *)&Data[i].precision); + if (rc) + { + trace_error = 360; + goto error; + } + } + else + // If the data type is CHAR + if (strcmp((char *)sqlType,"CHARACTER") == 0) + { + Data[i].type = SQL_CHAR; + } + else + if (strcmp((char *)sqlType,"VARCHAR") == 0) + { + Data[i].type = SQL_VARCHAR; + } + else + { + // sanity check + rc = sample_report_error_1822(rc, "Wrong column data type", 370, "SS_PDA"); + Wrapper_Utilities::trace_error(16,"Sample_Server::prepare_data_area", + 370, sizeof(rc), &rc); + goto error; + } + + // Get the next column + columnInfo = nickname_info->get_next_column(columnInfo); + i++; + } + +exit: + Wrapper_Utilities::fnc_exit(16,"Sample_Server::prepare_data_area", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(16,"Sample_Server::prepare_data_area", + trace_error, sizeof(rc), &rc); + goto exit; +} + +sqlint32 Sample_Server::null_terminate(char *instring, int len, char** outstring) +{ + sqlint32 rc = 0; + + char *null_term_buff = NULL; + Wrapper_Utilities::fnc_entry(17,"Sample_Server::null_terminate"); + + rc = Wrapper_Utilities::allocate(len+1, (void **) &null_term_buff); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", 400, "SS_NT"); + Wrapper_Utilities::trace_error(17,"Sample_Server::null_terminate", + 400, sizeof(rc), &rc); + goto exit; + } + + strncpy(null_term_buff, instring, len); + null_term_buff[len] = '\0'; + *outstring = null_term_buff; + +exit: + Wrapper_Utilities::fnc_exit(17,"Sample_Server::null_terminate", rc); + return(rc); + +} diff --git a/wrappers/wrapper_sdk/sample_server.h b/wrappers/wrapper_sdk/sample_server.h new file mode 100755 index 0000000..defc67d --- /dev/null +++ b/wrappers/wrapper_sdk/sample_server.h @@ -0,0 +1,84 @@ +/********************************************************************** +* +* Source File Name = sample_server.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: unfenced sample server subclass +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_SERVER_H__ +#define __SAMPLE_SERVER_H__ + +#include "sample_typedefs.h" +#include "sample_nickname.h" +#include "sqlqg_unfenced_generic_server.h" +#include "sqlqg_fenced_user.h" + +class Remote_Connection; +class Runtime_Data; +class Request; +class Reply; +class Request_Exp_Type; +class Request_Exp; +class Request_Constant; + +////////////////////////////////////////////////////////////////////////////// +// Sample Server class +///////////////////////////////////////////////////////////////////////////// +class Sample_Server : public Unfenced_Generic_Server +{ +public: + + // Constructor. + Sample_Server(sqluint8* server_name, UnfencedWrapper* server_wrapper, sqlint32 *rc); + + // Destructor. + virtual ~Sample_Server(); + + // Verifies options, local type mappings, remote function mappings + // specified on CREATE SERVER statement. + virtual sqlint32 verify_my_register_server_info(Server_Info* catalog_info, + Server_Info** delta_info); + + // Verifies options, local type mappings, remote function mappings + // specified on ALTER SERVER statement. + virtual sqlint32 verify_my_alter_server_info(Server_Info* catalog_info, + Server_Info** delta_info); + // Plan a request and return a reply + virtual sqlint32 plan_request(Request *rq, Reply **rep); + + +protected: + //////////////// + // Data. + //////////////// + + + //////////////// + // Methods. + //////////////// + + // Create instance of Sample_Nickname subclass. + virtual Nickname* create_nickname(sqluint8 *schema_name, + sqluint8 *name, + sqlint32 *rc); + + //stores a block of memory into the execution descriptor + inline void store_and_advance(char*&,void*,int); + + //Sets the types and the lengths of the data buffers, but does not allocate anything + sqlint32 prepare_data_area(Nickname_Info *nickname_info, columnData* &Data, int NumColumns); + + // Allocate, copy and null terminate a string + sqlint32 null_terminate(char *instr, int len, char** outstring); +}; + +#endif diff --git a/wrappers/wrapper_sdk/sample_typedefs.h b/wrappers/wrapper_sdk/sample_typedefs.h new file mode 100644 index 0000000..7989643 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_typedefs.h @@ -0,0 +1,78 @@ +/********************************************************************** +* +* Source File Name = sample_typedef.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining:Structures and macros used in sample wrapper +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_TYPEDEFS_H__ +#define __SAMPLE_TYPEDEFS_H__ + +#include "sqlcli.h" + + +// Wrapper Defines +#define SAMPLE_WRAPPER_TYPE 'N' // 'N' For Non-Relational (Generic) +#define SAMPLE_WRAPPER_VERSION 1 + +// Nickname Defines +#define FILE_PATH_OPTION "FILE_PATH" + +// Misc. Defines +#define NULL_WRAPPER "Cannot get wrapper object" +#define NULL_PATH "Data source path is NULL" +#define LSTAT_ERROR "STAT Failed on data source" +#define COLUMN_ERROR "No column info found" +#define ACCESS_ERROR "Unable to read file" +#define DATA_ERROR "Data Error" +#define NOT_FILE_ERROR "Data source is a non-standard file" +#define OPEN_ERROR "File open error" +#define BAD_PRED_OP "Unsupported operator" +#define BAD_COLUMN "Column not found" +#define KEY_EXCEEDS_SIZE "Key exceeds definition size" +#define FILE_SIZE_ERROR "Line in data file exceeds 32k" + +// Constants +#define MAX_DECIMAL_SIZE 34 +#define MAX_VARCHAR_LENGTH 32672 + +// enums and structs needed by the different classes. + +enum myboolean {NO,YES}; + + +struct columnData +{ + sqlint32 type; // This structure is used to + sqluint8 *name; // contain the information about + void *data; // a data element + sqlint32 len; + int precision; // Used with decimal data type + int scale; // Used with decimal data type +}; + +enum relOperator +{ + SQL_EQ, + ALL_ROWS +}; + +// This is a subset of Sample_Query that is generated by plan_request() +struct Sample_Exec_Descriptor +{ + relOperator mPredOperator; + int mNumColumns; + int mKeyVector; + int mBindIndex; +}; + +#endif diff --git a/wrappers/wrapper_sdk/sample_user.C b/wrappers/wrapper_sdk/sample_user.C new file mode 100755 index 0000000..587e39d --- /dev/null +++ b/wrappers/wrapper_sdk/sample_user.C @@ -0,0 +1,68 @@ +/********************************************************************** +* +* Source File Name = sample_user.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for unfenced sample user class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_user.h" +#include "sqlqg_utils.h" + +/************************************************************************** +* +* Function Name = Sample_User::Sample_User +* +* Function: Sample_User class constructor +* +* Dependencies: +* +* Restrictions: +* +* Input: sqluint8* local_user_name: local authid of user. +* User_Info* user_info: catalog info +* UnfencedServer* user_server: server associated with user +* +* Output: (required) sqlint32 *rc - return code +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +Sample_User::Sample_User(sqluint8* local_user_name, UnfencedServer* user_server, + sqlint32 *rc) + :UnfencedRemote_User(local_user_name, user_server, rc) +{ + Wrapper_Utilities::fnc_entry(20,"Sample_User::Sample_User"); + Wrapper_Utilities::fnc_exit(20,"Sample_User::Sample_User", *rc); +} + +/************************************************************************** +* +* Function Name = Sample_User::~Sample_User +* +* Function: Sample_User class destructor +* +* Dependencies: +* +* Restrictions: +* +* Input: none +* +* Output: none +* +**************************************************************************/ +Sample_User::~Sample_User() +{ + Wrapper_Utilities::fnc_entry(21,"Sample_User::~Sample_User"); + Wrapper_Utilities::fnc_exit(21,"Sample_User::~Sample_User", 0); +} diff --git a/wrappers/wrapper_sdk/sample_user.h b/wrappers/wrapper_sdk/sample_user.h new file mode 100755 index 0000000..8835deb --- /dev/null +++ b/wrappers/wrapper_sdk/sample_user.h @@ -0,0 +1,38 @@ +/********************************************************************** +* +* Source File Name = sample_user.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: unfenced sample user subclass +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_USER_H__ +#define __SAMPLE_USER_H__ + +#include "sqlqg_unfenced_user.h" + +////////////////////////////////////////////////////////////////////////////// +// Sample_User class definition +////////////////////////////////////////////////////////////////////////////// +class Sample_User : public UnfencedRemote_User { +public: + // Constructor. + Sample_User(sqluint8* local_user_name, UnfencedServer* user_server, sqlint32 *rc); + + // Destructor. + virtual ~Sample_User(); + +protected: + + +}; + +#endif diff --git a/wrappers/wrapper_sdk/sample_utilities.C b/wrappers/wrapper_sdk/sample_utilities.C new file mode 100644 index 0000000..bc91fbd --- /dev/null +++ b/wrappers/wrapper_sdk/sample_utilities.C @@ -0,0 +1,487 @@ +/********************************************************************** +* +* Source File Name = sample_utilities.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for sample utilities class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_typedefs.h" +#include "sample_utilities.h" +#include "sample_error_reporting.h" +#include "sqlqg_utils.h" +#include "sqlcodes.h" + +/************************************************************************** +* +* Function Name = Sample_Utilities::verify_column_type_and_options() +* +* Function: This method will verify that the column data type and the column +* options are supported by this wrapper. +* +* +* Input: nickname_info +* +* Output: +* +* Normal Return = 0 +* +* Error Return = !0 +* +**************************************************************************/ +sqlint32 +Sample_Utilities::verify_column_type_and_options(Nickname* a_nickname , + Nickname_Info *nickname_info, sqluint8* serverName) +{ + Column_Info *columnInfo = NULL; + Catalog_Option *catalog_option = NULL; + sqluint8 *dataType = NULL; + sqlint32 rc = 0; + sqlint32 trace_error = 0; + sqluint8 *column_name = NULL; + + Wrapper_Utilities::fnc_entry(90,"Sample_Utilities::verify_column_type_and_options"); + + Wrapper_Utilities::fnc_data(90,"Sample_Utilities::verify_column_type_and_options", + 5, strlen((char *)serverName), (char*)serverName); + columnInfo = nickname_info->get_first_column(); + + // sanity check.. + if (columnInfo == NULL) + { + rc = Wrapper_Utilities::report_error("SU_FCT", + SQL_RC_E901, 1, strlen(COLUMN_ERROR), COLUMN_ERROR); + trace_error = 10; + goto error; + } + + + while (columnInfo != NULL) + { + rc = columnInfo->get_type_name(&dataType); + + if ((rc) && (rc != SQLQG_NOVALUE)) + { + trace_error = 20; + goto error; + } + + Wrapper_Utilities::fnc_data(90,"Sample_Utilities::verify_column_type_and_options", + 25, strlen((char *)dataType), (char*)dataType); + if (rc != SQLQG_NOVALUE) + { + if ((strcmp((const char *)dataType,"CHARACTER") != 0) && + (strcmp((const char *)dataType,"VARCHAR") != 0) && + (strcmp((const char *)dataType,"INTEGER") != 0) && + (strcmp((const char *)dataType,"DECIMAL") != 0) && + (strcmp((const char *)dataType,"DOUBLE") != 0)) + { + rc = Wrapper_Utilities::report_error("SU_FCT", + SQL_RC_E1823, 2, + strlen((const char *)dataType), (const char *)dataType, + strlen((const char *)serverName), (const char *)serverName); + trace_error = 30; + goto error; + } + } + // check for unknown column options. + // This wrapper doesn't have any column options of its own + + catalog_option = columnInfo->get_first_option(); + + while (catalog_option != NULL) + { + sqluint8 *column_option_name = catalog_option->get_name(); + if (!a_nickname->is_reserved_column_option(column_option_name)) + { + // This is an unknown option. Complain.. + + // Get the column name + columnInfo->get_column_name(&column_name); + + rc = Wrapper_Utilities::report_error("SU_FCT", SQL_RC_E1881, 3, + strlen((const char *) column_option_name), + (const char *) column_option_name, + strlen("Column"), "Column", + strlen((const char *) column_name), + (const char *)column_name); + + Wrapper_Utilities::fnc_data2(90,"Sample_Utilities::verify_column_type_and_options", 40, + strlen((char *)column_option_name), (char *)column_option_name, + strlen((const char *)column_name), (const char *)column_name); + trace_error = 40; + goto error; + + } + + catalog_option = nickname_info->get_next_option(catalog_option); + } + + rc = 0; + columnInfo = nickname_info->get_next_column(columnInfo); + } + +exit: + Wrapper_Utilities::fnc_exit(90,"Sample_Utilities::verify_column_type_and_options", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(90,"Sample_Utilities::verify_column_type_and_options", + trace_error, sizeof(rc), &rc); + goto exit; +} + +/************************************************************************** +* +* Function Name = Sample_Utilities::save_option_value() +* +* Function: This method searches the list of catalog options and looks for +* option_name. If found, it allocats memory for it in +* option_save_location and copies the option value. +* +* Dependencies: +* +* Restrictions: +* +* Input: Catalog_Info *catalog_info - Catalog info for options +* char *option_name - name of the option to get the value for +* +* Output: char **option_save_location - pointer where memory will be +* allocated and the option value copied (if found) +* +* +* Normal Return = 0 +* +* Error Return = !0 +* +**************************************************************************/ +sqlint32 Sample_Utilities::save_option_value(Catalog_Info *catalog_info, + const char *option_name, + sqluint8 **option_save_location) +{ + sqlint32 rc = 0; + Catalog_Option *option = NULL; + Wrapper_Utilities::fnc_entry(91,"Sample_Utilities::save_option_value"); + + Wrapper_Utilities::fnc_data(91,"Sample_Utilities::save_option_value", + 45, strlen((char *)option_name), (char*)option_name); + + // Go through the list of options and look for the specified option. If + // found, save the value in option_save_buffer + option = catalog_info->get_first_option(); + while (option != NULL) + { + sqluint8 *catalog_option_name = option->get_name(); + if (strcmp((const char *) catalog_option_name, option_name) == 0) + { + if (*option_save_location != NULL) + { + Wrapper_Utilities::deallocate(*option_save_location); + } + + rc = Wrapper_Utilities::allocate(strlen((char *)option->get_value()) + 1, + (void **) option_save_location); + if (rc) + { + rc = sample_report_error_1822(rc, "Memory allocation error.", + 50, "SU_SOV"); + Wrapper_Utilities::trace_error(91,"Sample_Utilities::save_option_value", + 50, sizeof(rc), &rc); + goto exit; + } + + strcpy((char *) *option_save_location, (char *) option->get_value()); + break; + } + + option = catalog_info->get_next_option(option); + } + +exit: + Wrapper_Utilities::fnc_exit(91,"Sample_Utilities::save_option_value", rc); + return rc; +} + +/************************************************************************** +* +* Function Name = File_Utilities::unpack() +* +* Function: Unpacks a DB2 packed decimal into a string. The string representation +* will be allocated by this function. The caller should free the string +* when done. +* +* Input: +* +* Output: A string representation of the decimal number of size (precision + 3) +* +* Normal Return = 0 +* +* Error Return = !0 +* +**************************************************************************/ +sqlint32 Sample_Utilities::unpack(int scale, int precision, unsigned char *decData, + char **constant) +{ + sqlint32 rc = 0; + int suppressLeadingZero = 1; + int decimalPoint = 0; + int tmp = 0; + char zero = '0'; + char digit = 0x00; + + int i = 0; + char *bufPtr = NULL; // Point to the first byte of packed data + char *ptr = NULL; // Create a pointer to the start of the unpacked data + char *sign = NULL; // Save the location for the sign. + + sqlint32 trace_error = 0; + + Wrapper_Utilities::fnc_entry(92,"Sample_Utilities::unpack"); + + // If there's no data to unpack then signal an error. + if (decData == NULL) + { + rc = Wrapper_Utilities::report_error("SUunpack", + SQL_RC_E901, 1, + sizeof("Can't convert decimal"), "Can't convert decimal"); + trace_error = 10; + goto error; + } + + // Allocate an area to return the unpacked value. Make it 3 bytes larger than + // the precision to hold a decimal point, a sign, and a null terminator. + rc = Wrapper_Utilities::allocate((precision + 3), (void **)constant); + if (rc) + { + trace_error = 20; + goto error; + } + + decimalPoint = precision - scale; // Calculate the offset to the decimal point + + bufPtr = (char *)decData; // Point to the first byte of packed data + + ptr = *constant; // Create a pointer to the start of the unpacked data + sign = *constant; // Save the location for the sign. + + ptr++; // Increment past the sign location + + // If the precision is evenly divisable by 2 then that means that there is a + // leading zero so increment the iterator by 1 to account for the leading zero + if ((precision % 2) == 0) + { + tmp = precision + 1; + } + else + { + suppressLeadingZero = 0; + tmp = precision; + } + + for (i = 1; i <= tmp; i++) + { + digit = *bufPtr; // move the current byte to the digit byte. + + // If the iterator is not divisable by 2 that means we need to unpack the + // high order 4 bits. So, shift the high order 4 bits to the right 4 bits. + // Otherwise we are dealing with the low order 4 bits. So shift them to the + // left to clear the high order bits then back to the right. Increment the + // pointer to the next packed digit. + if (i % 2 == 1) + { + digit >>= 4; + digit = digit & 0x0f; + } + else + { + digit = digit & 0x0f; + bufPtr++; + } + + // Or the digit with an ascii zero to create the unpacked digit. + *ptr = zero | digit; + + ptr++; // Move to the next position of the unpacked number. + + // If this is the first iteration and the first digit is zero then reset the + // next unpacked position pointer and increment the decimal point locator. + if (suppressLeadingZero && *(ptr - 1) == '0') + { + ptr--; + decimalPoint++; + } + + // Reset the leading zero indicator + suppressLeadingZero = 0; + + // If the iterator is pointing to the decimal point offset then insert + // the decimal point into the unpacked string + if (i == decimalPoint) + { + *ptr = '.'; + ptr++; + } + } + + // Get the sign indicator + digit = *bufPtr; + digit = digit & 0x0f; + + // If the sign is positive (an F, A, C, or E) insert a "+" sign, otherwise insert + // a "-" sign. + if ((digit == 0x0f) || + (digit == 0x0a) || + (digit == 0x0c) || + (digit == 0x0e)) + { + *sign = '+'; + } + else + { + *sign = '-'; + } + +exit: + Wrapper_Utilities::fnc_exit(92,"File_Utilities::unpack", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(92,"File_Utilities::unpack", + trace_error, sizeof(rc), &rc); + goto exit; +} + + +/************************************************************************** +* +* Function Name = Sample_Utilities::convert_data() +* +* +* Function: This method converts a local data value into a format suitable +* for a remote server. +* +* The caller will pass in a buffer (converted_value) into which +* the converted value should be placed. The length of this buffer +* is given by the argument max_converted_value_length. If the buffer +* is not large enough, the return code should be set to 1, and +* the argument actual_converted_value_length should be set the +* size of the buffer that is required. +* +* Dependencies: +* +* Restrictions: +* +* Input: sqlint16 sqltype: Data type of input +* sqluint8* inputData: Pointer to input data +* sqlint32 inputLenght: Length of input data +* sqlint32 precision: Used with decimal datatype +* sqlint32 scale: Used with decimal datatype +* sqluint8 *converted_value: a buffer into which the converted +* value should be placed. +* +* +* Output: +* sqlint32 converted_value_length: if converted_value_length +* isn't long enough, should contain the length that the buffer should be. +* +* +* Normal Return = 0 +* +* Error Return = 1, if converted_value is not large enough to contain value +* != 0, error condition. +* +**************************************************************************/ +//@bd265406vcr +//@bd220117kal +sqlint32 Sample_Utilities::convert_data( + sqlint16 sqltype, + sqluint8* inputData, + sqlint32 inputLength, + sqlint32 precision, + sqlint32 scale, + char *converted_value, + sqlint32 *converted_value_length + ) +{ + sqlint32 rc = 0; + int searchTermInt = 0; + short searchTermShort = 0; + double searchTermFl = 0.0; + sqlint32 trace_error = 0; + + Wrapper_Utilities::fnc_entry(93,"Sample_Utilities::convert_data"); + + switch (sqltype) + { + case SQL_TYP_INTEGER: + { + searchTermInt = *(int *)inputData; + *converted_value_length = sprintf(converted_value, "%d", searchTermInt); + break; + } + case SQL_TYP_SMALL: + { + searchTermShort = *(short *)inputData; + *converted_value_length = sprintf(converted_value, "%d", searchTermShort); + break; + } + + case SQL_TYP_FLOAT: + { + searchTermFl = *(double *)inputData; + *converted_value_length = sprintf(converted_value, "%1f", searchTermFl); + break; + } + case SQL_TYP_CHAR: + case SQL_TYP_VARCHAR: + { + *converted_value_length = inputLength; + strncpy(converted_value, (char *)inputData, inputLength); + break; + } + case SQL_TYP_DECIMAL: + { + char *decString = NULL; + + // unpack the db2 packed decimal into a string.. + rc = Sample_Utilities::unpack( scale, precision, + (unsigned char *)inputData, &decString); + if (rc) + { + if (decString != NULL ) + { + Wrapper_Utilities::deallocate(decString); + } + trace_error = 10; + goto error; + } + + *converted_value_length = strlen(decString); + strncpy(converted_value, decString,*converted_value_length); + Wrapper_Utilities::deallocate(decString); + break; + } + default: + { + break; + } + } + + +exit: + Wrapper_Utilities::fnc_exit(93,"Sample_Utilities::convert_data", rc); + return rc; + +error: + Wrapper_Utilities::trace_error(93,"Sample_Utilities::convert_data", + trace_error, sizeof(rc), &rc); + goto exit; +} diff --git a/wrappers/wrapper_sdk/sample_utilities.h b/wrappers/wrapper_sdk/sample_utilities.h new file mode 100644 index 0000000..6c79762 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_utilities.h @@ -0,0 +1,58 @@ +/********************************************************************** +* +* Source File Name = sample_utilities.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: Class used to define utilities. +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_UTILITIES_H__ +#define __SAMPLE_UTILITIES_H__ + +#include "sample_nickname.h" +#include "sqlqg_misc.h" +#include "sqlqg_catalog.h" + +class Sample_Utilities { +public: + + // Verifies that the columns data types and options supplied in the CREATE/ALTER + // NICKNAME ddl are supported by this wrapper. + static sqlint32 verify_column_type_and_options(Nickname* a_nickname, Nickname_Info *nickname_info, + sqluint8* serverName); + + // Searches for an option_name and saves (allocate and copy) the value as a string + static sqlint32 save_option_value(Catalog_Info *catalog_info, const char *option_name, + sqluint8 **option_save_location); + + static sqlint32 unpack(int scale, int precision, unsigned char *decData, char **constant); + + static sqlint32 convert_data( + sqlint16 sqltype, + sqluint8* inputData, + sqlint32 inputLength, + sqlint32 precision, + sqlint32 scale, + char *converted_value, + sqlint32 *converted_value_length + ); + +private: + + // Constructor. + // Made private to prevent others from instantiating this class + + Sample_Utilities(); + +}; + + +#endif diff --git a/wrappers/wrapper_sdk/sample_wrapper.C b/wrappers/wrapper_sdk/sample_wrapper.C new file mode 100755 index 0000000..df6d3ea --- /dev/null +++ b/wrappers/wrapper_sdk/sample_wrapper.C @@ -0,0 +1,170 @@ +/********************************************************************** +* +* Source File Name = sample_wrapper.C +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Function definitions for unfenced sample wrapper class +* +* Operating System = All +* +***********************************************************************/ +#include "sample_wrapper.h" +#include "sample_typedefs.h" +#include "sample_error_reporting.h" + +#include "sqlqg_catalog.h" +#include "sqlqg_utils.h" +#include "sqlcodes.h" +#include + +/////////////////////////////////////////////////////////////////////////////// +// Sample wrapper class +////////////////////////////////////////////////////////////////////////////// + +/************************************************************************** +* +* Function Name = Sample_Wrapper::Sample_Wrapper() +* +* Function: Constructor for Sample_Wrapper class +* +* Dependencies: +* +* Restrictions: +* +* Input: (required) sqlint32* rc: return code to indicate errors. +* +* Output: N/A +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +Sample_Wrapper::Sample_Wrapper(sqlint32* rc) + : Unfenced_Generic_Wrapper(rc, SAMPLE_WRAPPER_VERSION) +{ + Wrapper_Utilities::fnc_entry(1,"Sample_Wrapper::Sample_Wrapper"); + Wrapper_Utilities::fnc_exit(1,"Sample_Wrapper::Sample_Wrapper", *rc); +} + +/************************************************************************** +* +* Function Name = Sample_Wrapper::~Sample_Wrapper() +* +* Function: Destructor for Sample_Wrapper class +* +* Dependencies: +* +* Restrictions: +* +* Input: none +* +* Output: N/A +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +Sample_Wrapper::~Sample_Wrapper() +{ + Wrapper_Utilities::fnc_entry(2,"Sample_Wrapper::~Sample_Wrapper"); + Wrapper_Utilities::fnc_exit(2,"Sample_Wrapper::~Sample_Wrapper", 0); +} + + +/************************************************************************** +* +* Function Name = Sample_Wrapper::create_server() +* +* Function: routine to create a new instance of Sample_Server +* +* Dependencies: +* +* Restrictions: +* +* Input: (required) sqluint8* server_name: name of server for which instance +* should be instantiated. +* +* Output: (optional) Server* server: newly instantiated Sample_Server instance. +* +* Normal Return = 0 +* +* Error Return = rc != 0 +* +**************************************************************************/ +Server* Sample_Wrapper::create_server(sqluint8* server_name, sqlint32* rc) +{ + Sample_Server *server=NULL; + Wrapper_Utilities::fnc_entry(3,"Sample_Wrapper::create_server"); + + Wrapper_Utilities::fnc_data(3,"Sample_Wrapper::create_server", + 10, strlen((char *)server_name), (char*)server_name); + server = new(rc) Sample_Server(server_name, this, rc); + if(*rc!=0) + { + *rc = sample_report_error_1822(*rc, "Memory allocation error.", + 20, "SW_CS"); + Wrapper_Utilities::trace_error(3,"Sample_Wrapper::create_server", + 20, sizeof(*rc), rc); + } + + Wrapper_Utilities::fnc_exit(3,"Sample_Wrapper::create_server", *rc); + return server; +} + +/************************************************************************** +* +* Function Name = UnfencedWrapper_Hook() +* +* Function: Hook function to get a handle on Sample_Wrapper instance. +* +* Dependencies: +* +* Restrictions: +* +* Input: none +* +* Output: N/A +* +* Normal Return = UnfencedWrapper*: a pointer to instantiated Wrapper instance +* +* Error Return = rc != 0 +* +**************************************************************************/ +extern "C" UnfencedWrapper* UnfencedWrapper_Hook() +{ + + UnfencedWrapper* wrapper=NULL; + sqlint32 rc=0; + Wrapper_Utilities::fnc_entry(4,"UnfencedWrapper_Hook"); + + wrapper = new(&rc) Sample_Wrapper(&rc); + + if( (rc) || (wrapper == NULL) ) + { + rc = Wrapper_Utilities::report_error("UW_Hook", + SQL_RC_E1822, 3, strlen("-1"), "-1", + strlen(SQLQG_WRAPPER_OPTION), SQLQG_WRAPPER_OPTION, + strlen(NULL_WRAPPER), NULL_WRAPPER); + + Wrapper_Utilities::trace_error(4,"UnfencedWrapper_Hook", + 30, sizeof(rc), &rc); + + if (wrapper != NULL ) + { + delete wrapper; + wrapper = NULL; + } + + } + + Wrapper_Utilities::fnc_exit(4,"UnfencedWrapper_Hook", rc); + return wrapper; +} diff --git a/wrappers/wrapper_sdk/sample_wrapper.h b/wrappers/wrapper_sdk/sample_wrapper.h new file mode 100755 index 0000000..7833e04 --- /dev/null +++ b/wrappers/wrapper_sdk/sample_wrapper.h @@ -0,0 +1,51 @@ +/********************************************************************** +* +* Source File Name = sample_wrapper.h +* +* (C) COPYRIGHT International Business Machines Corp. 2003,2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Function = Include File defining: unfenced wrapper class for sample wrapper +* +* Operating System = All +* +***********************************************************************/ +#ifndef __SAMPLE_WRAPPER_H__ +#define __SAMPLE_WRAPPER_H__ + +#include "sqlqg_unfenced_generic_wrapper.h" +#include "sample_server.h" + +////////////////////////////////////////////////////////////////////////////// +// Sample wrapper class +////////////////////////////////////////////////////////////////////////////// + +class Sample_Wrapper : public Unfenced_Generic_Wrapper +{ +public: + + // Constructor. + Sample_Wrapper(sqlint32 *rc); + + // Destructor. + virtual ~Sample_Wrapper(); + +protected: + + //////////////// + // Methods. + //////////////// + + // create_server() allows a wrapper subclass instance to + // create an instance of its own remote server subclass. + + virtual Server* create_server(sqluint8* server_name, + sqlint32* xrc); + +}; + +#endif diff --git a/wrappers/wrapper_sdk_java/FencedFileNickname.java b/wrappers/wrapper_sdk_java/FencedFileNickname.java new file mode 100644 index 0000000..ec029e2 --- /dev/null +++ b/wrappers/wrapper_sdk_java/FencedFileNickname.java @@ -0,0 +1,199 @@ +/********************************************************************** +* +* Source File Name = FencedFileNickname.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ + +import com.ibm.db2.wrapper.*; + +/** + * The FencedFileNickname represents a nickname of the file wrapper. + * In this case the nickname maps one to one with a flat text file containing the data. + * This class is responsible for validating information from the CREATE NICKNAME statement. + * The FencedFileNickname is the "run-time" part of the nickname that can retrieve the + * active remote connection from the parent server object and use it to obtain the + * nickname information from the remote data source. + * Since this sample deals with flat text files, the remote connection is a "no-op" and the + * nickname validates the information by itself. + */ +public class FencedFileNickname extends FencedGenericNickname +{ + /** + * Construct a nickname with the specified schema and name for the specified server. + * + * @param schema The local DB2 nickname schema name. + * @param name The local DB2 nickname name. + * @param server The server containing this nickname. + * + */ + public FencedFileNickname(String schema, String name, FencedFileServer server) + { + super(schema, name, server); + } + + /** + * Perform necessary nickname initialization. + * This method is called by the DB2 engine after the nickname is created or after the options are changed. + * This method is implemented by the wrapper to perform the nickname-specific initialization. + * The current implementation saves the file path into a class field. + * + * @param nicknameInfo The nickname catalog information. + * + * @exception WrapperException The DB2 error 1883 is thrown if the FILE_PATH option is not present. + */ + protected void initializeMyNickname(NicknameInfo nicknameInfo) throws WrapperException + { + + // save the file path from NicknameInfo into a class field + CatalogOption option = nicknameInfo.getOption("FILE_PATH"); + + // be sure the option is present + if( option != null ) + { + _filePath = option.getValue(); + } + else + { + throw new WrapperException(-1883, "FFNVR", new String[] {"FILE_PATH", "Nickname", nicknameInfo.getNickname() }); + } + + } + + /** + * Function to verify the nickname information that is specified in CREATE NICKNAME statement. + * The current implementation accepts only the reserved nickname options and the FILE_PATH option. + * It also verifies the column data types and the column options. + * + * @param nicknameInfo The nickname information specified in CREATE NICKNAME statement. + * + * @return Additional information that the wrapper wants to store in the DB2 UDB catalog. + * The current implementation returns null. + * + * @exception WrapperException The DB2 errors 1881, 1883 and 1823 are thrown if the verification fails. + * + */ + protected NicknameInfo verifyMyRegisterNicknameInfo(NicknameInfo nicknameInfo) throws WrapperException + { + // accept all reserved nickname options, FILE_PATH and READ_ONLY option + boolean foundFilePath = false; + NicknameInfo deltaInfo = null; + + CatalogOption option = nicknameInfo.getFirstOption(); + while( option != null ) + { + if( ! option.isReserved() ) + { + String optionName = option.getName(); + + if( optionName.equals("FILE_PATH") ) + { + foundFilePath = true; + } + else + { + // invalid option + throw new WrapperException(-1881, "FFNVR", new String[] {optionName, "Nickname", nicknameInfo.getNickname() }); + } + } + + option = nicknameInfo.getNextOption(option); + } + + // FILE_PATH is a required option; if not present, throw an error + if( ! foundFilePath ) + { + throw new WrapperException(-1883, "FFNVR", new String[] {"FILE_PATH", "Nickname", nicknameInfo.getNickname() }); + } + + // ensure READ_ONLY is set to "Y" + if ((option = nicknameInfo.getOption("READ_ONLY")) != null) + { + // user did already provide the option -> check value + if (option.getValue().compareTo("Y") != 0) + { + throw new WrapperException(-1882, "FFNVR", new String[] {"Nickname", "READ_ONLY", option.getValue(), nicknameInfo.getNickname() }); + } + } + else + { + // user did not provide READ_ONLY option -> so force the option from within the code + if (deltaInfo == null) + { + deltaInfo = new NicknameInfo(); + } + deltaInfo.addOption("READ_ONLY", "Y", CatalogOption.ADD); + } + + // check column types & options + verifyColumns(nicknameInfo); + + return deltaInfo; + } + + /** + * Function to verify the column information that is specified in CREATE NICKNAME statement. + * The current implementation accepts only a subset of column types and the reserved colun options. + * + * @param nicknameInfo The nickname information specified in CREATE NICKNAME statement. + * The nicknameInfo object contains the column information too. + * + * @exception WrapperException The DB2 errors 1881 and 1823 are thrown if the verification fails. + * + */ + protected void verifyColumns(NicknameInfo nicknameInfo) throws WrapperException + { + ColumnInfo columnInfo = nicknameInfo.getFirstColumn(); + + while( columnInfo != null ) + { + String type = columnInfo.getTypeName(); + + if( ! type.equals("VARCHAR") && + ! type.equals("CHARACTER") && + ! type.equals("INTEGER") && + ! type.equals("DOUBLE") && + ! type.equals("DECIMAL") ) + { + throw new WrapperException(-1823, "FFNVC", new String[] { type, getServer().getName() } ); + } + + // accept only the reserved columns options + CatalogOption option = columnInfo.getFirstOption(); + while( option != null ) + { + if( ! option.isReserved() ) + { + throw new WrapperException(-1881, "FFNVC", new String[] {option.getName(), "Column", nicknameInfo.getNickname() }); + } + option = columnInfo.getNextOption(option); + } + + columnInfo = nicknameInfo.getNextColumn(columnInfo); + } + } + + /** + * Retrieve the file path. + * + * @return The file path as extracted from the nickname catalog information. + * + */ + public String getFilePath() + { + return _filePath; + } + + /** + * The file path as extracted from the nickname catalog information. + */ + private String _filePath = null; +} diff --git a/wrappers/wrapper_sdk_java/FencedFileServer.java b/wrappers/wrapper_sdk_java/FencedFileServer.java new file mode 100644 index 0000000..b4256be --- /dev/null +++ b/wrappers/wrapper_sdk_java/FencedFileServer.java @@ -0,0 +1,74 @@ +/********************************************************************** +* +* Source File Name = FencedFileServer.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ + +import com.ibm.db2.wrapper.*; + +/** + * The FencedFileServer represents a server of the file wrapper. + * The Server maps to the remote data source, but since we are dealing with flat text files, + * fhe file server objects are responsible only for providing the user mapping, nickname and + * remote connection objects. + * The FencedFileServer is the "run-time" part of the server that DB2 uses to create remote + * connections to the remote data source. + */ +public class FencedFileServer extends FencedGenericServer +{ + /** + * Construct a server with the specified name for the specified wrapper. + * + * @param serverName The server name. + * @param wrapper The wrapper containing this server. + * + */ + public FencedFileServer(String serverName, FencedFileWrapper wrapper ) + { + super(serverName, wrapper); + } + + /** + * Create a nickname object that maps to a data collection a the remote data source. + * For the file wrapper, the data collection is a flat text file. + * + * @param schemaName The local DB2 nickname schema name. + * @param nickname The local DB2 nickname name. + * + * @return A nickname instance. + * + */ + public Nickname createNickname(String schemaName, String nickname) + { + return new FencedFileNickname(schemaName, nickname, this); + } + + /** + * Create a remote connection to handle a connection between the wrapper and the remote data source. + * For the file wrapper, the remote connection is a no-op. + * + * @param user The user mapping instance that the remote connection + * will use for authorization at the remote data source. + * @param kind A constant indicating whether the remote connection supports transactions or not. + * Valid values for this constant are defined in the RemoteConnection class. + * The wrapper specifies if the remote source supports transaction or not by + * overriding the FencedServer.getRemoteConnectionKind method. + * @param id Reserved DB2 value. + * + * @return A remote connection instance. + * + */ + public RemoteConnection createRemoteConnection(FencedRemoteUser user, int kind, long id) + { + return new FileConnection(this, user, kind, id); + } +} diff --git a/wrappers/wrapper_sdk_java/FencedFileWrapper.java b/wrappers/wrapper_sdk_java/FencedFileWrapper.java new file mode 100644 index 0000000..83e3f8d --- /dev/null +++ b/wrappers/wrapper_sdk_java/FencedFileWrapper.java @@ -0,0 +1,44 @@ +/********************************************************************** +* +* Source File Name = FencedFileWrapper.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ + +import com.ibm.db2.wrapper.*; + +/** + * The FencedFileWrapper represents a wrapper to access flat text files. + */ +public class FencedFileWrapper extends FencedGenericWrapper +{ + /** + * Construct a new wrapper object. + * + */ + public FencedFileWrapper() + { + super(); + } + + /** + * Create a server object that represents a remote data source. + * + * @param serverName The name of the server object. + * + * @return A new server instance. + * + */ + protected Server createServer(String serverName) + { + return new FencedFileServer(serverName, this); + } +} diff --git a/wrappers/wrapper_sdk_java/FileConnection.java b/wrappers/wrapper_sdk_java/FileConnection.java new file mode 100644 index 0000000..bc9f7a6 --- /dev/null +++ b/wrappers/wrapper_sdk_java/FileConnection.java @@ -0,0 +1,53 @@ +/********************************************************************** +* +* Source File Name = FileConnection.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ + +import com.ibm.db2.wrapper.*; + +/** + * The FileConnection represents a connection between the file wrapper and the remote data source. + * But since we are dealing with flat text files, there is no need to implement a connection + * mechanism and this class has only to provide the RemoteQuery objects that represent the run-time + * objects used by DB2 to retrieve data from the remote data source. + */ +public class FileConnection extends RemoteConnection +{ + /** + * Construct a connection for the specified server with the user authorization and transaction type as indicated. + * + * @param remoteServer The server that contains the connection. + * @param remoteUser The user object that is used for authentication. + * @param connectionKind The kind of connection; specifies what kind of transactions are supported. + * @param id Reserved for DB2 use. + * + * + */ + public FileConnection(FencedServer remoteServer, FencedRemoteUser remoteUser, int connectionKind, long id) + { + super(remoteServer, remoteUser, connectionKind, id); + } + + /** + * Create a FileQuery object for executing SQL statements. + * + * @param id Reserved for DB2 use. + * + * @return A FileQuery instance. + */ + public RemoteQuery createRemoteQuery(long id) + { + return new FileQuery(this, id); + } + +} diff --git a/wrappers/wrapper_sdk_java/FileExecDesc.java b/wrappers/wrapper_sdk_java/FileExecDesc.java new file mode 100644 index 0000000..5216d21 --- /dev/null +++ b/wrappers/wrapper_sdk_java/FileExecDesc.java @@ -0,0 +1,451 @@ +/********************************************************************** +* +* Source File Name = FileExecDesc.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ +import java.math.BigDecimal; + +/** + * The FileExecDesc class represents the wrapper specific execution descriptor class. + * During query planning, the wrapper builds an execution descriptor and attaches it + * to the Reply sent back to DB2. DB2 will store the execution descriptor until the + * query is executed and it will pass it back to the wrapper at that time. + * The stored information is wrapper specific and it has to allow the wrapper to + * execute the query at the remote data source. + * The only restriction imposed by DB2 on the execution descriptor is o be + * serializable. + *
+ * For simplicity and better understanding, the class methods don't validate the + * input data. Instead, if there are any dependencies, they are noted in the method + * description. + *
+ * The class has two types of methods:
    + *
  • the "set" methods are used during query planning, the phase when the execution + * descriptor is built and the information is added to it. + *
  • The "get" methods are used during query execution, the phase when the wrapper + * is retrieving the information from the execution descriptor. + *
+ */ +public class FileExecDesc implements java.io.Serializable +{ + + /** + * Set the number of columns of the nickname involved in the query. + * This method is called during query planning. + * + * @param number The number of columns. + */ + public void setNumberOfColumns(int number) + { + _nicknameColumns = number; + } + + /** + * Set the number of the columns from the SELECT clause of the query. + * This method is called during query planning and it should be called + * before {@link #setOutputColumn}. + * + * @param number The number of selected columns. + */ + public void setNumberOfOutputColumns(int number) + { + _outputColumns = new int[number]; + } + + /** + * Specify which nickname column is in the SELECT clause of the query + * at the given index. The nickname column is indicated by its position. + * This method is called during query planning. + * {@link #setNumberOfOutputColumns} should have been called in advance. + * + * @param outputIndex The index of the column in SELECT clause. + * @param columnIndex The position of the column in the nickname. + */ + public void setOutputColumn(int outputIndex, int columnIndex) + { + if( _outputColumns != null ) + { + _outputColumns[outputIndex] = columnIndex; + } + } + + /** + * Set the path to the flat text file for the nickname involved in the query. + * This method is called during query planning. + * + * @param filePath The file path as retrieved from the nickname catalog information. + */ + public void setFilePath(String filePath) + { + _filePath = filePath; + } + + /** + * Set the predicate. It can be FileExecDesc.EQUAL or FileExecDesc.ALLROW + * This method is called during query planning. + * + * @param predicate The predicate for the SELECT clause + */ + public void setPredicate(int predicate) + { + _predicateType = predicate; + } + + /** + * Set the keycolumn. It is the column no of the column = 'cst' or 'cst' = column + * This method is called during query planning. + * + * @param keyColumn The column no of the column + */ + public void setKeyColumn(int keyColumn) + { + _keyColumn = keyColumn; + } + + /** + * Set the bind index of unbound. It is the index no of the column = unbound or unbound = column + * This method is called during query planning. + * + * @param bindIndex The bind index no of the unbound + */ + public void setBindIndex(int bindIndex) + { + _bindIndex = bindIndex; + } + + /** + * Set the data type. It is the constant data type of the column = 'cst' or 'cst' = column + * It can be RuntimeData.CHAR, RuntimeData.VARCHAR, RuntimeData.INT, RuntimeData.DOUBLE, + * RuntimeData.FLOAT, or RuntimeData.DECIMAL. + * This method is called during query planning. + * + * @param type The data type of the constant + */ + public void setDataType(short type) + { + _dataType = type; + } + + /** + * If the data type is RuntimeData.CHAR or RuntimeData.VARCHAR, set the string constant value. + * This method is called during query planning. + * + * @param value The string value with data type of RuntimeData.CHAR or RuntimeData.VARCHAR + */ + public void setConstString(String value) + { + _valueString = value; + } + + /** + * If the data type is RuntimeData.INT, set the int constant value. + * This method is called during query planning. + * + * @param value The int value with data type of RuntimeData.INT + */ + public void setConstInt(int value) + { + _valueInt = value; + } + + /** + * If the data type is RuntimeData.DOUBLE, set the double constant value. + * This method is called during query planning. + * + * @param value The double value with data type of RuntimeData.DOUBLE + */ + public void setConstDouble(double value) + { + _valueDouble = value; + } + + /** + * If the data type is RuntimeData.FLOAT, set the float constant value. + * This method is called during query planning. + * + * @param value The float value with data type of RuntimeData.FLOAT + */ + public void setConstFloat(float value) + { + _valueFloat = value; + } + + /** + * If the data type is RuntimeData.DECIMAL, set the BigDecimal constant value. + * This method is called during query planning. + * + * @param value The BigDecimal value with data type of RuntimeData.DECIMAL + */ + public void setConstDecimal(BigDecimal value) + { + _valueDecimal = value; + } + + /** + * If the data type is RuntimeData.DECIMAL, set the scale of the decimal. + * This method is called during query planning. + * + * @param scale The scale of the decimal + */ + public void setScale(short scale) + { + _scale = scale; + } + + /** + * Retrieve the number of columns of the nickname involved in the query. + * This method is called during query execution. + * + * @return The number of columns. + */ + public int getNumberOfColumns() + { + return _nicknameColumns; + } + + /** + * Retrieve the array that describes the columns from the SELECT clause of the query. + * The columns are described by their position in the nickname. + * This method is called during query execution. + * + * @return An array containing the position of each selected column + * in the nickname. + */ + public int[] getOutputColumns() + { + return _outputColumns; + } + + /** + * Retrieve the number of the columns from the SELECT clause of the query. + * This method is called during query execution. + * + * @return The number of selected columns. + */ + public int getNumberOfOutputColumns() + { + return (_outputColumns == null ? 0: _outputColumns.length); + } + + /** + * Retrieve the position of the column in the nickname for the given column index from + * the SELECT clause of the query. + * This method is called during query execution. + * + * @param index The index of the column in SELECT clause. + * + * @return The position of the column in the nickname. + */ + public int getOutputColumn(int index) + { + return (_outputColumns == null || index >= _outputColumns.length ? -1: _outputColumns[index] ); + } + + /** + * Retrieve the path to the flat text file for the nickname involved in the query. + * This method is called during query execution. + * + * @return The file path that was stored in the execution descriptor. + */ + public String getFilePath() + { + return _filePath; + } + + /** + * Retrieve the predicate. It can be FileExecDesc.EQUAL or FileExecDesc.ALLROW + * This method is called during query execution. + * + * @return The predicate for the SELECT clause. + */ + public int getPredicate() + { + return _predicateType; + } + + /** + * Retrieve the keycolumn. It is the column no of the column = 'cst' or 'cst' = column + * This method is called during query execution. + * + * @return The column no of the column. + */ + public int getKeyColumn() + { + return _keyColumn; + } + + /** + * Retrieve the bind index of unbound. It is the index no of the column = unbound or unbound = column + * This method is called during query execution. + * + * @return The bind index no of the unbound + */ + public int getBindIndex() + { + return _bindIndex; + } + + /** + * Retrieve the data type. It is the constant data type of the column = 'cst' or 'cst' = column + * It can be RuntimeData.CHAR, RuntimeData.VARCHAR, RuntimeData.INT, RuntimeData.DOUBLE, + * RuntimeData.FLOAT, or RuntimeData.DECIMAL. + * This method is called during query execution. + * + * @return The data type of the constant + */ + public short getDataType() + { + return _dataType; + } + + /** + * If the data type is RuntimeData.CHAR or RuntimeData.VARCHAR, retrieve the string constant value. + * This method is called during query execution. + * + * @return The string value with data type of RuntimeData.CHAR or RuntimeData.VARCHAR + */ + public String getConstString() + { + return _valueString; + } + + /** + * If the data type is RuntimeData.INT, retrieve the int constant value. + * This method is called during query execution. + * + * @return The int value with data type of RuntimeData.INT + */ + public int getConstInt() + { + return _valueInt; + } + + /** + * If the data type is RuntimeData.DOUBLE, retrieve the double constant value. + * This method is called during query execution. + * + * @return The double value with data type of RuntimeData.DOUBLE + */ + public double getConstDouble() + { + return _valueDouble; + } + + /** + * If the data type is RuntimeData.FLOAT, retrieve the float constant value. + * This method is called during query execution. + * + * @return The float value with data type of RuntimeData.FLOAT + */ + public float getConstFloat() + { + return _valueFloat; + } + + /** + * If the data type is RuntimeData.DECIMAL, retrieve the BigDecimal constant value. + * This method is called during query execution. + * + * @return The BigDecimal value with data type of RuntimeData.DECIMAL + */ + public BigDecimal getConstDecimal() + { + return _valueDecimal; + } + + /** + * If the data type is RuntimeData.DECIMAL, retrieve the scale of the decimal. + * This method is called during query execution. + * + * @return The scale of the decimal + */ + public short getScale() + { + return _scale; + } + + /** + * It means get all the rows out. + */ + public static final int ALLROW = 0; + /** + * It means get rows, which meet column = 'cst' or 'cst' = column. + */ + public static final int EQUAL = 1; + + /** + * The path to the file that corresponds to the nickname involved in the query. + */ + private String _filePath = null; + + /** + * The number of columns for the nickname involved in the query. + */ + private int _nicknameColumns = 0; + + /** + * An array with the column positions in the nickname for each column from the + * SELECT clause of the query. + */ + private int[] _outputColumns = null; + + /** + * Predicate for the SELECT clause. It can be FileExecDesc.EQUAL or FileExecDesc.ALLROW + */ + private int _predicateType; + + /** + * Column no of the column for the predicate + */ + private int _keyColumn = 0; + + /** + * Bind index no of the unbound + */ + private int _bindIndex = -1; + + /** + * Value of the constant, if the data type is RuntimeData.CHAR or RuntimeData.VARCHAR + */ + private String _valueString; + + /** + * Value of the constant, if the data type is RuntimeData.INT + */ + private int _valueInt; + + /** + * Value of the constant, if the data type is RuntimeData.DOUBLE + */ + private double _valueDouble; + + /** + * Value of the constant, if the data type is RuntimeData.FLOAT + */ + private float _valueFloat; + + /** + * Value of the constant, if the data type is RuntimeData.DECIMAL + */ + private BigDecimal _valueDecimal; + + /** + * Scale of decimal, if the data type is RuntimeData.DECIMAL + */ + private short _scale; + + /** + * Data type of the constant. It can be RuntimeData.CHAR, RuntimeData.VARCHAR, + * RuntimeData.INT, RuntimeData.DOUBLE, RuntimeData.FLOAT, or RuntimeData.DECIMAL. + */ + private short _dataType; +} diff --git a/wrappers/wrapper_sdk_java/FileQuery.java b/wrappers/wrapper_sdk_java/FileQuery.java new file mode 100644 index 0000000..1bc68b5 --- /dev/null +++ b/wrappers/wrapper_sdk_java/FileQuery.java @@ -0,0 +1,387 @@ +/********************************************************************** +* +* Source File Name = FileQuery.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ + +import com.ibm.db2.wrapper.*; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.StringTokenizer; +/** + * The FileQuery class represents the mechanism by which DB2 retrieves data + * from the remote data source. + * The mechanism used is of type open-fetch-close. + */ +public class FileQuery extends RemoteQuery +{ + /** + * Construct a new FileQuery object for the specified connection. + * + * @param activeConnection The active connection that this FileQuery object will use + * to access the remote data source. + * @param id Reserved for DB2 use. + * + */ + public FileQuery(RemoteConnection activeConnection, long id) + { + super(activeConnection, id); + } + + /** + * Allow the wrapper to prepare the data source to return the first result row for the query. + * The file wrapper retrieves here the execution descriptor object that it constructed + * during query planning and opens an input stream for the file that needs to be read. + * + * @exception Exception if the processing fails. + */ + public void open() throws Exception + { + // retrieve the execution descriptor and set up a file reader + execDesc = (FileExecDesc) getExecDesc(); + + fileReader = new BufferedReader(new FileReader( execDesc.getFilePath() )); + + // report query status to DB2 + setStatus(OPEN); + } + + /** + * Reset a previously opened result stream and prepares the data source to return more results. + * The file wrapper re-opens an input stream for the file that needs to be read. + * + * @param action The flag to indicate the action needed in reopen. + * + * @exception Exception if the processing fails. + */ + public void reopen(short action) throws Exception + { + // re-initialize the file reader + fileReader = new BufferedReader(new FileReader( execDesc.getFilePath() )); + + // report query status to DB2 + setStatus(OPEN); + } + + /** + * Method that allows the wrapper and the data source to clean up after executing a query. + * The file wrapper closes the input stream previously opened for the file that needs to + * be read. + * + * @param status The flag that indicates the status of the operation. + * + * @exception Exception if the processing fails. + */ + public void close(short status) throws Exception + { + // close the file reader + if( fileReader != null ) + { + fileReader.close(); + fileReader = null; + } + + // report query status to DB2 + if( status == CLOSE_EOS || status == CLOSE_EOA ) + { + setStatus(UNREADY); + } + else + { + setStatus(READY); + } + } + + /** + * Convert a string into an array of tokens considering comma as separator. + * The string represents a line read from the file. + * + * @param line The string to be parsed into tokens. + * @param tokenCount The number of tokens that should be in the string. + * This value is used by the tokenizer to do a minimal + * validation of the string. + * + * @return The array of tokens. + * + * @exception WrapperException if the actual number of tokens is different than the + * expected token count. + */ + public String[] tokenize(String line, int tokenCount) throws WrapperException + { + String[] tokens = new String[tokenCount]; + StringTokenizer tokenizer = new StringTokenizer(line, ","); + int index = 0; + + while( tokenizer.hasMoreTokens() ) + { + if( index < tokenCount ) + { + tokens[index++] = tokenizer.nextToken(); + } + else + { + throw new WrapperException("Invalid line read from file. Too many columns!"); + } + } + if( index < tokenCount ) + { + throw new WrapperException("Invalid line read from file. Not enough columns!"); + } + + return tokens; + } + + /** + * Method that copies a single result row from the data source into the output RuntimeDataList. + * The file wrapper reads the file line by line, converts the line into an array of tokens and + * puts these tokens into the output RuntimeDataList object. If there is predicate, it will + * judge whether the value meets the predicate. Only the matched lines will be put into + * the output RuntimeDataList object. + * If there are no more lines to be read from the file, the fetch method calls reportEof to + * flag DB2 that data fetching is done. + * + * @exception Exception if the processing fails. + */ + public void fetch() throws Exception + { + if( fileReader == null || execDesc == null) + { + throw new WrapperException( "Query not initialized!"); + } + String line = null; + + while(true) + { + // read one line from the file + line = fileReader.readLine(); + + // if there are no more line, report Eof condition to DB2 + if( line == null ) + { + reportEof(); + break; + } + else + { + // split the line into columns + String[] tokens = tokenize(line, execDesc.getNumberOfColumns()); + + boolean match = true; + //If predicate is FileExecDesc.ALLROW, the line will be matched. + //Else it will jump into the logic to judge whether the line meet the predicate. + if(execDesc.getPredicate() != FileExecDesc.ALLROW) + { + match = false; + //Get the column's value to compare it with the constant specified + //in the equality predicate. To obtain the column value use its index + // that was stored in the Execution Descriptor at query planning. + int keyColumn = execDesc.getKeyColumn(); + String keyValue = new String(tokens[keyColumn]); + int bindIndex = execDesc.getBindIndex(); + //form column = 'cst' or 'cst' = column + if(bindIndex == -1) + { + switch(execDesc.getDataType()) + { + case RuntimeData.CHAR: + case RuntimeData.VARCHAR: + { + if(keyValue.equals(execDesc.getConstString())) + { + match = true; + } + break; + } + case RuntimeData.INT: + { + if(Integer.parseInt(keyValue) == execDesc.getConstInt()) + { + match = true; + } + break; + } + case RuntimeData.DOUBLE: + { + if(Double.parseDouble(keyValue) == execDesc.getConstDouble()) + { + match = true; + } + break; + } + case RuntimeData.FLOAT: + { + if(Float.parseFloat(keyValue) == execDesc.getConstFloat()) + { + match = true; + } + break; + } + case RuntimeData.DECIMAL: + { + //The comparison of decimal values requires them to have the same scale. + //Use the scale that was stored in the Execution Descriptor at query planning. + short scale = execDesc.getScale(); + BigDecimal value1 = execDesc.getConstDecimal(); + value1 = value1.setScale(scale,java.math.BigDecimal.ROUND_HALF_UP); + BigDecimal value2 = new BigDecimal(keyValue); + value2 = value2.setScale(scale,java.math.BigDecimal.ROUND_HALF_UP); + + if(value1.compareTo(value2) == 0) + { + match = true; + } + break; + } + + default: + { + throw new WrapperException("Fetch: Unknown data type!"); + } + } + } + else //form column = unbound or unbound = column + { + RuntimeDataList dataList = getInputData(); + RuntimeData data = dataList.getValue(bindIndex); + if(data == null) + { + throw new WrapperException("Fetch: runtimedata is null!"); + } + switch(data.getDataType()) + { + case RuntimeData.CHAR: + case RuntimeData.VARCHAR: + { + if(keyValue.equals(data.getString())) + { + match = true; + } + break; + } + case RuntimeData.INT: + { + if(Integer.parseInt(keyValue) == data.getInt()) + { + match = true; + } + break; + } + case RuntimeData.DOUBLE: + { + if(Double.parseDouble(keyValue) == data.getDouble()) + { + match = true; + } + break; + } + case RuntimeData.FLOAT: + { + if(Float.parseFloat(keyValue) == data.getFloat()) + { + match = true; + } + break; + } + case RuntimeData.DECIMAL: + { + //The comparison of decimal values requires them to have the same scale. + //Use the scale that was stored in the Execution Descriptor at query planning. + short scale = execDesc.getScale(); + BigDecimal value1 = data.getBigDecimal(); + value1 = value1.setScale(scale,java.math.BigDecimal.ROUND_HALF_UP); + BigDecimal value2 = new BigDecimal(keyValue); + value2 = value2.setScale(scale,java.math.BigDecimal.ROUND_HALF_UP); + + if(value1.compareTo(value2) == 0) + { + match = true; + } + break; + } + + default: + { + throw new WrapperException("Fetch: Unknown data type!"); + } + } + } + } + + //Found the wanted row + if(match == true) + { + RuntimeDataList outputDataList = getOutputData(); + int valuesCount = outputDataList.getNumberOfValues(); + // save the column values into the output data object + for( int i = 0; i < valuesCount; i++ ) + { + RuntimeData data = outputDataList.getValue(i); + int columnIndex = execDesc.getOutputColumn(i); + switch( data.getDataType() ) + { + case RuntimeData.CHAR: + case RuntimeData.VARCHAR: + { + data.setString( tokens[columnIndex] ); + break; + } + case RuntimeData.INT: + { + data.setInt( Integer.parseInt( tokens[columnIndex]) ); + break; + } + case RuntimeData.DOUBLE: + { + data.setDouble( Double.parseDouble( tokens[columnIndex]) ); + break; + } + case RuntimeData.FLOAT: + { + data.setFloat( Float.parseFloat( tokens[columnIndex]) ); + break; + } + case RuntimeData.DECIMAL: + { + data.setBigDecimal( new BigDecimal( tokens[columnIndex]) ); + break; + } + + default: + { + throw new WrapperException("Fetch: Unknown data type!"); + } + } // end switch + } // end for + + //Get the wanted row and break + break; + } //end else + } // end else if line == null + } // end while(true) + } // end fetch + + /** + * The execution descriptor object. + */ + private FileExecDesc execDesc = null; + + /** + * The input stream that is used to retrieve data from the file. + */ + private BufferedReader fileReader = null; + +} // end class diff --git a/wrappers/wrapper_sdk_java/Readme.txt b/wrappers/wrapper_sdk_java/Readme.txt new file mode 100644 index 0000000..550c973 --- /dev/null +++ b/wrappers/wrapper_sdk_java/Readme.txt @@ -0,0 +1,134 @@ +***************************************************************************** +* README for DB2 Java Sample Wrapper +* +* NOTE: +* Inside this README file the samples and function directories are relative +* paths to the DB2 instance directory. Moreover, this README file assumes that +* the DB2 instance is installed at $HOME/sqllib, where $HOME represents the +* home directory of the current user. For example, if your DB2 instance is +* installed at /home/db2inst1/sqllib, than the full path of the samples +* directory is /home/db2inst1/sqllib/samples and the full path of the function +* directory is /home/db2inst1/sqllib/function. +* +* The samples/wrapper_sdk_java directory contains this README file, the javadoc +* files for the Java Wrapper API classes and the Java files for creating the +* Java sample flat-file wrapper. +* +* This README file describes the sample files in this directory. +* It is recommended that you copy the files from this directory to your +* working directory prior to building the sample program. +* +* To access and build the DB2 Java sample wrapper under the +* samples/wrapper_sdk_java directory, you must: +* +* 1. Install the DB2 Base Application Development Tools +* 2. Install the DB2 Sample Applications +* +* To run the DB2 Java sample wrapper under the samples/wrapper_sdk_java +* directory, you must install the DB2 Enterprise Server Edition. +* +* For information on developing Java wrappers for federated databases, +* see the IBM DB2 Information Integrator Wrapper Developer's Guide and +* the IBM DB2 Information Integrator Java API Reference for Developing +* Wrappers. +* +* For the latest information on developing and building Java applications +* for DB2, visit the DB2 Java website at +* http://www.software.ibm.com/data/db2/java. +* +***************************************************************************** +* +* QUICKSTART +* +* 1) Copy the files samples/wrapper_sdk_java/*.java to your working directory. +* +* 2) To deploy the Java sample wrapper, ensure that you have write permission +* to the $HOME/sqllib/function directory. +* +* 3) Compile and deploy the Java sample wrapper to sqllib/function by running +* the following command from a DB2 CLP window in your working directory. +* javac -classpath $HOME/sqllib/java/db2qgjava.jar:$CLASSPATH \ +* -d $HOME/sqllib/function \ +* UnfencedFileWrapper.java \ +* UnfencedFileServer.java \ +* UnfencedFileNickname.java \ +* FencedFileWrapper.java \ +* FencedFileServer.java \ +* FencedFileNickname.java \ +* FileConnection.java \ +* FileQuery.java \ +* FileExecDesc.java +* +* 4) To run the Java sample wrapper, you need to: +* +* 1. Enable the database for federation. +* By default, your database manager configuration parameter FEDERATED is +* set to NO. If this is true, update the database manager configuration +* using the following command: +* db2 update dbm cfg using FEDERATED YES +* +* 2. Set the database manager configuration parameter JDK_PATH to point to +* a valid JDK installation. To achieve that replace in +* the following command to the actual path for your JDK installation and +* execute the command: +* db2 update dbm cfg using JDK_PATH +* You can use an empty string, '', if you have a JDK installed under +* $HOME/sqllib/java/jdk directory. +* +* 3. Increase the heap size for the Java VM. +* By default, the Java VM heap size is set to 512 blocks of 4k. +* The recommended value for the sample wrapper is 1024 blocks of 4k +* or more. To set the Java VM heap size to 1024 blocks of 4k execute +* the following command: +* db2 update dbm cfg using JAVA_HEAP_SZ 1024 +* +* 4. After you have updated the database manager configuration, you have +* to restart DB2 using the following commands: +* db2 terminate +* db2stop +* db2start +* +* 5. Create a sample data file by executing the following commands: +* echo "1,first string" > $HOME/sample_file_a.txt +* echo "2,second string" >> $HOME/sample_file_a.txt +* echo "3,third string" >> $HOME/sample_file_a.txt +* +* 6. Connect to your database and create the wrapper by executing the +* appropriate command for your operating system: +* +* AIX: +* db2 "create wrapper file_wrapper library 'libdb2qgjava.a' \ +* options( UNFENCED_WRAPPER_CLASS 'UnfencedFileWrapper')" +* Linux: +* db2 "create wrapper file_wrapper library 'libdb2qgjava.so' \ +* options( UNFENCED_WRAPPER_CLASS 'UnfencedFileWrapper')" +* HPUX: +* db2 "create wrapper file_wrapper library 'libdb2qgjava.sl' \ +* options( UNFENCED_WRAPPER_CLASS 'UnfencedFileWrapper')" +* Solaris: +* db2 "create wrapper file_wrapper library 'libdb2qgjava.so' \ +* options( UNFENCED_WRAPPER_CLASS 'UnfencedFileWrapper')" +* +* 7. Create a server and a nickname by executing the following commands: +* db2 "create server file_server wrapper file_wrapper" +* db2 "create nickname file_a(number integer, text char(20)) \ +* for server file_server options(file_path '$HOME/sample_file_a.txt')" +* +* 8. Retrieve data from the sample nickname with the command: +* db2 "select * from file_a" +* +****************************************************************************** +* +* Java Sample Wrapper Description +* +* The Java Sample Wrapper demonstrate the process to build a Java wrapper for +* DB2 Information Integrator. A wrapper allows DB2 to obtain information from +* data sources that have a common programmatic interface. The process of +* writing a Java Wrapper consists in implementing a set of services in a +* collection of classes that extend and use the DB2 Information Integrator +* Java API for Developing Wrappers. +* For more information on the Java Sample Wrapper, refer to the Java Sample +* Wrapper source code files. +* +****************************************************************************** + diff --git a/wrappers/wrapper_sdk_java/UnfencedFileNickname.java b/wrappers/wrapper_sdk_java/UnfencedFileNickname.java new file mode 100644 index 0000000..ff37df3 --- /dev/null +++ b/wrappers/wrapper_sdk_java/UnfencedFileNickname.java @@ -0,0 +1,209 @@ +/********************************************************************** +* +* Source File Name = UnfencedFileNickname.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ + +import com.ibm.db2.wrapper.*; + +/** + * The UnfencedFileNickname represents a nickname of the file wrapper. + * In this case the nickname maps one to one with a flat text file containing the data. + * This class is responsible for validating information from the CREATE NICKNAME and ALTER NICKNAME statements. + * The UnfencedFileNickname is also instantiated and used in the query planning phase. + */ +public class UnfencedFileNickname extends UnfencedGenericNickname +{ + /** + * Construct a nickname with the specified schema and name for the specified server. + * + * @param schema The local DB2 nickname schema name. + * @param name The local DB2 nickname name. + * @param server The server containing this nickname. + * + */ + public UnfencedFileNickname(String schema, String name, UnfencedGenericServer server) + { + super(schema, name, server); + } + + /** + * Perform necessary nickname initialization. + * This method is called by the DB2 engine after the nickname is created or after the options are changed. + * This method is implemented by the wrapper to perform the nickname-specific initialization. + * The current implementation saves the file path into a class field. + * + * @param nicknameInfo The nickname catalog information. + * + * @exception WrapperException The DB2 error 1883 is thrown if the FILE_PATH option is not present. + */ + protected void initializeMyNickname(NicknameInfo nicknameInfo) throws WrapperException + { + // save the file path from NicknameInfo into a class field + CatalogOption option = nicknameInfo.getOption("FILE_PATH"); + + // be sure the option is present + if( option != null ) + { + _filePath = option.getValue(); + } + else + { + throw new WrapperException(-1883, "FFNVR", new String[] {"FILE_PATH", "Nickname", nicknameInfo.getNickname() }); + } + + } + + /** + * Function to verify the nickname information that is specified in CREATE NICKNAME statements. + * In this case, the function is a no-op because the nickname validation is done by the + * FencedFileNickname instance. + * + * @param nicknameInfo The nickname information specified in CREATE NICKNAME statement. + * + * @return Additional information that the wrapper wants to store in the DB2 UDB catalog. + * The current implementation returns null. + */ + protected NicknameInfo verifyMyRegisterNicknameInfo(NicknameInfo nicknameInfo) + { + // all verifications are on the fenced side. + // Here accept anything. + // Don't use default implementation because it will get upset about non-standard options. + return null; + } + + /** + * Function to verify the nickname information that is specified in ALTER NICKNAME statement. + * The current implementation accepts only the reserved nickname options and the FILE_PATH option. + * It also verifies the column data types and the column options. + * + * @param nicknameInfo The nickname information specified in ALTER NICKNAME statement. + * + * @return Additional information that the wrapper wants to store in the DB2 UDB catalog. + * The current implementation returns null. + * + * @exception WrapperException The DB2 errors 1881, 1883 and 1823 are thrown if the verification fails. + * + */ + protected NicknameInfo verifyMyAlterNicknameInfo(NicknameInfo nicknameInfo) throws WrapperException + { + // Walk through the list of options supplied in the DDL to : + // 1. Check to see if the user is not trying to drop the FILE_PATH option + // 2. Check to see if the user is not trying to alter an unknown option + boolean foundFilePath = false; + + CatalogOption option = nicknameInfo.getFirstOption(); + while( option != null ) + { + if( ! option.isReserved() ) + { + String optionName = option.getName(); + + if( optionName.equals("FILE_PATH") ) + { + if( option.getAction() == CatalogOption.DROP ) + { + throw new WrapperException(-1883, "FFNVA", new String[] {optionName, "Nickname", nicknameInfo.getNickname() }); + } + } + else + { + throw new WrapperException(-1881, "FFNVA", new String[] {optionName, "Nickname", nicknameInfo.getNickname() }); + } + } + + option = nicknameInfo.getNextOption(option); + } + + // check column types & options + verifyColumns(nicknameInfo); + + return null; + } + + /** + * Function to verify the column information that is specified in ALTER NICKNAME statement. + * The current implementation accepts only a subset of column types and the reserved colun options. + * + * @param nicknameInfo The nickname information specified in ALTER NICKNAME statement. + * The nicknameInfo object contains the column information too. + * + * @exception WrapperException The DB2 errors 1881 and 1823 are thrown if the verification fails. + * + */ + public void verifyColumns(NicknameInfo nicknameInfo) throws WrapperException + { + ColumnInfo columnInfo = nicknameInfo.getFirstColumn(); + while( columnInfo != null ) + { + String type = columnInfo.getTypeName(); + if( type != null && + ! type.equals("VARCHAR") && + ! type.equals("CHARACTER") && + ! type.equals("INTEGER") && + ! type.equals("DOUBLE") && + ! type.equals("DECIMAL") ) + { + throw new WrapperException(-1823, "FFNVC", new String[] { type, getServer().getName() } ); + } + + CatalogOption option = columnInfo.getFirstOption(); + while( option != null ) + { + if( ! option.isReserved() ) + { + throw new WrapperException(-1881, "FFNVC", new String[] {option.getName(), "Column", nicknameInfo.getNickname() }); + } + option = columnInfo.getNextOption(option); + } + + columnInfo = nicknameInfo.getNextColumn(columnInfo); + } + } + + /** + * Retrieve the index (position) of the column specified by its name. + * + * @param columnName The name of the column. + * + * @return The index(position) of the column with the given name. + * + * @exception Exception if the column with the given name cannot be found. + * + */ + public int getColumnIndex(String columnName) throws Exception + { + ColumnInfo column = getInfo().getColumn(columnName); + if( column == null ) + { + throw new Exception("The column " + columnName + " cannot be found."); + } + return column.getColumnID(); + } + + /** + * Retrieve the file path. + * + * @return The file path as extracted from the nickname catalog information. + * + */ + public String getFilePath() + { + return _filePath; + } + + /** + * The file path as extracted from the nickname catalog information. + */ + private String _filePath = null; + +} diff --git a/wrappers/wrapper_sdk_java/UnfencedFileServer.java b/wrappers/wrapper_sdk_java/UnfencedFileServer.java new file mode 100644 index 0000000..4c176ec --- /dev/null +++ b/wrappers/wrapper_sdk_java/UnfencedFileServer.java @@ -0,0 +1,387 @@ +/********************************************************************** +* +* Source File Name = UnfencedFileServer.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ + +import java.io.IOException; + +import com.ibm.db2.wrapper.*; +/** + * The UnfencedFileServer represents a server of the file wrapper. + * The Server maps to the remote data source, but since we are dealing with flat text files, + * the file server objects are responsible only for validating the CREATE SERVER and ALTER + * SERVER statements and to provide the user mapping and nickname objects. + */ +public class UnfencedFileServer extends UnfencedGenericServer +{ + /** + * Construct a server with the specified name for the specified wrapper. + * + * @param serverName The server name. + * @param wrapper The wrapper containing this server. + * + */ + public UnfencedFileServer(String serverName, UnfencedFileWrapper wrapper ) + { + super(serverName, wrapper); + } + + /** + * Create a nickname object that maps to a data collection at the remote data source. + * For the file wrapper, the data collection is a flat text file. + * + * @param schemaName The local DB2 nickname schema name. + * @param nickname The local DB2 nickname name. + * + * @return A nickname instance. + * + */ + protected Nickname createNickname(String schemaName, String nickname) + { + return new UnfencedFileNickname(schemaName, nickname, this); + } + + /** + * Analyze a proposed plan and determine what portion, if any, + * can be pushed down to the remote data source. + * The file wrapper accepts query fragments that contain only one + * nickname and it can only support one predicate. And the predicate + * should be column = 'cst' or 'cst' = column or column = unbound or + * unbound = column. + * The function constructs a Reply that describes the query + * fragment that the wrapper is able to execute/push down to the + * remote data source. It also constructs an execution descriptor + * object that DB2 will pass back to the wrapper at run-time and + * that is used internally by the wrapper during the query execution. + * + * + * @param request The Request object that contains the query to be planned. + * + * @return The Reply object that describes the query fragment that the + * wrapper is able to push down to the remote data source. + * + * @exception Exception if the processing fails. + * + */ + public Reply planRequest(Request request) throws Exception + { + // accept only one nickname in the query fragment + // the wrapper can't handle joins + if( request.getNumberOfQuantifiers() == 1 ) + { + Reply reply = createReply(request); + FileExecDesc execDesc = new FileExecDesc(); + + UnfencedFileNickname nick = null; + + // add the Quantifier handle to reply object + // by this we signal DB2 that the wrapper will handle this nickname + reply.addQuantifier( request.getQuantifier(1) ); + + // add the file path to the execution descriptor + // we do that because at runtime we don't have access to the nickname + nick = (UnfencedFileNickname) request.getQuantifier(1).getNickname(); + if( nick != null ) + { + execDesc.setFilePath( nick.getFilePath() ); + } + else + { + throw new Exception("Unknown nickname!"); + } + + // add the number of nickname columns to the execution descriptor + NicknameInfo nicknameInfo = nick.getInfo(); + execDesc.setNumberOfColumns( nicknameInfo.getNumColumns() ); + + // add the number of output columns to the execution descriptor + int n = request.getNumberOfHeadExp(); + execDesc.setNumberOfOutputColumns(n); + + // add the head expressions to the reply + // the wrapper has to provide the values for them at runtime + for(int i = 1; i <= n; i++) + { + RequestExp column = request.getHeadExp(i); + reply.addHeadExp( column ); + + execDesc.setOutputColumn(i-1, nick.getColumnIndex( column.getColumnName() ) ); // 0-based index + } + + //begin deal with predicate, firstly set it to be FileExecDesc.ALLROW + int predicate = FileExecDesc.ALLROW; + int number = request.getNumberOfPredicates(); + + //We only support one predicate, choose one that is valid for our conditions from all predicates + for(int i = 1; i <= number; i++) + { + //Get the predicate + RequestExp expression = request.getPredicate(i); + int kind = expression.getKind(); + + //We like only predicates that have an operator and 2 children + if(kind == RequestExp.OPERATOR && expression.getNumberOfChildren() == 2) + { + String token = expression.getToken(); + //We only support predicate '=' + if( token.length() != 1 || token.charAt(0) == '=' ) + { + RequestExp firstChild = expression.getFirstChild(); + RequestExp secondChild = firstChild.getNextChild(); + //We only support column = 'cst' or 'cst' = column or column = unbound or unbound = column + if(firstChild.getKind() == RequestExp.CONSTANT && secondChild.getKind() == RequestExp.COLUMN || + firstChild.getKind() == RequestExp.COLUMN && secondChild.getKind() == RequestExp.CONSTANT || + firstChild.getKind() == RequestExp.UNBOUND && secondChild.getKind() == RequestExp.COLUMN || + firstChild.getKind() == RequestExp.COLUMN && secondChild.getKind() == RequestExp.UNBOUND) + { + RequestConstant value = null; + String keyColumnName; + int bindIndex = -1; + + //form column = 'cst' or column = unbound + if(firstChild.getKind() == RequestExp.COLUMN) + { + // form column = 'cst' + if(secondChild.getKind() == RequestExp.CONSTANT) + { + value = secondChild.getValue(); + + //whether constant is null + if(value.isDataNull()) + { + throw new WrapperException( "Constant is Null!"); + } + } + else // form column = unbound + { + bindIndex++; + } + keyColumnName = firstChild.getColumnName(); + } + else //form 'cst' = column or unbound = column + { + //form 'cst' = column + if(firstChild.getKind() == RequestExp.CONSTANT) + { + value = firstChild.getValue(); + //whether constant is null + if(value.isDataNull()) + { + throw new WrapperException( "Constant is Null!"); + } + } + else //form unbound = column + { + bindIndex++; + } + keyColumnName = secondChild.getColumnName(); + } + + //Get the column no for the column + ColumnInfo columnInfo = nicknameInfo.getColumn(keyColumnName); + + if (columnInfo == null) + { + throw new WrapperException( "Key column not found"); + } + + execDesc.setKeyColumn(columnInfo.getColumnID()); + //Set unbound index + execDesc.setBindIndex(bindIndex); + //Set the data type for the form of column = 'cst' or 'cst' = column + if(bindIndex == -1) + { + execDesc.setDataType(value.getDataType()); + + //Set different kinds of value following the data type + switch(value.getDataType()) + { + case RuntimeData.CHAR: + case RuntimeData.VARCHAR: + { + execDesc.setConstString(value.getString()); + break; + } + case RuntimeData.INT: + { + execDesc.setConstInt(value.getInt()); + break; + } + case RuntimeData.DOUBLE: + { + execDesc.setConstDouble(value.getDouble()); + break; + } + case RuntimeData.FLOAT: + { + execDesc.setConstFloat(value.getFloat()); + break; + } + case RuntimeData.DECIMAL: + { + //Get scale for decimal + short scale = columnInfo.getOrgScale(); + execDesc.setConstDecimal(value.getBigDecimal()); + execDesc.setScale(scale); + break; + } + + default: + { + throw new WrapperException("Fetch: Unknown data type!"); + } + } + } + else //Set scale for the form of column = unbound or unbound = column + { + short scale = columnInfo.getOrgScale(); + execDesc.setScale(scale); + } + + //Change the predicate to FileExecDesc.EQUAL + predicate = FileExecDesc.EQUAL; + reply.addPredicate(expression); + break; + } + } + } + } + + //Set the predicate + execDesc.setPredicate(predicate); + //Set exec descriptor + reply.setExecDesc(execDesc); + //print the request for debugging & tracing + printRequest(request); + + return reply; + } + else // numberOfQuantifies > 1 + { + // for more than one quantifier we can't return any plan + // return a null reply + return null; + } + } + + /** + * Print the Request object that contains the query fragment to be printed. + * This function is used for debugging/tracing purposes. + * + * @param request The Request object that contains the query to be printed. + * + * @exception Exception if the procesing fails. + */ + private void printRequest(Request request) throws Exception + { + StringBuffer sBuffer = new StringBuffer(); + int n = request.getNumberOfHeadExp(); + + sBuffer.append("\nSELECT "); + + for(int i = 1; i <= n; i++) + { + RequestExp e = request.getHeadExp(i); + sBuffer.append("("); + printRequestExp(e, sBuffer); + sBuffer.append(")"); + if( i < n ) + { + sBuffer.append(", "); + } + } + sBuffer.append("\nFROM "); + + n = request.getNumberOfQuantifiers(); + for(int i = 1; i <= n; i++) + { + UnfencedGenericNickname nick = request.getQuantifier(i).getNickname(); + sBuffer.append(nick.getLocalSchema() + "." + nick.getLocalName()); + if( i < n ) + { + sBuffer.append(", "); + } + } + + sBuffer.append("\n"); + + n = request.getNumberOfPredicates(); + if( n > 0 ) + { + sBuffer.append("WHERE "); + for(int i = 1; i <= n; i++) + { + RequestExp e = request.getPredicate(i); + sBuffer.append("("); + printRequestExp(e, sBuffer); + sBuffer.append(")"); + if( i < n ) + { + sBuffer.append(", "); + } + } + + sBuffer.append("\n"); + } + + WrapperUtilities.traceFunctionData(0, "printRequest", 1, sBuffer.toString()); + } + + /** + * Print the RequestExp object that contains an expression, part of the query to be planned. + * This function is used for debugging/tracing purposes. + * + * @param expression The RequestExp object that contains the expression to be printed. + * @param sBuffer The string buffer where the expression is printed to. + * + * @exception Exception if the procesing fails. + */ + private void printRequestExp(RequestExp expression, StringBuffer sBuffer) throws Exception + { + int kind = expression.getKind(); + + switch(kind) + { + case RequestExp.BADKIND: + sBuffer.append("[]"); + break; + case RequestExp.COLUMN: + sBuffer.append("["); + sBuffer.append( expression.getColumnName()); + sBuffer.append("]"); + break; + case RequestExp.CONSTANT: + sBuffer.append("["); + sBuffer.append( expression.getValue().getObject().toString() ); + sBuffer.append("]"); + break; + case RequestExp.OPERATOR: + sBuffer.append("["); + sBuffer.append( expression.getToken()); + int n = expression.getNumberOfChildren(); + RequestExp e = null; + for(int i = 1; i <= n; i++ ) + { + e = i == 1? expression.getFirstChild() : e.getNextChild(); + printRequestExp(e, sBuffer); + } + sBuffer.append("]"); + break; + case RequestExp.UNBOUND: + sBuffer.append("[]"); + break; + default: + sBuffer.append("[]"); + } + } +} diff --git a/wrappers/wrapper_sdk_java/UnfencedFileWrapper.java b/wrappers/wrapper_sdk_java/UnfencedFileWrapper.java new file mode 100644 index 0000000..01fd14e --- /dev/null +++ b/wrappers/wrapper_sdk_java/UnfencedFileWrapper.java @@ -0,0 +1,79 @@ +/********************************************************************** +* +* Source File Name = UnfencedFileWrapper.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ + +import com.ibm.db2.wrapper.*; + +/** + * The UnfencedFileWrapper represents a wrapper to access flat text files. + */ +public class UnfencedFileWrapper extends UnfencedGenericWrapper +{ + /** + * Construct a new wrapper object. + * + */ + public UnfencedFileWrapper() + { + super(); + } + + /** + * Create a server object that represents a remote data source. + * + * @param serverName The name of the server object. + * + * @return A new server instance. + * + */ + protected Server createServer(String serverName) + { + Server s = new UnfencedFileServer(serverName, this); + return s; + } + + /** + * Function to verify the wrapper information that is specified in CREATE WRAPPER statement. + * The current implementation accepts only the reserved wrapper options and it sets the + * fenced wrapper class. + * + * @param wrapperInfo The wrapper information specified in CREATE WRAPPER statement. + * + * @return Additional information that the wrapper wants to store in the DB2 UDB catalog. + * The current implementation sets the fenced wrapper class. + * + * @exception WrapperException if the verification fails. + * + */ + protected WrapperInfo verifyMyRegisterWrapperInfo(WrapperInfo wrapperInfo) throws Exception + { + // check options + // accept only reserved wrapper options + // call the method on the base class to verify that + WrapperInfo wi = super.verifyMyRegisterWrapperInfo(wrapperInfo); + + // add FENCED_WRAPPER_CLASS option + // first, check whether the previous call returned a WrapperInfo object + // or we need to create a new one + if( wi == null ) + { + wi = new WrapperInfo(); + } + setFencedWrapperClass(wi, "FencedFileWrapper"); + + // return the newly created WrapperInfo object + // DB2 will merge the returned information with the catalog information + return wi; + } +} diff --git a/wrappers/wrapper_sdk_java/javadoc/allclasses-frame.html b/wrappers/wrapper_sdk_java/javadoc/allclasses-frame.html new file mode 100644 index 0000000..385af43 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/allclasses-frame.html @@ -0,0 +1,68 @@ + + + + + +All Classes (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + +

All Classes

+
+ + + diff --git a/wrappers/wrapper_sdk_java/javadoc/allclasses-noframe.html b/wrappers/wrapper_sdk_java/javadoc/allclasses-noframe.html new file mode 100644 index 0000000..f8a186d --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/allclasses-noframe.html @@ -0,0 +1,68 @@ + + + + + +All Classes (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + +

All Classes

+
+ + + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/CatalogInfo.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/CatalogInfo.html new file mode 100644 index 0000000..0240a43 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/CatalogInfo.html @@ -0,0 +1,348 @@ + + + + + +CatalogInfo (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class CatalogInfo

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.CatalogInfo
    • +
    +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    ColumnInfo, IndexInfo, NicknameInfo, RemoteFunctionInfo, RFuncParmInfo, ServerInfo, UserInfo, WrapperInfo
    +
    +
    +
    +
    public class CatalogInfo
    +extends java.lang.Object
    +
    CatalogInfo represents the base class for all the catalog classes + and provides the infrastructure to manage a list of options. + +

    + This class is a collection style class that stores a sequential list + of options that can be accessed either by their sequences or by their + option names. + This class uses the current option and the methods that relate to the option. + +

    + The CatalogInfo class is one of the catalog classes for the Java API.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      voidaddOption(java.lang.String optionName, + java.lang.String optionValue, + int action, + java.lang.String optionType, + java.lang.String objectName) +
      Add an option to the options chain.
      +
      voiddropOption(CatalogOption option) +
      Delete an option from the options chain.
      +
      CatalogOptiongetFirstOption() +
      Retrieve the first option from the chain.
      +
      CatalogOptiongetNextOption(CatalogOption currentOption) +
      Retrieve the next option from the chain.
      +
      CatalogOptiongetOption(java.lang.String optionName) +
      Retrieve the option object for the specified option name.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        addOption

        +
        public void addOption(java.lang.String optionName,
        +             java.lang.String optionValue,
        +             int action,
        +             java.lang.String optionType,
        +             java.lang.String objectName)
        +               throws WrapperException
        +
        Add an option to the options chain.
        +
        Parameters:
        optionName - The name of the option.
        optionValue - The value of the option.
        action - The action flag for the option. + Valid actions for the options are specified in CatalogOption class.
        optionType - The type of the object that owns the option. This parameter value is a token + that is used in the SQL1884 error message to identify the option type if this + is a duplicate option.
        objectName - The name of the object that owns the option. This parameter value is a token + that is used in the SQL1884 error message to identify the owner object name + if this is a duplicate option.
        +
        Throws:
        +
        WrapperException - if the option already exists in the chain or if the action is invalid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        dropOption

        +
        public void dropOption(CatalogOption option)
        +                throws WrapperException
        +
        Delete an option from the options chain.
        +
        Parameters:
        option - The option to be deleted.
        +
        Throws:
        +
        WrapperException - if the option object is null.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        CatalogOption
        +
      • +
      + + + +
        +
      • +

        getFirstOption

        +
        public final CatalogOption getFirstOption()
        +
        Retrieve the first option from the chain.
        +
        Returns:
        A CatalogOption instance that represents the first option + or null if no options are specified.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        CatalogOption
        +
      • +
      + + + +
        +
      • +

        getNextOption

        +
        public final CatalogOption getNextOption(CatalogOption currentOption)
        +
        Retrieve the next option from the chain.
        +
        Parameters:
        currentOption - The current option in the chain.
        +
        Returns:
        A CatalogOption instance that represents the next option + or null if there are no more options.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        CatalogOption
        +
      • +
      + + + +
        +
      • +

        getOption

        +
        public final CatalogOption getOption(java.lang.String optionName)
        +                              throws WrapperException
        +
        Retrieve the option object for the specified option name.
        +
        Parameters:
        optionName - The name of the option.
        +
        Returns:
        A CatalogOption instance that represents the searched option + or null if no option is found.
        +
        Throws:
        +
        WrapperException - if the option name is null.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        CatalogOption
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/CatalogOption.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/CatalogOption.html new file mode 100644 index 0000000..8dca5ab --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/CatalogOption.html @@ -0,0 +1,426 @@ + + + + + +CatalogOption (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class CatalogOption

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.CatalogOption
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public class CatalogOption
    +extends java.lang.Object
    +
    The CatalogOption class represents the base class for options of the catalog objects. + This class encapsulates one or more name-value pairs and links to the next option and the previous option. + +

    The CatalogOption class is one of the catalog classes for the Java API.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Summary

      + + + + + + + + + + + + + + + + + + + + + + +
      Fields 
      Modifier and TypeField and Description
      static intADD +
      Action constant; indicates that the option is added to the catalog.
      +
      static intDROP +
      Action constant; indicates that the option is dropped from the catalog.
      +
      static intNONE +
      Action constant; indicates no action for the option.
      +
      static intSET +
      Action constant; indicates that the option is set to a new value.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      intgetAction() +
      Retrieve the action for the option.
      +
      java.lang.StringgetName() +
      Retrieve the name of the option.
      +
      CatalogOptiongetNextOption() +
      Retrieve the next option in the chain that this option belongs to.
      +
      CatalogOptiongetPrevOption() +
      Retrieve the previous option in the chain that this option belongs to.
      +
      java.lang.StringgetValue() +
      Retrieve the option value.
      +
      booleanisReserved() +
      Indicate whether the option is a DB2-reserved option.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Detail

      + + + +
        +
      • +

        ADD

        +
        public static final int ADD
        +
        Action constant; indicates that the option is added to the catalog.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        DROP

        +
        public static final int DROP
        +
        Action constant; indicates that the option is dropped from the catalog.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        NONE

        +
        public static final int NONE
        +
        Action constant; indicates no action for the option.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        SET

        +
        public static final int SET
        +
        Action constant; indicates that the option is set to a new value. + The option to set to a new value must already be in the catalog.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getAction

        +
        public final int getAction()
        +
        Retrieve the action for the option.
        +
        Returns:
        The action.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getName

        +
        public final java.lang.String getName()
        +
        Retrieve the name of the option.
        +
        Returns:
        The option name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNextOption

        +
        public final CatalogOption getNextOption()
        +
        Retrieve the next option in the chain that this option belongs to.
        +
        Returns:
        The next option in the chain + or null if there are no more options.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPrevOption

        +
        public final CatalogOption getPrevOption()
        +
        Retrieve the previous option in the chain that this option belongs to.
        +
        Returns:
        The previous option in the chain + or null if there are no previous options.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getValue

        +
        public java.lang.String getValue()
        +
        Retrieve the option value.
        +
        Returns:
        The option value as a string.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isReserved

        +
        public final boolean isReserved()
        +
        Indicate whether the option is a DB2-reserved option.
        +
        Returns:
        true if the option is a DB2-reserved option, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ColumnInfo.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ColumnInfo.html new file mode 100644 index 0000000..6f278ff --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ColumnInfo.html @@ -0,0 +1,1311 @@ + + + + + +ColumnInfo (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class ColumnInfo

+
+
+ +
+
    +
  • +
    +
    +
    public final class ColumnInfo
    +extends CatalogInfo
    +
    The ColumnInfo class encapsulates catalog information for a column of a nickname. + This class includes column-statistical information. +

    The ColumnInfo class is one of the catalog classes for the Java API. +
    +
    Usage:
    + The ColumnInfo class is instantiated by the DB2 federated server to contain + information from a CREATE NICKNAME or an ALTER NICKNAME statement + or to contain information from the federated server's system catalog. + This class is instantiated by the wrapper when information is added + during CREATE NICKNAME or ALTER NICKNAME statement operations.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      ColumnInfo() +
      Construct a default (empty) column information object.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      voidaddOption(java.lang.String optionName, + java.lang.String optionValue, + int action) +
      Add an option to the options chain.
      +
      intgetAvgLength() +
      Retrieve the average length of the column.
      +
      shortgetCodepage1() +
      Retrieve the single-byte character set (SBCS) code page for the column.
      +
      shortgetCodepage2() +
      Retrieve the double-byte character set (DBCS) code page for the column.
      +
      longgetColCard() +
      Retrieve the cardinality of the column.
      +
      shortgetColumnID() +
      Retrieve the column ID.
      +
      java.lang.StringgetColumnName() +
      Retrieve the name of the column.
      +
      java.lang.StringgetColumnType() +
      Retrieve the type of the column.
      +
      java.lang.StringgetDefault() +
      Retrieve the default value for the column.
      +
      booleangetForBitData() +
      Retrieve the FOR BIT DATA flag for the column.
      +
      java.lang.StringgetHigh2Key() +
      Retrieve the second-highest value for the column.
      +
      java.lang.StringgetLow2Key() +
      Retrieve the second-lowest value for the column.
      +
      java.lang.StringgetNewColumnName() +
      Retrieve the new column name that is specified in an ALTER COLUMN + statement that includes an ALTER (or SET) COLUMN clause to rename the column.
      +
      ColumnInfogetNextColumn() +
      Retrieve the next column in the columns chain.
      +
      booleangetNulls() +
      Retrieve the nulls-allowed flag.
      +
      longgetNumNulls() +
      Retrieve the number of null values in the column, -1 if statistics are not collected.
      +
      intgetOrgLength() +
      Retrieve the maximum length (in bytes) for the column.
      +
      shortgetOrgScale() +
      Retrieve the numeric scale of the column.
      +
      java.lang.StringgetTypeName() +
      Retrieve the name of the local column type.
      +
      java.lang.StringgetTypeSchema() +
      Retrieve the schema of the local column type.
      +
      booleanisAvgLengthValid() +
      Verify whether an average length is specified for the column.
      +
      booleanisCodepage1Valid() +
      Verify whether a single-byte character set (SBCS) code page is specified for the column.
      +
      booleanisCodepage2Valid() +
      Verify whether a double-byte character set (DBCS) code page is specified for the column.
      +
      booleanisColCardValid() +
      Verify whether a cardinality value is specified for the column.
      +
      booleanisColumnIDValid() +
      Verify whether a column ID (position) is specified for the column.
      +
      booleanisColumnNameValid() +
      Verify whether a name is specified for the column.
      +
      booleanisColumnTypeValid() +
      Verify whether a local type is specified for the column.
      +
      booleanisDefaultValid() +
      Verify whether a default value is specified for the column.
      +
      booleanisForBitDataValid() +
      Verify whether a FOR BIT DATA flag is specified for the column.
      +
      booleanisHigh2KeyValid() +
      Verify whether a second-highest value is specified for the column.
      +
      booleanisLow2KeyValid() +
      Verify whether a second-lowest value is specified for the column.
      +
      booleanisNewColumnNameValid() +
      Verify whether a new name is specified for the column.
      +
      booleanisNullsValid() +
      Verify whether a nulls-allowed flag is specified for the column.
      +
      booleanisNumNullsValid() +
      Verify whether numNulls is specified for the column.
      +
      booleanisOrgLengthValid() +
      Verify whether an original length is specified for the column.
      +
      booleanisOrgScaleValid() +
      Verify whether an original scale is specified for the column.
      +
      booleanisTypeNameValid() +
      Verify whether a local type name is specified for the column.
      +
      booleanisTypeSchemaValid() +
      Verify whether a local type schema is specified for the column.
      +
      voidsetAvgLength(int avgLength) +
      Set the average length of the column.
      +
      voidsetCodepage1(short codepage1) +
      Set the single-byte character set (SBCS) code page for the column.
      +
      voidsetCodepage2(short codepage2) +
      Set the double-byte character set (DBCS) code page for the column.
      +
      voidsetColCard(long colCard) +
      Set the cardinality of the column.
      +
      voidsetColumnID(short columnID) +
      Set the column ID, which represents the position of he column.
      +
      voidsetColumnName(java.lang.String columnName) +
      Set the name of the column.
      +
      voidsetColumnType(java.lang.String columnType) +
      Set the type of the column.
      +
      voidsetDefault(java.lang.String defaultValue) +
      Set the default value for the column.
      +
      voidsetForBitData(boolean forBitData) +
      Set the FOR BIT DATA flag for the column.
      +
      voidsetHigh2Key(java.lang.String high2Key) +
      Set the second-highest value for the column.
      +
      voidsetLow2Key(java.lang.String low2Key) +
      Set the second-lowest value for the column.
      +
      voidsetNewColumnName(java.lang.String newColumnName) +
      Set the new name for the column.
      +
      voidsetNulls(boolean nulls) +
      Set the nulls-allowed flag.
      +
      voidsetNumNulls(long numNulls) +
      Set the number of null values in the column, -1 if statistics are not collected.
      +
      voidsetOrgLength(int orgLength) +
      Set the maximum length (in bytes) for the column.
      +
      voidsetOrgScale(short orgScale) +
      Set the numeric scale of the column.
      +
      voidsetTypeName(java.lang.String typeName) +
      Set the name of the local column type.
      +
      voidsetTypeSchema(java.lang.String typeSchema) +
      Set the schema of the local column type.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        ColumnInfo

        +
        public ColumnInfo()
        +
        Construct a default (empty) column information object.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        addOption

        +
        public void addOption(java.lang.String optionName,
        +             java.lang.String optionValue,
        +             int action)
        +               throws WrapperException
        +
        Add an option to the options chain.
        +
        Parameters:
        optionName - The name of the option.
        optionValue - The value of the option.
        action - The action flag for the option. + Valid actions for the options are specified in CatalogOption class.
        +
        Throws:
        +
        WrapperException - if the option already exists in the chain or if the action is invalid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getAvgLength

        +
        public int getAvgLength()
        +
        Retrieve the average length of the column.
        +
        Returns:
        The average column length.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getCodepage1

        +
        public short getCodepage1()
        +
        Retrieve the single-byte character set (SBCS) code page for the column.
        +
        Returns:
        The single-byte character set (SBCS) code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getCodepage2

        +
        public short getCodepage2()
        +
        Retrieve the double-byte character set (DBCS) code page for the column.
        +
        Returns:
        The double-byte character set (DBCS) code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getColCard

        +
        public long getColCard()
        +
        Retrieve the cardinality of the column.
        +
        Returns:
        The column cardinality.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getColumnID

        +
        public short getColumnID()
        +
        Retrieve the column ID. Represents the position of the column. + The first column is at position 0.
        +
        Returns:
        The column ID (position).
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getColumnName

        +
        public java.lang.String getColumnName()
        +
        Retrieve the name of the column.
        +
        Returns:
        The column name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getColumnType

        +
        public java.lang.String getColumnType()
        +
        Retrieve the type of the column.
        +
        Returns:
        The column type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDefault

        +
        public java.lang.String getDefault()
        +
        Retrieve the default value for the column.
        +
        Returns:
        The default value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getForBitData

        +
        public boolean getForBitData()
        +
        Retrieve the FOR BIT DATA flag for the column.
        +
        Returns:
        The value that indicates if the column has the FOR BIT DATA flag set.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getHigh2Key

        +
        public java.lang.String getHigh2Key()
        +
        Retrieve the second-highest value for the column.
        +
        Returns:
        The high2Key value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getLow2Key

        +
        public java.lang.String getLow2Key()
        +
        Retrieve the second-lowest value for the column.
        +
        Returns:
        The low2Key value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNewColumnName

        +
        public java.lang.String getNewColumnName()
        +
        Retrieve the new column name that is specified in an ALTER COLUMN + statement that includes an ALTER (or SET) COLUMN clause to rename the column.
        +
        Returns:
        The new column name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNextColumn

        +
        public ColumnInfo getNextColumn()
        +
        Retrieve the next column in the columns chain.
        +
        Returns:
        The next column in the chain or null if there are no more columns.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNulls

        +
        public boolean getNulls()
        +
        Retrieve the nulls-allowed flag.
        +
        Returns:
        The nulls-allowed flag.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNumNulls

        +
        public long getNumNulls()
        +
        Retrieve the number of null values in the column, -1 if statistics are not collected.
        +
        Returns:
        Number of nulls in the column
        Since:
        +
        IBM DB2 Information Integrator Version 9.5fp2
        +
      • +
      + + + +
        +
      • +

        getOrgLength

        +
        public int getOrgLength()
        +
        Retrieve the maximum length (in bytes) for the column.
        +
        Returns:
        The column length.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getOrgScale

        +
        public short getOrgScale()
        +
        Retrieve the numeric scale of the column.
        +
        Returns:
        The column scale.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getTypeName

        +
        public java.lang.String getTypeName()
        +
        Retrieve the name of the local column type.
        +
        Returns:
        The local type name of the column.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getTypeSchema

        +
        public java.lang.String getTypeSchema()
        +
        Retrieve the schema of the local column type.
        +
        Returns:
        The local type schema name of the column.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isAvgLengthValid

        +
        public boolean isAvgLengthValid()
        +
        Verify whether an average length is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isCodepage1Valid

        +
        public boolean isCodepage1Valid()
        +
        Verify whether a single-byte character set (SBCS) code page is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isCodepage2Valid

        +
        public boolean isCodepage2Valid()
        +
        Verify whether a double-byte character set (DBCS) code page is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isColCardValid

        +
        public boolean isColCardValid()
        +
        Verify whether a cardinality value is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isColumnIDValid

        +
        public boolean isColumnIDValid()
        +
        Verify whether a column ID (position) is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isColumnNameValid

        +
        public boolean isColumnNameValid()
        +
        Verify whether a name is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isColumnTypeValid

        +
        public boolean isColumnTypeValid()
        +
        Verify whether a local type is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isDefaultValid

        +
        public boolean isDefaultValid()
        +
        Verify whether a default value is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isForBitDataValid

        +
        public boolean isForBitDataValid()
        +
        Verify whether a FOR BIT DATA flag is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isHigh2KeyValid

        +
        public boolean isHigh2KeyValid()
        +
        Verify whether a second-highest value is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isLow2KeyValid

        +
        public boolean isLow2KeyValid()
        +
        Verify whether a second-lowest value is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isNewColumnNameValid

        +
        public boolean isNewColumnNameValid()
        +
        Verify whether a new name is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isNullsValid

        +
        public boolean isNullsValid()
        +
        Verify whether a nulls-allowed flag is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isNumNullsValid

        +
        public boolean isNumNullsValid()
        +
        Verify whether numNulls is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 9.5fp2
        +
      • +
      + + + +
        +
      • +

        isOrgLengthValid

        +
        public boolean isOrgLengthValid()
        +
        Verify whether an original length is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isOrgScaleValid

        +
        public boolean isOrgScaleValid()
        +
        Verify whether an original scale is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isTypeNameValid

        +
        public boolean isTypeNameValid()
        +
        Verify whether a local type name is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isTypeSchemaValid

        +
        public boolean isTypeSchemaValid()
        +
        Verify whether a local type schema is specified for the column.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setAvgLength

        +
        public void setAvgLength(int avgLength)
        +
        Set the average length of the column.
        +
        Parameters:
        avgLength - The length to be set.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setCodepage1

        +
        public void setCodepage1(short codepage1)
        +
        Set the single-byte character set (SBCS) code page for the column.
        +
        Parameters:
        codepage1 - The single-byte character set (SBCS) code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setCodepage2

        +
        public void setCodepage2(short codepage2)
        +
        Set the double-byte character set (DBCS) code page for the column.
        +
        Parameters:
        codepage2 - The double-byte character set (DBCS) code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setColCard

        +
        public void setColCard(long colCard)
        +
        Set the cardinality of the column. + The wrapper sets the column cardinality (if known) during CREATE + NICKNAME or ALTER NICKNAME statement processing. The DB2 + optimizer uses this information when it generates an optimal + performance plan. For columns with distinct values (no duplicates), + the column cardinality must be the same as the nickname cardinality. + The DB2 optimizer generates an error if the column cardinality is + greater than the nickname cardinality.
        +
        Parameters:
        colCard - The column cardinality.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setColumnID

        +
        public void setColumnID(short columnID)
        +
        Set the column ID, which represents the position of he column. + The first column is at position 0.
        +
        Parameters:
        columnID - The ID (position) of the column.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setColumnName

        +
        public void setColumnName(java.lang.String columnName)
        +
        Set the name of the column.
        +
        Parameters:
        columnName - The name to be set.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setColumnType

        +
        public void setColumnType(java.lang.String columnType)
        +
        Set the type of the column.
        +
        Parameters:
        columnType - The column type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setDefault

        +
        public void setDefault(java.lang.String defaultValue)
        +
        Set the default value for the column.
        +
        Parameters:
        defaultValue - The default value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setForBitData

        +
        public void setForBitData(boolean forBitData)
        +
        Set the FOR BIT DATA flag for the column.
        +
        Parameters:
        forBitData - The FOR BIT DATA flag.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setHigh2Key

        +
        public void setHigh2Key(java.lang.String high2Key)
        +
        Set the second-highest value for the column. + The wrapper can set the second-highest value of a column during + CREATE NICKNAME or ALTER NICKNAME statement processing. + The DB2 optimizer can use this second-highest value or the highest + value when the optimizer develops an optimized query plan.
        +
        Parameters:
        high2Key - The high2Key value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setLow2Key

        +
        public void setLow2Key(java.lang.String low2Key)
        +
        Set the second-lowest value for the column. + The wrapper can set the second-lowest value of a column during + CREATE NICKNAME or ALTER NICKNAME statement processing. + The DB2 optimizer can use this second-lowest value or the lowest + value when the optimizer develops an optimized query plan.
        +
        Parameters:
        low2Key - The low2Key value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNewColumnName

        +
        public void setNewColumnName(java.lang.String newColumnName)
        +
        Set the new name for the column. + Set the new column name that is specified in an ALTER + COLUMN statement that includes an ALTER or SET COLUMN + clause to rename the column.
        +
        Parameters:
        newColumnName - The new column name to be set.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNulls

        +
        public void setNulls(boolean nulls)
        +
        Set the nulls-allowed flag.
        +
        Parameters:
        nulls - True to allow null values. False to disallow null values.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNumNulls

        +
        public void setNumNulls(long numNulls)
        +
        Set the number of null values in the column, -1 if statistics are not collected.
        +
        Parameters:
        numNulls - Number of null values in the column.
        Since:
        +
        IBM DB2 Information Integrator Version 9.5fp2
        +
      • +
      + + + +
        +
      • +

        setOrgLength

        +
        public void setOrgLength(int orgLength)
        +
        Set the maximum length (in bytes) for the column.
        +
        Parameters:
        orgLength - The length to be set.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setOrgScale

        +
        public void setOrgScale(short orgScale)
        +
        Set the numeric scale of the column.
        +
        Parameters:
        orgScale - The scale to be set.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setTypeName

        +
        public void setTypeName(java.lang.String typeName)
        +
        Set the name of the local column type.
        +
        Parameters:
        typeName - The local type name of the column.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setTypeSchema

        +
        public void setTypeSchema(java.lang.String typeSchema)
        +
        Set the schema of the local column type.
        +
        Parameters:
        typeSchema - The local type schema name of the column.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Data.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Data.html new file mode 100644 index 0000000..15ac2ee --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Data.html @@ -0,0 +1,879 @@ + + + + + +Data (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class Data

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.Data
    • +
    +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    RequestConstant, RuntimeData
    +
    +
    +
    +
    public abstract class Data
    +extends java.lang.Object
    +
    The Data class is the base class that manages cell values, + constants, and parameter values. + This class provides methods to convert the values from + internal formats into Java standard types and objects.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Fields 
      Modifier and TypeField and Description
      static shortBLOB +
      Constant that indicates a BLOB data type.
      +
      static shortCHAR +
      Constant that indicates a CHAR data type.
      +
      static shortCLOB +
      Constant that indicates a CLOB data type.
      +
      static shortDATE +
      Constant that indicates a DATE data type.
      +
      static shortDECIMAL +
      Constant that indicates a DECIMAL or NUMERIC data type.
      +
      static shortDOUBLE +
      Constant that indicates a DOUBLE data type.
      +
      static shortFLOAT +
      Constant that indicates a FLOAT data type.
      +
      static shortINT +
      Constant that indicates an INTEGER (INT) data type.
      +
      static shortLONG +
      Constant that indicates a LONG data type.
      +
      static shortNONE +
      Constant that indicates an unknown data type.
      +
      static shortSHORT +
      Constant that indicates a SHORT data type.
      +
      static shortSQL_NO_NULLS +
      Constant that indicates the column NULL status as NO NULLS.
      +
      static shortSQL_NULLABLE +
      Constant that indicates the column NULL status as NULLABLE.
      +
      static shortSQL_NULLABLE_UNKNOWN +
      Constant that indicates the column NULL status as UNKNOWN.
      +
      static shortTIME +
      Constant that indicates a TIME data type.
      +
      static shortTIMESTAMP +
      Constant that indicates a TIMESTAMP data type.
      +
      static shortVARCHAR +
      Constant that indicates a VARCHAR data type.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      java.math.BigDecimalgetBigDecimal() +
      Retrieve the data as a BigDecimal instance.
      +
      bytegetByte() +
      Retrieve the data as a byte value.
      +
      protected abstract byte[]getData() +
      Retrieve the data as a byte array.
      +
      abstract shortgetDataType() +
      Retrieve the data type.
      +
      java.sql.DategetDate() +
      Retrieve the data as a Date instance.
      +
      doublegetDouble() +
      Retrieve the data as a double value.
      +
      floatgetFloat() +
      Retrieve the data as a float value.
      +
      abstract booleangetForBitData() +
      Retrieve the FOR BIT DATA flag.
      +
      intgetInt() +
      Retrieve the data as an integer (int) value.
      +
      longgetLong() +
      Retrieve the data as a long value.
      +
      java.lang.ObjectgetObject() +
      Retrieve the data as an Object instance.
      +
      shortgetShort() +
      Retrieve the data as a short value.
      +
      java.lang.StringgetString() +
      Retrieve the data as a string.
      +
      java.sql.TimegetTime() +
      Retrieve the data as a Time instance.
      +
      java.sql.TimestampgetTimestamp() +
      Retrieve the data as a Timestamp instance.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Detail

      + + + +
        +
      • +

        BLOB

        +
        public static final short BLOB
        +
        Constant that indicates a BLOB data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        CHAR

        +
        public static final short CHAR
        +
        Constant that indicates a CHAR data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        CLOB

        +
        public static final short CLOB
        +
        Constant that indicates a CLOB data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        DATE

        +
        public static final short DATE
        +
        Constant that indicates a DATE data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        DECIMAL

        +
        public static final short DECIMAL
        +
        Constant that indicates a DECIMAL or NUMERIC data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        DOUBLE

        +
        public static final short DOUBLE
        +
        Constant that indicates a DOUBLE data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        FLOAT

        +
        public static final short FLOAT
        +
        Constant that indicates a FLOAT data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        INT

        +
        public static final short INT
        +
        Constant that indicates an INTEGER (INT) data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        LONG

        +
        public static final short LONG
        +
        Constant that indicates a LONG data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        NONE

        +
        public static final short NONE
        +
        Constant that indicates an unknown data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        SHORT

        +
        public static final short SHORT
        +
        Constant that indicates a SHORT data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        SQL_NO_NULLS

        +
        public static final short SQL_NO_NULLS
        +
        Constant that indicates the column NULL status as NO NULLS.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2 fp10
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        SQL_NULLABLE

        +
        public static final short SQL_NULLABLE
        +
        Constant that indicates the column NULL status as NULLABLE.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2 fp10
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        SQL_NULLABLE_UNKNOWN

        +
        public static final short SQL_NULLABLE_UNKNOWN
        +
        Constant that indicates the column NULL status as UNKNOWN.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2 fp10
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        TIME

        +
        public static final short TIME
        +
        Constant that indicates a TIME data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        TIMESTAMP

        +
        public static final short TIMESTAMP
        +
        Constant that indicates a TIMESTAMP data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        VARCHAR

        +
        public static final short VARCHAR
        +
        Constant that indicates a VARCHAR data type.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getBigDecimal

        +
        public java.math.BigDecimal getBigDecimal()
        +                                   throws WrapperException
        +
        Retrieve the data as a BigDecimal instance.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getByte

        +
        public byte getByte()
        +             throws WrapperException
        +
        Retrieve the data as a byte value.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getData

        +
        protected abstract byte[] getData()
        +                           throws WrapperException
        +
        Retrieve the data as a byte array. + The value is in an internal format.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - - if the processing fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDataType

        +
        public abstract short getDataType()
        +
        Retrieve the data type.
        +
        Returns:
        The data type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDate

        +
        public java.sql.Date getDate()
        +                      throws WrapperException
        +
        Retrieve the data as a Date instance.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDouble

        +
        public double getDouble()
        +                 throws WrapperException
        +
        Retrieve the data as a double value.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getFloat

        +
        public float getFloat()
        +               throws WrapperException
        +
        Retrieve the data as a float value.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getForBitData

        +
        public abstract boolean getForBitData()
        +
        Retrieve the FOR BIT DATA flag. + Use this method only for CHAR or VARCHAR + data types to indicate whether the data is stored in a + binary format.
        +
        Returns:
        The FOR BIT DATA flag.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getInt

        +
        public int getInt()
        +           throws WrapperException
        +
        Retrieve the data as an integer (int) value.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getLong

        +
        public long getLong()
        +             throws WrapperException
        +
        Retrieve the data as a long value.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getObject

        +
        public java.lang.Object getObject()
        +                           throws WrapperException
        +
        Retrieve the data as an Object instance.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getShort

        +
        public short getShort()
        +               throws WrapperException
        +
        Retrieve the data as a short value.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getString

        +
        public java.lang.String getString()
        +                           throws WrapperException
        +
        Retrieve the data as a string.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getTime

        +
        public java.sql.Time getTime()
        +                      throws WrapperException
        +
        Retrieve the data as a Time instance.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getTimestamp

        +
        public java.sql.Timestamp getTimestamp()
        +                                throws WrapperException
        +
        Retrieve the data as a Timestamp instance.
        +
        Returns:
        The data.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/DefaultRemoteFunction.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/DefaultRemoteFunction.html new file mode 100644 index 0000000..1b6c987 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/DefaultRemoteFunction.html @@ -0,0 +1,832 @@ + + + + + +DefaultRemoteFunction (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class DefaultRemoteFunction

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.DefaultRemoteFunction
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public final class DefaultRemoteFunction
    +extends java.lang.Object
    +
    The DefaultRemoteFunction class represents a simple remote function + mapping. It can be used within the UnfencedServer.insertRemoteFunction(DefaultRemoteFunction) + method to add a temporary function mapping definition to the UnfencedServer object.
    +
    Since:
    +
    IBM WebSphere Information Integrator Version 9.1
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + + +
      Constructors 
      Constructor and Description
      DefaultRemoteFunction() +
      Class constructor
      +
      DefaultRemoteFunction(java.lang.String localSignature, + java.lang.String remoteFunctionName, + short remoteResultType, + double iosPerInvoke, + double instsPerInvoke, + double iosPerArgByte, + double instsPerArgByte, + short percentArgByte, + double initialIos, + double initialInsts) +
      Construct an instance with the specified values.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      doublegetInitialInsts() +
      Returns the number of machine instructions executed the first time the function is executed
      +
      doublegetInitialIos() +
      Returns the number of I/O operations the first time the function is executed
      +
      doublegetInstsPerArgByte() +
      Returns the number of machine instructions per byte of argument for one invocation of the function.
      +
      doublegetInstsPerInvoke() +
      Returns the number of machine instructions per invocation of the function.
      +
      doublegetIosPerArgByte() +
      Returns the number of I/O operations per byte of argument for one invocation of the function.
      +
      doublegetIosPerInvoke() +
      Returns the number of I/O operations per invocation of the function.
      +
      java.lang.StringgetLocalSignature() +
      Returns the local signature of the function
      +
      shortgetPercentArgByte() +
      Retruns the precentage of arguments bytes
      +
      java.lang.StringgetRemoteFunctionName() +
      Returns the remote name of the function
      +
      shortgetRemoteResultType() +
      Returns the result type of the function.
      +
      booleanisInitialInstsValid() +
      Check to see if a value for the number of machine instructions executed the first time the function is executed was specified
      +
      booleanisInitialIosValid() +
      Check to see if a value for the number of I/O operations the first time the function is executed was specified
      +
      booleanisInstsPerArgByteValid() +
      Check to see if a value for the number of machine instructions per byte of argument for one invocation was specified
      +
      booleanisInstsPerInvokeValid() +
      Check to see if a value for the number of machine instructions per invocation was specified
      +
      booleanisIosPerArgByteValid() +
      Check to see if a value for the number of I/O operations per byte of argument for one invocation was specified
      +
      booleanisIosPerInvokeValid() +
      Check to see if a value for the number of I/O operations per invocation was specified
      +
      booleanisLocalSignatureValid() +
      Check to see if a local function signature was specified
      +
      booleanisPercentArgByteValid() +
      Check to see if a value for the percentage of arguments bytes was specified
      +
      booleanisRemoteFunctionNameValid() +
      Check to see if a remote function name was specified
      +
      booleanisRemoteResultTypeValid() +
      Check to see if a remote result type was specified
      +
      voidsetInitialInsts(double initialInsts) +
      Set the value for the number of machine instructions executed the first time the function is executed
      +
      voidsetInitialIos(double initialIos) +
      Set the value for the number of I/O operations the first time the function is executed
      +
      voidsetInstsPerArgByte(double instsPerArgByte) +
      Set the value for the number of machine instructions per byte of argument for one invocation of the function.
      +
      voidsetInstsPerInvoke(double instsPerInvoke) +
      Set the value for the number of machine instructions per invocation of the function.
      +
      voidsetIosPerArgByte(double iosPerArgByte) +
      Set the value for the number of I/O operations per byte of argument for one invocation of the function.
      +
      voidsetIosPerInvoke(double iosPerInvoke) +
      Set the value for the number of I/O operations per invocation of the function.
      +
      voidsetLocalSignature(java.lang.String localSignature) +
      Set the value for the local signature.
      +
      voidsetPercentArgByte(short percentArgByte) +
      Set the value for the percentage of arguments bytes
      +
      voidsetRemoteFunctionName(java.lang.String remoteFunctionName) +
      Set the value for the remote function name.
      +
      voidsetRemoteResultType(short remoteResultType) +
      Set the value for the result type.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        DefaultRemoteFunction

        +
        public DefaultRemoteFunction()
        +
        Class constructor
        +
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        DefaultRemoteFunction

        +
        public DefaultRemoteFunction(java.lang.String localSignature,
        +                     java.lang.String remoteFunctionName,
        +                     short remoteResultType,
        +                     double iosPerInvoke,
        +                     double instsPerInvoke,
        +                     double iosPerArgByte,
        +                     double instsPerArgByte,
        +                     short percentArgByte,
        +                     double initialIos,
        +                     double initialInsts)
        +
        Construct an instance with the specified values.
        +
        Parameters:
        localSignature - The local signature
        remoteFunctionName - The remote function name
        remoteResultType - The return type of the function.
        iosPerInvoke - number of I/O operations per invocation.
        instsPerInvoke - number of machine instructions per invocation.
        iosPerArgByte - number of I/O operations per byte of argument.
        instsPerArgByte - number of machine instructions per byte of argument.
        percentArgByte - precentage of arguments bytes
        initialIos - number of I/O operations
        initialInsts - number of machine instructions
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getInitialInsts

        +
        public double getInitialInsts()
        +
        Returns the number of machine instructions executed the first time the function is executed
        +
        Returns:
        number of machine instructions
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        getInitialIos

        +
        public double getInitialIos()
        +
        Returns the number of I/O operations the first time the function is executed
        +
        Returns:
        number of I/O operations
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        getInstsPerArgByte

        +
        public double getInstsPerArgByte()
        +
        Returns the number of machine instructions per byte of argument for one invocation of the function.
        +
        Returns:
        number of machine instructions per byte of argument.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        getInstsPerInvoke

        +
        public double getInstsPerInvoke()
        +
        Returns the number of machine instructions per invocation of the function.
        +
        Returns:
        number of machine instructions per invocation.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        getIosPerArgByte

        +
        public double getIosPerArgByte()
        +
        Returns the number of I/O operations per byte of argument for one invocation of the function.
        +
        Returns:
        number of I/O operations per byte of argument.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        getIosPerInvoke

        +
        public double getIosPerInvoke()
        +
        Returns the number of I/O operations per invocation of the function.
        +
        Returns:
        number of I/O operations per invocation.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        getLocalSignature

        +
        public java.lang.String getLocalSignature()
        +
        Returns the local signature of the function
        +
        Returns:
        local signature
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        getPercentArgByte

        +
        public short getPercentArgByte()
        +
        Retruns the precentage of arguments bytes
        +
        Returns:
        percentage of arguments bytes
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        getRemoteFunctionName

        +
        public java.lang.String getRemoteFunctionName()
        +
        Returns the remote name of the function
        +
        Returns:
        remote function name
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        getRemoteResultType

        +
        public short getRemoteResultType()
        +
        Returns the result type of the function. This can be any + data type defined in Data.
        +
        Returns:
        result type
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isInitialInstsValid

        +
        public boolean isInitialInstsValid()
        +
        Check to see if a value for the number of machine instructions executed the first time the function is executed was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isInitialIosValid

        +
        public boolean isInitialIosValid()
        +
        Check to see if a value for the number of I/O operations the first time the function is executed was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isInstsPerArgByteValid

        +
        public boolean isInstsPerArgByteValid()
        +
        Check to see if a value for the number of machine instructions per byte of argument for one invocation was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isInstsPerInvokeValid

        +
        public boolean isInstsPerInvokeValid()
        +
        Check to see if a value for the number of machine instructions per invocation was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isIosPerArgByteValid

        +
        public boolean isIosPerArgByteValid()
        +
        Check to see if a value for the number of I/O operations per byte of argument for one invocation was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isIosPerInvokeValid

        +
        public boolean isIosPerInvokeValid()
        +
        Check to see if a value for the number of I/O operations per invocation was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isLocalSignatureValid

        +
        public boolean isLocalSignatureValid()
        +
        Check to see if a local function signature was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isPercentArgByteValid

        +
        public boolean isPercentArgByteValid()
        +
        Check to see if a value for the percentage of arguments bytes was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isRemoteFunctionNameValid

        +
        public boolean isRemoteFunctionNameValid()
        +
        Check to see if a remote function name was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isRemoteResultTypeValid

        +
        public boolean isRemoteResultTypeValid()
        +
        Check to see if a remote result type was specified
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setInitialInsts

        +
        public void setInitialInsts(double initialInsts)
        +
        Set the value for the number of machine instructions executed the first time the function is executed
        +
        Parameters:
        initialInsts - number of machine instructions
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setInitialIos

        +
        public void setInitialIos(double initialIos)
        +
        Set the value for the number of I/O operations the first time the function is executed
        +
        Parameters:
        initialIos - number of I/O operations
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setInstsPerArgByte

        +
        public void setInstsPerArgByte(double instsPerArgByte)
        +
        Set the value for the number of machine instructions per byte of argument for one invocation of the function.
        +
        Parameters:
        instsPerArgByte - number of machine instructions per byte of argument.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setInstsPerInvoke

        +
        public void setInstsPerInvoke(double instsPerInvoke)
        +
        Set the value for the number of machine instructions per invocation of the function.
        +
        Parameters:
        instsPerInvoke - number of machine instructions per invocation.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setIosPerArgByte

        +
        public void setIosPerArgByte(double iosPerArgByte)
        +
        Set the value for the number of I/O operations per byte of argument for one invocation of the function.
        +
        Parameters:
        iosPerArgByte - number of I/O operations per byte of argument.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setIosPerInvoke

        +
        public void setIosPerInvoke(double iosPerInvoke)
        +
        Set the value for the number of I/O operations per invocation of the function.
        +
        Parameters:
        iosPerInvoke - number of I/O operations per invocation.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setLocalSignature

        +
        public void setLocalSignature(java.lang.String localSignature)
        +
        Set the value for the local signature. The name consists of the + schema and signature of the local function - for example: "SYSIBM.+(FLOAT, FLOAT)"
        +
        Parameters:
        localSignature - The local signature
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setPercentArgByte

        +
        public void setPercentArgByte(short percentArgByte)
        +
        Set the value for the percentage of arguments bytes
        +
        Parameters:
        percentArgByte - precentage of arguments bytes
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setRemoteFunctionName

        +
        public void setRemoteFunctionName(java.lang.String remoteFunctionName)
        +
        Set the value for the remote function name. The name should be provided in the V-2 style - for example: "LENGTH(1P, 2P)"
        +
        Parameters:
        remoteFunctionName - The remote function name
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setRemoteResultType

        +
        public void setRemoteResultType(short remoteResultType)
        +
        Set the value for the result type. This can be any + data type defined in Data.
        +
        Parameters:
        remoteResultType - The return type of the function.
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericNickname.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericNickname.html new file mode 100644 index 0000000..3b906ff --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericNickname.html @@ -0,0 +1,274 @@ + + + + + +FencedGenericNickname (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class FencedGenericNickname

+
+
+ +
+
    +
  • +
    +
    +
    public class FencedGenericNickname
    +extends FencedNickname
    +
    The FencedGenericNickname class represents a nonrelational nickname + in the fenced (untrusted) process space. This class is responsible for validating + information from the CREATE NICKNAME statement. + +

    Usage:
    + The wrapper must implement a subclass of FencedGenericNickname. This class is + instantiated by the wrapper in the createNickname + method of the wrapper-specific subclass of FencedGenericServer.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        FencedGenericNickname

        +
        protected FencedGenericNickname(java.lang.String schema,
        +                     java.lang.String name,
        +                     FencedGenericServer server)
        +
        Construct a nickname with the specified schema and name for the specified data source server.
        +
        Parameters:
        schema - The local DB2 Information Integrator schema name + for the remote data set that is defined for this nickname.
        name - The local DB2 Information Integrator name for the remote + data set that is defined for this nickname.
        server - The data source server object that contains the nickname.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericRemoteUser.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericRemoteUser.html new file mode 100644 index 0000000..0314c13 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericRemoteUser.html @@ -0,0 +1,286 @@ + + + + + +FencedGenericRemoteUser (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class FencedGenericRemoteUser

+
+
+ +
+
    +
  • +
    +
    +
    public class FencedGenericRemoteUser
    +extends FencedRemoteUser
    +
    The FencedGenericRemoteUser class represents a user mapping + for a nonrelational data source in the fenced (untrusted) process space. + +

    Usage:
    + This class is instantiated by the wrapper in the + createRemoteUser method of the + wrapper-specific subclass of FencedGenericServer class. + The wrapper implements a subclass of FencedGenericRemoteUser if + wrapper-specific user mapping options are supported.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        FencedGenericRemoteUser

        +
        public FencedGenericRemoteUser(java.lang.String localName,
        +                       FencedGenericServer server)
        +
        Construct a user mapping with a specified name for the specified data source server.
        +
        Parameters:
        localName - The local DB2 Information Integrator name of the user mapping.
        server - The server object that contains the user mapping.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        FencedRemoteUser, +FencedGenericServer
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericServer.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericServer.html new file mode 100644 index 0000000..720905a --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericServer.html @@ -0,0 +1,328 @@ + + + + + +FencedGenericServer (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class FencedGenericServer

+
+
+ +
+
    +
  • +
    +
    +
    public class FencedGenericServer
    +extends FencedServer
    +
    The FencedGenericServer class is a subclass of the Server class and is the + abstract base class for all nonrelational data source server functionality + that operates in the fenced (untrusted) process space. + This class is responsible for creating remote connections and nicknames. + +

    Usage:
    + The wrapper must implement a subclass of FencedGenericServer class. + This class is instantiated by the wrapper in the createServer + method of the wrapper-specific subclass of the FencedGenericWrapper class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        FencedGenericServer

        +
        protected FencedGenericServer(java.lang.String name,
        +                   FencedGenericWrapper wrapper)
        +
        Construct a FencedGenericServer object for the specified wrapper with the specified name.
        +
        Parameters:
        name - The name of the data source server.
        wrapper - The wrapper object that contains the data source server.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        FencedGenericWrapper, +FencedServer
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        createRemoteUser

        +
        protected RemoteUser createRemoteUser(java.lang.String userName)
        +                               throws java.lang.Exception
        +
        Instantiate an appropriate RemoteUser subclass for this data source server. + By default, the createRemoteUser method creates an instance of the + FencedGenericRemoteUser class. + The wrapper can implement this method in the wrapper-specific + data source server subclass. The wrapper writer must implement this method + if a wrapper-specific subclass of the FencedGenericRemoteUser class is + implemented.
        +
        +
        Overrides:
        +
        createRemoteUser in class Server
        +
        Parameters:
        userName - The name of the remote user mapping to be created as + specified in the CREATE USER MAPPING statement.
        +
        Returns:
        The newly created FencedGenericRemoteUser instance.
        +
        Throws:
        +
        java.lang.Exception - if a new RemoteUser instance cannot be created.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteUser
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericWrapper.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericWrapper.html new file mode 100644 index 0000000..fac5fc4 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedGenericWrapper.html @@ -0,0 +1,310 @@ + + + + + +FencedGenericWrapper (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class FencedGenericWrapper

+
+
+ +
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + +
      Constructors 
      ModifierConstructor and Description
      protected FencedGenericWrapper() +
      Construct a new FencedGenricWrapper object.
      +
      +
    • +
    + + +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        FencedGenericWrapper

        +
        protected FencedGenericWrapper()
        +
        Construct a new FencedGenricWrapper object.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        FencedWrapper
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getType

        +
        public char getType()
        +
        Retrieve the wrapper type. + A default implementation returns a value of N. N is the only valid value.
        +
        +
        Overrides:
        +
        getType in class Wrapper
        +
        Returns:
        The type of the wrapper. By default, this method returns a value of N.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Wrapper
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedNickname.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedNickname.html new file mode 100644 index 0000000..aa0a899 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedNickname.html @@ -0,0 +1,221 @@ + + + + + +FencedNickname (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class FencedNickname

+
+
+
    +
  • java.lang.Object
  • +
  • + +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    FencedGenericNickname
    +
    +
    +
    +
    public class FencedNickname
    +extends Nickname
    +
    The FencedNickname class represents a nickname + in the fenced (untrusted) process space. + This class is responsible for validating + information from the CREATE NICKNAME statement. + +

    Usage:
    + Do not use this class directly. Instantiating or subclassing the + FencedNickname class directly results in incorrect wrapper behavior. + Subclass the FencedGenericNickname class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedRemoteUser.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedRemoteUser.html new file mode 100644 index 0000000..7301108 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedRemoteUser.html @@ -0,0 +1,235 @@ + + + + + +FencedRemoteUser (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class FencedRemoteUser

+
+
+
    +
  • java.lang.Object
  • +
  • + +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    FencedGenericRemoteUser
    +
    +
    +
    +
    public class FencedRemoteUser
    +extends RemoteUser
    +
    The FencedRemoteUser class represents a user mapping in the fenced (untrusted) process space. + +

    Usage:
    + Do not use the FencedRemoteUser class directly. + Instantiating or subclassing the FencedRemoteUser class + directly results in incorrect wrapper behavior. + Instantiate or subclass the FencedGenericRemoteUser + class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedServer.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedServer.html new file mode 100644 index 0000000..7c39ee9 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedServer.html @@ -0,0 +1,313 @@ + + + + + +FencedServer (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class FencedServer

+
+
+
    +
  • java.lang.Object
  • +
  • + +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    FencedGenericServer
    +
    +
    +
    +
    public class FencedServer
    +extends Server
    +
    The FencedServer class is a subclass of the Server class and is the + abstract base class for all server functionality that operates in the fenced + (untrusted) process space. This class is responsible for creating remote + connections and nicknames. + +

    Usage:
    + Do not use this class directly. Instantiating or subclassing the + FencedServer class directly results in incorrect wrapper behavior. + Subclass the FencedGenericServer class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        createRemoteConnection

        +
        protected RemoteConnection createRemoteConnection(FencedRemoteUser user,
        +                                      int kind,
        +                                      long id)
        +                                           throws java.lang.Exception
        +
        Create a new connection for the specified user mapping and of the specified kind. + The wrapper writer implements this method.
        +
        Parameters:
        user - The user mapping object that is used to authenticate the user.
        kind - The connection type.
        id - An integer value that represents the RemoteConnection object.
        +
        Returns:
        The newly created connection instance.
        +
        Throws:
        +
        java.lang.Exception - if the RemoteConnection instance cannot be created.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteConnection
        +
      • +
      + + + +
        +
      • +

        findConnection

        +
        public final RemoteConnection findConnection()
        +
        Retrieve the current active connection for the data source server.
        +
        Returns:
        The active connection for this data source server or null if no + active connection is found.
        +
      • +
      + + + + +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedWrapper.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedWrapper.html new file mode 100644 index 0000000..544acb5 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/FencedWrapper.html @@ -0,0 +1,218 @@ + + + + + +FencedWrapper (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class FencedWrapper

+
+
+
    +
  • java.lang.Object
  • +
  • + +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    FencedGenericWrapper
    +
    +
    +
    +
    public class FencedWrapper
    +extends Wrapper
    +
    The FencedWrapper class represents the wrapper on the fenced (untrusted) process space. + +

    Usage:
    + Do not use this class directly. Instantiating or subclassing the + FencedWrapper class directly results in incorrect wrapper behavior. + Subclass the FencedGenericWrapper class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/IndexInfo.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/IndexInfo.html new file mode 100644 index 0000000..86f1088 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/IndexInfo.html @@ -0,0 +1,903 @@ + + + + + +IndexInfo (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class IndexInfo

+
+
+ +
+
    +
  • +
    +
    +
    public final class IndexInfo
    +extends CatalogInfo
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      IndexInfo() +
      Class constructor.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      voidaddColumn(java.lang.String colName, + int colDir) +
      Add a column specification to the index specification
      +
      voidaddOption(java.lang.String optionName, + java.lang.String optionValue, + int action) +
      Add an option to the options chain.
      +
      shortgetClusterRatio() +
      Retrieve the cluster ratio.
      +
      intgetColCount() +
      Retrieve the number of columns in the index.
      +
      intgetColDir(int colIndex) +
      Retrieve the sort direction of an indexed column.
      +
      java.lang.StringgetColName(int colIndex) +
      Retrieve the name of an indexed column.
      +
      java.util.ArrayListgetColNames() +
      Retrieve the names of the indexed columns.
      +
      longgetFirstKeycard() +
      Retrieve the first key cardinality.
      +
      longgetFullKeycard() +
      Retrieve the full key cardinality.
      +
      java.lang.StringgetIndexName() +
      Retrieve the name of the index.
      +
      IndexInfogetNextIndex() +
      Retrieve the next index in the chain.
      +
      intgetNLeaf() +
      Set the number of leafs.
      +
      shortgetNLevels() +
      Retrieve the number of levels.
      +
      IndexInfogetPrevIndex() +
      Retrieve the previous index in the chain.
      +
      shortgetUniqueColCount() +
      Retrieve the number of unique columns in the index.
      +
      bytegetUniqueRule() +
      Retrieve the flag to indicate whether or not the index has a unique rule.
      +
      booleanisClusterRatioValid() +
      Check to see if the cluster ratio is specified.
      +
      booleanisFirstKeycardValid() +
      Check to see if the first key cardinality is specified.
      +
      booleanisFullKeycardValid() +
      Check to see if the full key cardinality is specified.
      +
      booleanisIndexNameValid() +
      Check to see if an index name is specified.
      +
      booleanisNLeafValid() +
      Check to see if the number of leafs is specified.
      +
      booleanisNLevelsValid() +
      Check to see if the number of levels is specified.
      +
      booleanisUniqueColCountValid() +
      Check to see if the number of unique columns is specified.
      +
      booleanisUniqueRuleValid() +
      Check to see if the unique rule flag is specified.
      +
      voidsetClusterRatio(short clusterRatio) +
      Set the cluster ratio.
      +
      voidsetColNames(java.util.ArrayList colNames) +
      Set the names of the indexed columns.
      +
      voidsetFirstKeycard(long firstKeycard) +
      Set the first key cardinality.
      +
      voidsetFullKeycard(long fullKeycard) +
      Set the full key cardinality.
      +
      voidsetIndexName(java.lang.String indexName) +
      Set the name of the index.
      +
      voidsetNextIndex(IndexInfo nextIndex) +
      Set the next index in the chain.
      +
      voidsetNLeaf(int nLeaf) +
      Set the number of leafs.
      +
      voidsetNLevels(short nLevels) +
      Set the number of levels.
      +
      voidsetPrevIndex(IndexInfo indexInfo) +
      Set the previous index in the chain.
      +
      voidsetUniqueColCount(short uniqueColCount) +
      Set the number of unique columns in the index.
      +
      voidsetUniqueRule(byte uniqueRule) +
      Set the flag to indicate whether or not the index has a unique rule.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        IndexInfo

        +
        public IndexInfo()
        +
        Class constructor.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        addColumn

        +
        public void addColumn(java.lang.String colName,
        +             int colDir)
        +
        Add a column specification to the index specification
        +
        Parameters:
        colName - The name of the column
        colDir - The sort direction for the column
        Since:
        +
        IBM WebSphere Federation Server Version 9.5fp2
        +
      • +
      + + + +
        +
      • +

        addOption

        +
        public void addOption(java.lang.String optionName,
        +             java.lang.String optionValue,
        +             int action)
        +               throws WrapperException
        +
        Add an option to the options chain.
        +
        Parameters:
        optionName - The name of the option.
        optionValue - The value of the option.
        action - The action flag for the option. + Valid actions for the options are specified in CatalogOption class.
        +
        Throws:
        +
        WrapperException - if the option already exists in the chain or if the action is invalid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getClusterRatio

        +
        public short getClusterRatio()
        +
        Retrieve the cluster ratio.
        +
        Returns:
        The cluster ratio value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getColCount

        +
        public int getColCount()
        +
        Retrieve the number of columns in the index.
        +
        Returns:
        The number of columns.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getColDir

        +
        public int getColDir(int colIndex)
        +
        Retrieve the sort direction of an indexed column.
        +
        Parameters:
        colIndex - The index of the column
        +
        Returns:
        The sort direction of the column.
        Since:
        +
        IBM WebSphere Federation Server Python
        +
      • +
      + + + +
        +
      • +

        getColName

        +
        public java.lang.String getColName(int colIndex)
        +
        Retrieve the name of an indexed column.
        +
        Parameters:
        colIndex - The index of the column
        +
        Returns:
        The name of the column.
        Since:
        +
        IBM WebSphere Federation Server Version 9.5fp2
        +
      • +
      + + + +
        +
      • +

        getColNames

        +
        public java.util.ArrayList getColNames()
        +
        Retrieve the names of the indexed columns.
        +
        Returns:
        The name of the columns.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getFirstKeycard

        +
        public long getFirstKeycard()
        +
        Retrieve the first key cardinality.
        +
        Returns:
        The first key cardinality value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getFullKeycard

        +
        public long getFullKeycard()
        +
        Retrieve the full key cardinality.
        +
        Parameters:
        fullKeycard - The full key cardinality.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getIndexName

        +
        public java.lang.String getIndexName()
        +
        Retrieve the name of the index.
        +
        Returns:
        The index name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNextIndex

        +
        public IndexInfo getNextIndex()
        +
        Retrieve the next index in the chain.
        +
        Returns:
        The next index in the chain.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNLeaf

        +
        public int getNLeaf()
        +
        Set the number of leafs.
        +
        Returns:
        The number of leafs.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNLevels

        +
        public short getNLevels()
        +
        Retrieve the number of levels.
        +
        Returns:
        The number of levels.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPrevIndex

        +
        public IndexInfo getPrevIndex()
        +
        Retrieve the previous index in the chain.
        +
        Returns:
        The previous index in the chain.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getUniqueColCount

        +
        public short getUniqueColCount()
        +
        Retrieve the number of unique columns in the index.
        +
        Returns:
        The number of unique columns.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getUniqueRule

        +
        public byte getUniqueRule()
        +
        Retrieve the flag to indicate whether or not the index has a unique rule.
        +
        Returns:
        The flag that indicates if the index has a unique rule.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isClusterRatioValid

        +
        public boolean isClusterRatioValid()
        +
        Check to see if the cluster ratio is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isFirstKeycardValid

        +
        public boolean isFirstKeycardValid()
        +
        Check to see if the first key cardinality is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isFullKeycardValid

        +
        public boolean isFullKeycardValid()
        +
        Check to see if the full key cardinality is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isIndexNameValid

        +
        public boolean isIndexNameValid()
        +
        Check to see if an index name is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isNLeafValid

        +
        public boolean isNLeafValid()
        +
        Check to see if the number of leafs is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isNLevelsValid

        +
        public boolean isNLevelsValid()
        +
        Check to see if the number of levels is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isUniqueColCountValid

        +
        public boolean isUniqueColCountValid()
        +
        Check to see if the number of unique columns is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isUniqueRuleValid

        +
        public boolean isUniqueRuleValid()
        +
        Check to see if the unique rule flag is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setClusterRatio

        +
        public void setClusterRatio(short clusterRatio)
        +
        Set the cluster ratio.
        +
        Parameters:
        clusterRatio - The cluster ratio value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setColNames

        +
        public void setColNames(java.util.ArrayList colNames)
        +
        Set the names of the indexed columns.
        +
        Parameters:
        colNames - The name of the columns.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setFirstKeycard

        +
        public void setFirstKeycard(long firstKeycard)
        +
        Set the first key cardinality.
        +
        Parameters:
        firstKeycard - The first key cardinality value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setFullKeycard

        +
        public void setFullKeycard(long fullKeycard)
        +
        Set the full key cardinality.
        +
        Parameters:
        fullKeycard - The full key cardinality value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setIndexName

        +
        public void setIndexName(java.lang.String indexName)
        +
        Set the name of the index.
        +
        Parameters:
        indexName - The name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNextIndex

        +
        public void setNextIndex(IndexInfo nextIndex)
        +
        Set the next index in the chain.
        +
        Parameters:
        nextIndex - The next index in the chain.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNLeaf

        +
        public void setNLeaf(int nLeaf)
        +
        Set the number of leafs.
        +
        Parameters:
        nLeaf - The number of leafs.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNLevels

        +
        public void setNLevels(short nLevels)
        +
        Set the number of levels.
        +
        Parameters:
        nLevels - The number of levels.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setPrevIndex

        +
        public void setPrevIndex(IndexInfo indexInfo)
        +
        Set the previous index in the chain.
        +
        Parameters:
        prevIndex - The previous index in the chain.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setUniqueColCount

        +
        public void setUniqueColCount(short uniqueColCount)
        +
        Set the number of unique columns in the index.
        +
        Parameters:
        colCount - The number of unique columns.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setUniqueRule

        +
        public void setUniqueRule(byte uniqueRule)
        +
        Set the flag to indicate whether or not the index has a unique rule.
        +
        Parameters:
        uniqueRule - The flag that indicates a unique rule.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Nickname.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Nickname.html new file mode 100644 index 0000000..3eb626a --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Nickname.html @@ -0,0 +1,417 @@ + + + + + +Nickname (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class Nickname

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.SqlqgBaseClass
    • +
    • +
        +
      • com.ibm.db2.wrapper.Nickname
      • +
      +
    • +
    +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    FencedNickname, UnfencedNickname
    +
    +
    +
    +
    public class Nickname
    +extends com.ibm.db2.wrapper.SqlqgBaseClass
    +
    The Nickname class models collections of data that a data source server manages. + Each instance of this class or its subclasses represents a collection + of data that is managed by the data source server that the wrapper works with. + The Nickname base class implementation maintains the following information: +
      +
    • The local name for the remote data set that is defined for the nickname. +
    • The local schema for the remote data set that is defined for the nickname. +
    • A NicknameInfo object that contains information pertaining to + this nickname that was stored in the federated server's system catalog + after executing the CREATE NICKNAME or ALTER NICKNAME statement. + The NicknameInfo object references ColumnInfo objects that contain + the local name of each column and additional information that was stored in + the federated server's system catalog as a result of running DDL statements. +
    • A reference to the data source server object that contains this nickname. +
    + +

    Usage:
    + Do not use this class directly, but subclass the FencedGenericNickname class + and the UnfencedGenericNickname class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      protected voiddestroy() +
      Destroys this nickname object and frees any resources associated with it.
      +
      NicknameInfogetInfo() +
      Retrieve the nickname information stored in the federated server's system + catalog as a result of running DDL statements.
      +
      java.lang.StringgetLocalName() +
      Retrieve the local name for this nickname.
      +
      java.lang.StringgetLocalSchema() +
      Retrieve the local schema for this nickname.
      +
      ServergetServer() +
      Retrieve the data source server that contains this nickname.
      +
      WrappergetWrapper() +
      Retrieve the wrapper instance that this nickname belongs to.
      +
      protected voidinitializeMyNickname(NicknameInfo nicknameInfo) +
      Perform the necessary nickname initialization.
      +
      protected NicknameInfoverifyMyRegisterNicknameInfo(NicknameInfo nicknameInfo) +
      Validate the nickname information that is specified in CREATE NICKNAME statements.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        destroy

        +
        protected void destroy()
        +                throws java.lang.Exception
        +
        Destroys this nickname object and frees any resources associated with it. + The default implementation does nothing. This method is called by the + federated server before the nickname object is removed and gives the + wrapper a chance to free any resources allocated. + If wrapper-specific resources need to be freed, the wrapper writer can + implement this method in the wrapper-specific subclass + of UnfencedGenericNickname and FencedGenericNickname.
        +
        Throws:
        +
        java.lang.Exception - if the processing fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getInfo

        +
        public final NicknameInfo getInfo()
        +
        Retrieve the nickname information stored in the federated server's system + catalog as a result of running DDL statements.
        +
        Returns:
        The NicknameInfo instance that contains the nickname information.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        NicknameInfo
        +
      • +
      + + + +
        +
      • +

        getLocalName

        +
        public final java.lang.String getLocalName()
        +
        Retrieve the local name for this nickname.
        +
        Returns:
        The local nickname name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getLocalSchema

        +
        public final java.lang.String getLocalSchema()
        +
        Retrieve the local schema for this nickname.
        +
        Returns:
        The local nickname schema.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getServer

        +
        public final Server getServer()
        +
        Retrieve the data source server that contains this nickname.
        +
        Returns:
        The data source server.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getWrapper

        +
        public final Wrapper getWrapper()
        +
        Retrieve the wrapper instance that this nickname belongs to.
        +
        Returns:
        The wrapper object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        initializeMyNickname

        +
        protected void initializeMyNickname(NicknameInfo nicknameInfo)
        +                             throws java.lang.Exception
        +
        Perform the necessary nickname initialization. + This method is called when the nickname is created or when the options + are changed. + The wrapper writer can implement this method in the wrapper-specific + nickname subclass to invoke the nickname-specific initialization process.
        +
        Parameters:
        nicknameInfo - The nickname catalog information.
        +
        Throws:
        +
        java.lang.Exception - if the initialization process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        NicknameInfo
        +
      • +
      + + + +
        +
      • +

        verifyMyRegisterNicknameInfo

        +
        protected NicknameInfo verifyMyRegisterNicknameInfo(NicknameInfo nicknameInfo)
        +                                             throws java.lang.Exception
        +
        Validate the nickname information that is specified in CREATE NICKNAME statements. + By default, this method allows only reserved options and does not return additional information. + The wrapper can implement this method in the wrapper-specific nickname subclass. + Either the unfenced class or the fenced class must implement this method if the + wrapper-specific nickname or column options are supported. Because + the verifyMyRegisterNicknameInfo method of the UnfencedGenericNickname class is + part of the trusted process space, the method cannot interact with the remote + data source. If interaction with the remote data source is necessary to verify + the nickname information, the verifyMyRegisterNicknameInfo method of the + FencedGenericNickname class must be implemented.
        +
        Parameters:
        nicknameInfo - The information from the CREATE NICKNAME statement.
        +
        Returns:
        The information that is added by the nickname object.
        +
        Throws:
        +
        java.lang.Exception - if the verification process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        NicknameInfo
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/NicknameInfo.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/NicknameInfo.html new file mode 100644 index 0000000..134f2ee --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/NicknameInfo.html @@ -0,0 +1,857 @@ + + + + + +NicknameInfo (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class NicknameInfo

+
+
+ +
+
    +
  • +
    +
    +
    public final class NicknameInfo
    +extends CatalogInfo
    +
    The NicknameInfo class encapsulates the catalog information for a nickname + object including column definitions from the CREATE NICKNAME and ALTER + NICKNAME statements. + +

    + The NicknameInfo class is one of the catalog classes for the Java API. + +

    Usage:
    + This class is instantiated by the DB2 federated server to contain + information from a CREATE NICKNAME or an ALTER NICKNAME + statement or to contain information from the federated server's + system catalog. This class is instantiated by the wrapper when + information is added during CREATE NICKNAME or ALTER + NICKNAME statement operations.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      NicknameInfo() +
      Construct a default (empty) nickname information object.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      voidaddOption(java.lang.String optionName, + java.lang.String optionValue, + int action) +
      Add an option to the options chain.
      +
      longgetCard() +
      Retrieve the cardinality value.
      +
      ColumnInfogetColumn(java.lang.String name) +
      Retrieve the column with the specified name.
      +
      ColumnInfogetColumnWithRemoteColumnName(java.lang.String remoteColumnName) +
      Retrieve the column with the specified remote column name.
      +
      ColumnInfogetFirstColumn() +
      Retrieve the first column information object.
      +
      longgetFPages() +
      Retrieve the fpages statistics for the nickname.
      +
      ColumnInfogetNextColumn(ColumnInfo currentColumn) +
      Retrieve the next column information object.
      +
      java.lang.StringgetNickname() +
      Retrieve the name of the nickname.
      +
      longgetNPages() +
      Retrieve the npages statistics for the nickname.
      +
      intgetNumColumns() +
      Retrieve the number of columns.
      +
      longgetOverflow() +
      Retrieve the overflow statistics for the nickname.
      +
      java.lang.StringgetSchema() +
      Retrieve the local schema name of the nickname.
      +
      java.lang.StringgetServerName() +
      Retrieve the server name of the nickname.
      +
      voidinsertColumn(ColumnInfo newColumn) +
      Insert a column information object at the position given by its column ID field.
      +
      booleanisCachingAllowed() +
      Returns true if it is allowed to use the Nickname in local caches like MQTs
      +
      booleanisCachingAllowedValid() +
      Verify whether isCachingAllowed is specified.
      +
      booleanisCardValid() +
      Verify whether a cardinality value is specified.
      +
      booleanisFPagesValid() +
      Verify whether the fpages statistics is specified.
      +
      booleanisNicknameValid() +
      Verify whether the name of the nickname is specified.
      +
      booleanisNPagesValid() +
      Verify whether the npages statistics is specified.
      +
      booleanisOverflowValid() +
      Verify whether an overflow statistics is specified.
      +
      booleanisSchemaValid() +
      Verify whether a schema name is specified.
      +
      booleanisServerNameValid() +
      Verify whether a server name is specified.
      +
      voidsetCachingAllowed(boolean isCachingAllowed) +
      Set the isCachingAllowed flag for the nickname determining if it is allowed to use the Nickname in local caches like MQTs
      +
      voidsetCard(long card) +
      Set the cardinality value.
      +
      voidsetFPages(long fPages) +
      Set the fpages statistics for the nickname.
      +
      voidsetNickname(java.lang.String nickname) +
      Set the name of the nickname.
      +
      voidsetNPages(long nPages) +
      Set the npages statistics for the nickname.
      +
      voidsetOverflow(long overflow) +
      Set the overflow statistics for the nickname.
      +
      voidsetSchema(java.lang.String schema) +
      Set the local schema name of the nickname.
      +
      voidsetServerName(java.lang.String serverName) +
      Set the server name of the nickname.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        NicknameInfo

        +
        public NicknameInfo()
        +
        Construct a default (empty) nickname information object.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        addOption

        +
        public void addOption(java.lang.String optionName,
        +             java.lang.String optionValue,
        +             int action)
        +               throws WrapperException
        +
        Add an option to the options chain.
        +
        Parameters:
        optionName - The name of the option.
        optionValue - The value of the option.
        action - The action flag for the option. + Valid actions for the options are specified in CatalogOption class.
        +
        Throws:
        +
        WrapperException - if the option already exists in the chain or if the action is invalid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getCard

        +
        public long getCard()
        +
        Retrieve the cardinality value.
        +
        Returns:
        The cardinality value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getColumn

        +
        public ColumnInfo getColumn(java.lang.String name)
        +
        Retrieve the column with the specified name.
        +
        Parameters:
        name - The name of the column to be retrieved.
        +
        Returns:
        The column descriptor.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        ColumnInfo
        +
      • +
      + + + +
        +
      • +

        getColumnWithRemoteColumnName

        +
        public ColumnInfo getColumnWithRemoteColumnName(java.lang.String remoteColumnName)
        +                                         throws WrapperException
        +
        Retrieve the column with the specified remote column name.
        +
        Parameters:
        remoteColumnName - The remote name of the column to be retrieved.
        +
        Returns:
        The column descriptor.
        +
        Throws:
        +
        WrapperException - if the method fails
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        ColumnInfo
        +
      • +
      + + + +
        +
      • +

        getFirstColumn

        +
        public ColumnInfo getFirstColumn()
        +
        Retrieve the first column information object.
        +
        Returns:
        The first column information object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        ColumnInfo
        +
      • +
      + + + +
        +
      • +

        getFPages

        +
        public long getFPages()
        +
        Retrieve the fpages statistics for the nickname.
        +
        Returns:
        The fpages statistics value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNextColumn

        +
        public ColumnInfo getNextColumn(ColumnInfo currentColumn)
        +
        Retrieve the next column information object.
        +
        Parameters:
        currentColumn - The current column information object.
        +
        Returns:
        The next column information object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        ColumnInfo
        +
      • +
      + + + +
        +
      • +

        getNickname

        +
        public java.lang.String getNickname()
        +
        Retrieve the name of the nickname.
        +
        Returns:
        The name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNPages

        +
        public long getNPages()
        +
        Retrieve the npages statistics for the nickname.
        +
        Returns:
        The npages statistics value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNumColumns

        +
        public int getNumColumns()
        +
        Retrieve the number of columns.
        +
        Returns:
        The number of columns.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getOverflow

        +
        public long getOverflow()
        +
        Retrieve the overflow statistics for the nickname.
        +
        Returns:
        The overflow statistics value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getSchema

        +
        public java.lang.String getSchema()
        +
        Retrieve the local schema name of the nickname.
        +
        Returns:
        The local schema name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getServerName

        +
        public java.lang.String getServerName()
        +
        Retrieve the server name of the nickname.
        +
        Returns:
        The server name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        insertColumn

        +
        public void insertColumn(ColumnInfo newColumn)
        +                  throws WrapperException
        +
        Insert a column information object at the position given by its column ID field.
        +
        Parameters:
        newColumn - The column information object to be inserted.
        +
        Throws:
        +
        WrapperException - if the ColumnInfo object is null.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        ColumnInfo
        +
      • +
      + + + +
        +
      • +

        isCachingAllowed

        +
        public boolean isCachingAllowed()
        +
        Returns true if it is allowed to use the Nickname in local caches like MQTs
        +
        Returns:
        true or false
        Since:
        +
        IBM DB2 Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isCachingAllowedValid

        +
        public boolean isCachingAllowedValid()
        +
        Verify whether isCachingAllowed is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        isCardValid

        +
        public boolean isCardValid()
        +
        Verify whether a cardinality value is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isFPagesValid

        +
        public boolean isFPagesValid()
        +
        Verify whether the fpages statistics is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isNicknameValid

        +
        public boolean isNicknameValid()
        +
        Verify whether the name of the nickname is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isNPagesValid

        +
        public boolean isNPagesValid()
        +
        Verify whether the npages statistics is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isOverflowValid

        +
        public boolean isOverflowValid()
        +
        Verify whether an overflow statistics is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isSchemaValid

        +
        public boolean isSchemaValid()
        +
        Verify whether a schema name is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isServerNameValid

        +
        public boolean isServerNameValid()
        +
        Verify whether a server name is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setCachingAllowed

        +
        public void setCachingAllowed(boolean isCachingAllowed)
        +
        Set the isCachingAllowed flag for the nickname determining if it is allowed to use the Nickname in local caches like MQTs
        +
        Parameters:
        isCachingAllowed - true or false
        Since:
        +
        IBM DB2 Information Integrator Version 9.1
        +
      • +
      + + + +
        +
      • +

        setCard

        +
        public void setCard(long card)
        +
        Set the cardinality value.
        +
        Parameters:
        card - The cardinality value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setFPages

        +
        public void setFPages(long fPages)
        +
        Set the fpages statistics for the nickname.
        +
        Parameters:
        fPages - The fpages statistics value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNickname

        +
        public void setNickname(java.lang.String nickname)
        +
        Set the name of the nickname.
        +
        Parameters:
        nickname - The nickname name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNPages

        +
        public void setNPages(long nPages)
        +
        Set the npages statistics for the nickname.
        +
        Parameters:
        nPages - The npages statistics value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setOverflow

        +
        public void setOverflow(long overflow)
        +
        Set the overflow statistics for the nickname.
        +
        Parameters:
        overflow - The overflow statistics value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setSchema

        +
        public void setSchema(java.lang.String schema)
        +
        Set the local schema name of the nickname.
        +
        Parameters:
        schema - The local schema name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setServerName

        +
        public void setServerName(java.lang.String serverName)
        +
        Set the server name of the nickname.
        +
        Parameters:
        serverName - The server name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ParsedQueryFragment.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ParsedQueryFragment.html new file mode 100644 index 0000000..6172db5 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ParsedQueryFragment.html @@ -0,0 +1,398 @@ + + + + + +ParsedQueryFragment (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class ParsedQueryFragment

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.ParsedQueryFragment
    • +
    +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    Reply, Request
    +
    +
    +
    +
    public class ParsedQueryFragment
    +extends java.lang.Object
    +
    The ParsedQueryFragment class represents the base class of both the + Request class and Reply class. + The ParsedQueryFragment class describes a query fragment. The query fragment + is composed of SELECT, FROM, WHERE and ORDER BY clauses. Each clause is + represented by an array of objects. The methods of this class return the size + of the arrays, the entries and the associated data structures.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      booleangetDistinct() +
      Test the DISTINCT indicator (SELECT DISTINCT clause).
      +
      RequestExpgetHeadExp(int position) +
      Retrieve the expression at the specified position in the SELECT clause.
      +
      UnfencedGenericNicknamegetNickname(int position) +
      Retrieve the nickname that corresponds to the specified position in the FROM clause.
      +
      intgetNumberOfHeadExp() +
      Retrieve the number of elements in the SELECT clause.
      +
      intgetNumberOfPredicates() +
      Retrieve the number of elements (predicates) in the WHERE clause.
      +
      intgetNumberOfQuantifiers() +
      Retrieve the number of elements (quantifiers) in the FROM clause.
      +
      RequestExpgetPredicate(int position) +
      Retrieve the predicate expression at the specified position in the WHERE clause.
      +
      QuantifiergetQuantifier(int position) +
      Retrieve the quantifier at the specified position in the FROM clause.
      +
      QuantifiergetQuantifierByHandle(int quantifierHandle) +
      Retrieve the quantifier with the specified handle in the FROM clause.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getDistinct

        +
        public final boolean getDistinct()
        +
        Test the DISTINCT indicator (SELECT DISTINCT clause).
        +
        Returns:
        The DISTINCT indicator.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getHeadExp

        +
        public final RequestExp getHeadExp(int position)
        +
        Retrieve the expression at the specified position in the SELECT clause.
        +
        Parameters:
        position - The position of the head expression in the SELECT clause. + The first head expression is at position 1.
        +
        Returns:
        The head expression at the specified position.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RequestExp
        +
      • +
      + + + +
        +
      • +

        getNickname

        +
        public final UnfencedGenericNickname getNickname(int position)
        +
        Retrieve the nickname that corresponds to the specified position in the FROM clause.
        +
        Parameters:
        position - The position of the quantifier in the FROM clause. + The first quantifier is at position 1.
        +
        Returns:
        The nickname object at the specified position.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        UnfencedGenericNickname
        +
      • +
      + + + +
        +
      • +

        getNumberOfHeadExp

        +
        public final int getNumberOfHeadExp()
        +
        Retrieve the number of elements in the SELECT clause.
        +
        Returns:
        The number of head expressions.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNumberOfPredicates

        +
        public final int getNumberOfPredicates()
        +
        Retrieve the number of elements (predicates) in the WHERE clause.
        +
        Returns:
        The number of predicates.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNumberOfQuantifiers

        +
        public final int getNumberOfQuantifiers()
        +
        Retrieve the number of elements (quantifiers) in the FROM clause.
        +
        Returns:
        The number of quantifiers.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPredicate

        +
        public final RequestExp getPredicate(int position)
        +
        Retrieve the predicate expression at the specified position in the WHERE clause.
        +
        Parameters:
        position - The position of the predicate in the WHERE clause. + The first predicate is at position 1.
        +
        Returns:
        The predicate expression at the specified position.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RequestExp
        +
      • +
      + + + +
        +
      • +

        getQuantifier

        +
        public final Quantifier getQuantifier(int position)
        +
        Retrieve the quantifier at the specified position in the FROM clause.
        +
        Parameters:
        position - The quantifier position in the FROM clause. + The first quantifier is at position 1.
        +
        Returns:
        The quantifier at the specified position.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Quantifier
        +
      • +
      + + + +
        +
      • +

        getQuantifierByHandle

        +
        public final Quantifier getQuantifierByHandle(int quantifierHandle)
        +
        Retrieve the quantifier with the specified handle in the FROM clause.
        +
        Parameters:
        quantifierHandle - The quantifier handle.
        +
        Returns:
        The quantifier object for the specified handle.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Quantifier
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/PredicateList.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/PredicateList.html new file mode 100644 index 0000000..5f78af9 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/PredicateList.html @@ -0,0 +1,305 @@ + + + + + +PredicateList (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class PredicateList

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.PredicateList
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public final class PredicateList
    +extends java.lang.Object
    +
    The PredicateList describes two lists of predicates to + estimate the selectivity factor. + Instances of this class are used as input to + UnfencedGenericServer.getSelectivity, + the selectivity estimation function. +

    The two predicate lists are: +
      +
    • a list of predicates that selectivity is solicited for (P) +
    • a list of previously applied predicates (AP) +
    + The result selectivity is conditional selectivity: +

    selectivity (P/AP)

    + If you need unconditional selectivity, the AP can be null. + If the implementation cannot support this framework, + the implementation can be set to ignore the AP. + The lists of predicates are similar to the list of predicates + in the Request class and are manipulated with similar methods.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      RequestExpgetAppliedPredicate(int position) +
      Retrieve a RequestExp object that describes the applied predicate at the specified position.
      +
      intgetNumberOfAppliedPredicates() +
      Retrieve the number of applied predicates.
      +
      intgetNumberOfPredicates() +
      Retrieve the number of predicates in the list.
      +
      RequestExpgetPredicate(int position) +
      Retrieve a RequestExp object that describes the predicate at the specified position.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getAppliedPredicate

        +
        public RequestExp getAppliedPredicate(int position)
        +
        Retrieve a RequestExp object that describes the applied predicate at the specified position.
        +
        Parameters:
        position - The predicate position. + The first predicate is at position 1.
        +
        Returns:
        The applied predicate expression.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNumberOfAppliedPredicates

        +
        public int getNumberOfAppliedPredicates()
        +
        Retrieve the number of applied predicates.
        +
        Returns:
        The number of applied predicates.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNumberOfPredicates

        +
        public int getNumberOfPredicates()
        +
        Retrieve the number of predicates in the list.
        +
        Returns:
        The number of predicates.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPredicate

        +
        public RequestExp getPredicate(int position)
        +
        Retrieve a RequestExp object that describes the predicate at the specified position.
        +
        Parameters:
        position - The predicate position. + The first predicate is at position 1.
        +
        Returns:
        The predicate expression.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Quantifier.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Quantifier.html new file mode 100644 index 0000000..60a31aa --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Quantifier.html @@ -0,0 +1,260 @@ + + + + + +Quantifier (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class Quantifier

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.Quantifier
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public final class Quantifier
    +extends java.lang.Object
    +
    The Quantifier class encapsulates information for a quantifier of a Request. + +

    Usage:
    + This class is instantiated by the federated server to contain + information for a Request object during query planning. + The quantifiers are the entities specified in the FROM clause of the query. + The planRequest method + in the wrapper-specific unfenced server subclass examines the quantifier + information and adds the information to the Reply objects if the + wrapper can process this information.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      intgetHandle() +
      Retrieve the handle of the quantifier.
      +
      UnfencedGenericNicknamegetNickname() +
      Retrieve the nickname that is referenced by this quantifier.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getHandle

        +
        public int getHandle()
        +
        Retrieve the handle of the quantifier. + The handle is an integer value that is used by the + federated server's query planning component.
        +
        Returns:
        The quantifier handle.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNickname

        +
        public UnfencedGenericNickname getNickname()
        +
        Retrieve the nickname that is referenced by this quantifier.
        +
        Returns:
        The nickname that is referenced by the quantifier.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RFuncParmInfo.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RFuncParmInfo.html new file mode 100644 index 0000000..bba9e7f --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RFuncParmInfo.html @@ -0,0 +1,372 @@ + + + + + +RFuncParmInfo (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RFuncParmInfo

+
+
+ +
+
    +
  • +
    +
    +
    public final class RFuncParmInfo
    +extends CatalogInfo
    +
    The RFuncParmInfo class represents the information that describes a function parameter + in a function mapping.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + + +
      Constructors 
      Constructor and Description
      RFuncParmInfo() +
      Default constructor.
      +
      RFuncParmInfo(short ordinal) +
      Construct a function parameter with the specified ordinal.
      +
      +
    • +
    + + +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        RFuncParmInfo

        +
        public RFuncParmInfo()
        +
        Default constructor.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        RFuncParmInfo

        +
        public RFuncParmInfo(short ordinal)
        +
        Construct a function parameter with the specified ordinal.
        +
        Parameters:
        ordinal - The ordinal value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getNextRFuncParm

        +
        public RFuncParmInfo getNextRFuncParm()
        +
        Retrieve the next function parameter in the chain.
        +
        Returns:
        The next parameter.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getOrdinal

        +
        public short getOrdinal()
        +
        Retrieve the ordinal value.
        +
        Returns:
        The ordinal value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isOrdinalValid

        +
        public boolean isOrdinalValid()
        +
        check if an ordinal value was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNextRFuncParm

        +
        public void setNextRFuncParm(RFuncParmInfo next)
        +
        Set the next function parameter in the chain.
        +
        Parameters:
        next - The next parameter.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setOrdinal

        +
        public void setOrdinal(short ordinal)
        +
        Set the ordinal value.
        +
        Parameters:
        ordinal - The ordinal value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteConnection.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteConnection.html new file mode 100644 index 0000000..d5dbf07 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteConnection.html @@ -0,0 +1,642 @@ + + + + + +RemoteConnection (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RemoteConnection

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.SqlqgBaseClass
    • +
    • +
        +
      • com.ibm.db2.wrapper.RemoteConnection
      • +
      +
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public class RemoteConnection
    +extends com.ibm.db2.wrapper.SqlqgBaseClass
    +
    The RemoteConnection class represents a connection (session) with a data source server. + The operations on the data source server (database) are processed through a connection. + Connections can be created only for untrusted and fenced data source servers. + The RemoteConnection base class implementation maintains the following information: + +
      +
    • The status (connected or disconnected) of your connection to your data source. +
    • A reference to the appropriate FencedServer object. +
    • A reference to the appropriate FencedRemoteUser object. +
    • The code page to use for this connection. +
    • The connection kind: indicates if the connection supports one-phase commit transactions, + the ONE_PHASE_KIND value, or not, the NO_PHASE_KIND value. +
    +

    + +

    Usage:
    + You can create an instance of your RemoteConnection subclass by invoking the + FencedServer.createRemoteConnection method on an instance of the appropriate + fenced server subclass. The federated server calls this method before processing + the first remote operation at the relevant data source server. The federated + server destroys the RemoteConnection instance after a predefined number of + transactions are processed by the application without using the data source + server.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Summary

      + + + + + + + + + + + + + + +
      Fields 
      Modifier and TypeField and Description
      static intNO_PHASE_KIND +
      Constant to indicate that no transactions are supported.
      +
      static intONE_PHASE_KIND +
      Constant to indicate that one-phase commit transactions are supported.
      +
      +
    • +
    + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + +
      Constructors 
      ModifierConstructor and Description
      protected RemoteConnection(FencedServer remoteServer, + FencedRemoteUser remoteUser, + int connectionKind, + long id) +
      Construct a connection for the specified server with the user authorization and transaction type as specified.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      protected voidcommit() +
      Indicate the successful completion of a transaction and + that the remote data source then commits the transaction.
      +
      protected voidconnect() +
      Invoke the code to connect to the data source server.
      +
      protected RemotePassthrucreateRemotePassthru(long id) +
      Create a RemotePassthru object to run pass-through statements.
      +
      protected RemoteQuerycreateRemoteQuery(long id) +
      Create a RemoteQuery object to run SQL statements.
      +
      protected voiddisconnect() +
      Invoke the code to disconnect from the data source server.
      +
      shortgetCodepage() +
      Retrieve the code page for the connection.
      +
      intgetKind() +
      Retrieve the connection type.
      +
      FencedServergetServer() +
      Retrieve the data source server object that contains this connection.
      +
      FencedRemoteUsergetUser() +
      Retrieve the user mapping to authenticate this connection.
      +
      WrappergetWrapper() +
      Retrieve the wrapper object.
      +
      booleanisConnected() +
      Verify whether the connection with the data source server exists.
      +
      voidmarkDisconnected() +
      Set the flag to indicate that the connection with the data source server finished.
      +
      protected voidrollback() +
      Indicate the unsuccessful completion of a + transaction and that the remote data + source then rolls back the transaction.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Detail

      + + + +
        +
      • +

        NO_PHASE_KIND

        +
        public static final int NO_PHASE_KIND
        +
        Constant to indicate that no transactions are supported.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        ONE_PHASE_KIND

        +
        public static final int ONE_PHASE_KIND
        +
        Constant to indicate that one-phase commit transactions are supported.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        RemoteConnection

        +
        protected RemoteConnection(FencedServer remoteServer,
        +                FencedRemoteUser remoteUser,
        +                int connectionKind,
        +                long id)
        +
        Construct a connection for the specified server with the user authorization and transaction type as specified.
        +
        Parameters:
        remoteServer - The data source server that contains the connection.
        remoteUser - The user mapping object that is used for authentication.
        connectionKind - The type of connection, specifies the supported transaction types. + A connection that can support one-phase commit transactions is + indicated by the ONE_PHASE_KIND constant. A connection + that does not have transaction support is indicated by the NO_PHASE_KIND constant.
        id - An integer value that represents the RemoteConnection object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        FencedServer, +FencedRemoteUser
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        commit

        +
        protected void commit()
        +               throws java.lang.Exception
        +
        Indicate the successful completion of a transaction and + that the remote data source then commits the transaction. + A default implementation does nothing. The wrapper can + override this method to implement necessary commit logic + for the remote data source.
        +
        Throws:
        +
        java.lang.Exception - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        connect

        +
        protected void connect()
        +                throws java.lang.Exception
        +
        Invoke the code to connect to the data source server. + This method does nothing by default. The connect method can + be implemented by the wrapper writer if the wrapper-specific + connection class needs to perform any operation to establish + a connection with the remote data source.
        +
        Throws:
        +
        java.lang.Exception - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        createRemotePassthru

        +
        protected RemotePassthru createRemotePassthru(long id)
        +                                       throws java.lang.Exception
        +
        Create a RemotePassthru object to run pass-through statements. + This method returns null by default. However, if the wrapper supports the + ability to run pass-through statements, it must implement the method in the + wrapper-specific connection class. When the createRemotePassthru method is + used in this situation, it must return a value that is not null.
        +
        Parameters:
        id - An integer value that represents the RemotePassthru object.
        +
        Returns:
        A RemotePassthru instance or null if the operation is not + supported by the wrapper.
        +
        Throws:
        +
        java.lang.Exception - if the object creation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemotePassthru
        +
      • +
      + + + +
        +
      • +

        createRemoteQuery

        +
        protected RemoteQuery createRemoteQuery(long id)
        +                                 throws java.lang.Exception
        +
        Create a RemoteQuery object to run SQL statements. + This method returns null by default. However, if the wrapper supports the + ability to run SQL statements, it must implement the method in the + wrapper-specific connection class. When the createRemoteQuery is used in + this situation, it must return a value that is not null.
        +
        Parameters:
        id - An integer value that represents the RemoteQuery object.
        +
        Returns:
        A RemoteQuery instance or null if the operation is not + supported by the wrapper.
        +
        Throws:
        +
        java.lang.Exception - if the object creation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteQuery
        +
      • +
      + + + +
        +
      • +

        disconnect

        +
        protected void disconnect()
        +                   throws java.lang.Exception
        +
        Invoke the code to disconnect from the data source server. + This method does nothing by default. The disconnect method + can be implemented by the wrapper writer if the wrapper-specific + connection class needs to perform any operation to terminate + a connection with the remote data source.
        +
        Throws:
        +
        java.lang.Exception - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getCodepage

        +
        public final short getCodepage()
        +
        Retrieve the code page for the connection.
        +
        Returns:
        The code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getKind

        +
        public final int getKind()
        +
        Retrieve the connection type. + A connection can either support one-phase commit transactions + (indicated by the ONE_PHASE_KIND constant) or + cannot support transactions (indicated by the + NO_PHASE_KIND constant).
        +
        Returns:
        The connection type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getServer

        +
        public final FencedServer getServer()
        +
        Retrieve the data source server object that contains this connection.
        +
        Returns:
        The data source server for this connection.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        FencedServer
        +
      • +
      + + + +
        +
      • +

        getUser

        +
        public final FencedRemoteUser getUser()
        +
        Retrieve the user mapping to authenticate this connection.
        +
        Returns:
        The user mapping for this connection.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        FencedRemoteUser
        +
      • +
      + + + +
        +
      • +

        getWrapper

        +
        public final Wrapper getWrapper()
        +
        Retrieve the wrapper object.
        +
        Returns:
        The wrapper object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Wrapper
        +
      • +
      + + + +
        +
      • +

        isConnected

        +
        public final boolean isConnected()
        +
        Verify whether the connection with the data source server exists.
        +
        Returns:
        true if a connection with the server exists, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        markDisconnected

        +
        public final void markDisconnected()
        +
        Set the flag to indicate that the connection with the data source server finished.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        rollback

        +
        protected void rollback()
        +                 throws java.lang.Exception
        +
        Indicate the unsuccessful completion of a + transaction and that the remote data + source then rolls back the transaction. + A default implementation does nothing. The wrapper can + override this method to implement necessary rollback + logic for the remote data source.
        +
        Throws:
        +
        java.lang.Exception - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteFunctionInfo.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteFunctionInfo.html new file mode 100644 index 0000000..0c3f7ef --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteFunctionInfo.html @@ -0,0 +1,1000 @@ + + + + + +RemoteFunctionInfo (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RemoteFunctionInfo

+
+
+ +
+
    +
  • +
    +
    +
    public final class RemoteFunctionInfo
    +extends CatalogInfo
    +
    The RemoteFunctionInfo class represents the catalog information + and describes the function mapping with a remote source. + The RemoteFunctionInfo class is one of the catalog classes for the Java wrapper SDK. +
    +
    Usage:
    + This class is instantiated by the wrapper when information is added + during CREATE FUNCTION MAPPING statement operations.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + + + + + +
      Constructors 
      Constructor and Description
      RemoteFunctionInfo() +
      Class constructor.
      +
      RemoteFunctionInfo(int action, + java.lang.String mappingName, + java.lang.String signature, + java.lang.String schema, + int funcID, + java.lang.String specificName, + java.lang.String definer, + byte definerType, + java.sql.Timestamp timestamp) +
      Construct an instance with the specified values.
      +
      RemoteFunctionInfo(int action, + java.lang.String mappingName, + java.lang.String signature, + java.lang.String schema, + int funcID, + java.lang.String specificName, + java.lang.String definer, + java.sql.Timestamp timestamp) +
      Construct an instance with the specified values.
      +
      +
    • +
    + + +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        RemoteFunctionInfo

        +
        public RemoteFunctionInfo()
        +
        Class constructor.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        RemoteFunctionInfo

        +
        public RemoteFunctionInfo(int action,
        +                  java.lang.String mappingName,
        +                  java.lang.String signature,
        +                  java.lang.String schema,
        +                  int funcID,
        +                  java.lang.String specificName,
        +                  java.lang.String definer,
        +                  byte definerType,
        +                  java.sql.Timestamp timestamp)
        +
        Construct an instance with the specified values.
        +
        Parameters:
        action - The action.
        mappingName - The name of the mapping.
        signature - The signature of the function.
        schema - The local schema name.
        funcID - The local function ID.
        specificName - The specific name.
        definer - The definer.
        definerType - The definer type.
        timestamp - The timestamp for the mapping.
        Since:
        +
        IBM DB2 Information Integrator Version 9.5fp2
        +
      • +
      + + + +
        +
      • +

        RemoteFunctionInfo

        +
        public RemoteFunctionInfo(int action,
        +                  java.lang.String mappingName,
        +                  java.lang.String signature,
        +                  java.lang.String schema,
        +                  int funcID,
        +                  java.lang.String specificName,
        +                  java.lang.String definer,
        +                  java.sql.Timestamp timestamp)
        +
        Construct an instance with the specified values.
        +
        Parameters:
        action - The action.
        mappingName - The name of the mapping.
        signature - The signature of the function.
        schema - The local schema name.
        funcID - The local function ID.
        specificName - The specific name.
        definer - The definer.
        timestamp - The timestamp for the mapping.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        addOption

        +
        public void addOption(java.lang.String optionName,
        +             java.lang.String optionValue,
        +             int action)
        +               throws WrapperException
        +
        Add an option to the options chain.
        +
        Parameters:
        optionName - The name of the option.
        optionValue - The value of the option.
        action - The action flag for the option. + Valid actions for the options are specified in CatalogOption class.
        +
        Throws:
        +
        WrapperException - if the option already exists in the chain or if the action is invalid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getAction

        +
        public int getAction()
        +
        Retrieve the action value.
        +
        Returns:
        The action.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDefiner

        +
        public java.lang.String getDefiner()
        +
        Retrieve the definer.
        +
        Returns:
        The definer.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDefinerType

        +
        public byte getDefinerType()
        +
        Retrieve the definer type.
        +
        Returns:
        The definer type.
        Since:
        +
        IBM DB2 Information Integrator Version 9.5fp2
        +
      • +
      + + + +
        +
      • +

        getFirstLocalParm

        +
        public RFuncParmInfo getFirstLocalParm()
        +
        Retrieve the first local parameter.
        +
        Returns:
        The first local parameter.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RFuncParmInfo
        +
      • +
      + + + +
        +
      • +

        getFirstRemoteParm

        +
        public RFuncParmInfo getFirstRemoteParm()
        +
        Retrieve the first remote parameter.
        +
        Returns:
        The first remote parameter.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RFuncParmInfo
        +
      • +
      + + + +
        +
      • +

        getFuncID

        +
        public int getFuncID()
        +
        Retrieve the local function ID.
        +
        Returns:
        The ID.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getLocalSchema

        +
        public java.lang.String getLocalSchema()
        +
        Retrieve the local schema name.
        +
        Returns:
        The schema name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getLocalSignature

        +
        public java.lang.String getLocalSignature()
        +
        Retrieve the signature.
        +
        Returns:
        The signature.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getMappingName

        +
        public java.lang.String getMappingName()
        +
        Retrieve the mapping name.
        +
        Returns:
        The mapping name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNextFunction

        +
        public RemoteFunctionInfo getNextFunction()
        +
        Retrieve the next function in the chain.
        +
        Returns:
        The next function.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPrevFunction

        +
        public RemoteFunctionInfo getPrevFunction()
        +
        Retrieve the previous function in the chain.
        +
        Returns:
        The previous function.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getSpecificName

        +
        public java.lang.String getSpecificName()
        +
        Retrieve the specific name.
        +
        Returns:
        The specific name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getTimestamp

        +
        public java.sql.Timestamp getTimestamp()
        +
        Retrieve the timestamp value.
        +
        Returns:
        The timestamp.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        insertLocalParm

        +
        public void insertLocalParm(RFuncParmInfo localParm)
        +                     throws WrapperException
        +
        Insert a local parameter in the local parameters list.
        +
        Parameters:
        localParm - The local parameter to be inserted.
        +
        Throws:
        +
        WrapperException - if the parameter is null.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RFuncParmInfo
        +
      • +
      + + + +
        +
      • +

        insertRemoteParm

        +
        public void insertRemoteParm(RFuncParmInfo remoteParm)
        +                      throws WrapperException
        +
        Insert a remote parameter in the remote parameters list.
        +
        Parameters:
        remoteParm - The remote parameter to be inserted.
        +
        Throws:
        +
        WrapperException - if the parameter is null.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RFuncParmInfo
        +
      • +
      + + + +
        +
      • +

        isActionValid

        +
        public boolean isActionValid()
        +
        Check to see if an action was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isDefinerTypeValid

        +
        public boolean isDefinerTypeValid()
        +
        Check to see if a definer type was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 9.5fp2
        +
      • +
      + + + +
        +
      • +

        isDefinerValid

        +
        public boolean isDefinerValid()
        +
        Check to see if a definer was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isFuncIDValid

        +
        public boolean isFuncIDValid()
        +
        Check to see if a function ID was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isMappingNameValid

        +
        public boolean isMappingNameValid()
        +
        Check to see if a mapping name was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isSchemaValid

        +
        public boolean isSchemaValid()
        +
        Check to see if a schema name was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isSignatureValid

        +
        public boolean isSignatureValid()
        +
        Check to see if a signature was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isSpecificNameValid

        +
        public boolean isSpecificNameValid()
        +
        Check to see if a specific name was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isTimestampValid

        +
        public boolean isTimestampValid()
        +
        Check to see if a timestamp was specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setAction

        +
        public void setAction(int action)
        +
        Set the action value.
        +
        Parameters:
        action - The action.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setDefiner

        +
        public void setDefiner(java.lang.String definer)
        +
        Set the definer.
        +
        Parameters:
        definer - The definer.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setDefinerType

        +
        public void setDefinerType(byte definerType)
        +
        Set the definer type.
        +
        Parameters:
        definerType - The definer type.
        Since:
        +
        IBM DB2 Information Integrator Version 9.5fp2
        +
      • +
      + + + +
        +
      • +

        setFuncID

        +
        public void setFuncID(int funcID)
        +
        Set the local function ID.
        +
        Parameters:
        funcID - The ID.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setLocalSchema

        +
        public void setLocalSchema(java.lang.String schema)
        +
        Set the local schema name.
        +
        Parameters:
        schema - The schema name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setLocalSignature

        +
        public void setLocalSignature(java.lang.String signature)
        +
        Set the signature.
        +
        Parameters:
        signature - The signature.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setMappingName

        +
        public void setMappingName(java.lang.String mappingName)
        +
        Set the mapping name.
        +
        Parameters:
        mappingName - The mapping name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNextFunction

        +
        public void setNextFunction(RemoteFunctionInfo next)
        +
        Set the next function in the chain.
        +
        Parameters:
        next - The next function.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setPrevFunction

        +
        public void setPrevFunction(RemoteFunctionInfo prev)
        +
        Set the previous function in the chain.
        +
        Parameters:
        prev - The previous function.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setSpecificName

        +
        public void setSpecificName(java.lang.String specificName)
        +
        Set the specific name.
        +
        Parameters:
        specificName - The specific name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setTimestamp

        +
        public void setTimestamp(java.sql.Timestamp timestamp)
        +
        Set the timestamp value.
        +
        Parameters:
        timestamp - The timestamp.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteOperation.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteOperation.html new file mode 100644 index 0000000..918bbb3 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteOperation.html @@ -0,0 +1,375 @@ + + + + + +RemoteOperation (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RemoteOperation

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.SqlqgBaseClass
    • +
    • +
        +
      • com.ibm.db2.wrapper.RemoteOperation
      • +
      +
    • +
    +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    RemotePassthru, RemoteQuery
    +
    +
    +
    +
    public class RemoteOperation
    +extends com.ibm.db2.wrapper.SqlqgBaseClass
    +
    The RemoteOperation class serves as the base class for classes that represent + various remote operations. These remote operations include queries and + pass-through sessions. The RemoteOperation class is not directly instantiated + and cannot be customized directly. + The RemoteOperation base class implementation maintains the following information: +
      +
    • The type of remote operation that is represented by the object. +
    • A reference to the RemoteConnection object. +
    • A reference to a RuntimeDataList that describes the type and location + of values to be bound to parameter markers (if any) in the SQL statement. +
    • A reference to a RuntimeDataList that describes the expected type and + provides the buffers for values to be returned (if any) by the SQL statement. +
    +

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      RemoteConnectiongetConnection() +
      Retrieve the connection for the remote operation.
      +
      java.lang.ObjectgetExecDesc() +
      Retrieve the execution descriptor for the remote operation.
      +
      RuntimeDataListgetInputData() +
      Retrieve the list of input values for the remote operation.
      +
      RuntimeDataListgetOutputData() +
      Retrieve the list of output data buffers for the remote operation.
      +
      FencedServergetServer() +
      Retrieve the data source server that owns the remote operation.
      +
      WrappergetWrapper() +
      Get the wrapper object.
      +
      protected voidreportEof() +
      Report an end-of-file condition during a fetch operation.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getConnection

        +
        public final RemoteConnection getConnection()
        +
        Retrieve the connection for the remote operation.
        +
        Returns:
        The RemoteConnection instance.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteConnection
        +
      • +
      + + + +
        +
      • +

        getExecDesc

        +
        public final java.lang.Object getExecDesc()
        +                                   throws WrapperException,
        +                                          java.io.IOException,
        +                                          java.lang.ClassNotFoundException
        +
        Retrieve the execution descriptor for the remote operation.
        +
        Returns:
        The execution descriptor.
        +
        Throws:
        +
        WrapperException - if the retrieval of the execution descriptor object fails.
        +
        java.io.IOException - if the streaming of the execution descriptor fails.
        +
        java.lang.ClassNotFoundException - if the execution descriptor class cannot be found.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getInputData

        +
        public final RuntimeDataList getInputData()
        +
        Retrieve the list of input values for the remote operation.
        +
        Returns:
        The list of input values.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RuntimeDataList
        +
      • +
      + + + +
        +
      • +

        getOutputData

        +
        public final RuntimeDataList getOutputData()
        +
        Retrieve the list of output data buffers for the remote operation.
        +
        Returns:
        The list of output data buffers.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RuntimeDataList
        +
      • +
      + + + +
        +
      • +

        getServer

        +
        public final FencedServer getServer()
        +
        Retrieve the data source server that owns the remote operation.
        +
        Returns:
        The FencedServer instance where the remote operation runs.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        FencedServer
        +
      • +
      + + + +
        +
      • +

        getWrapper

        +
        public final Wrapper getWrapper()
        +
        Get the wrapper object.
        +
        Returns:
        The wrapper object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Wrapper
        +
      • +
      + + + +
        +
      • +

        reportEof

        +
        protected void reportEof()
        +                  throws WrapperException
        +
        Report an end-of-file condition during a fetch operation.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemotePassthru.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemotePassthru.html new file mode 100644 index 0000000..3a8dc69 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemotePassthru.html @@ -0,0 +1,456 @@ + + + + + +RemotePassthru (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RemotePassthru

+
+
+ +
+
    +
  • +
    +
    +
    public class RemotePassthru
    +extends RemoteOperation
    +
    The RemotePassthru class represents a pass-through session on a remote data source. + An instance of your RemotePassthru subclass is created when the federated server + invokes the createRemotePassthru method + on an instance of the appropriate RemoteConnection subclass. + If your data source does not support pass-through operations, + do not implement a RemotePassthru subclass and do not override the default + implementation of this method.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + +
      Constructors 
      ModifierConstructor and Description
      protected RemotePassthru(RemoteConnection activeConnection, + long id) +
      Construct a new pass-through object for the specified connection.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      protected voidclose() +
      Close a pass-through cursor and allows the data source to clean up after pass-through statement processing.
      +
      protected voiddescribe(RuntimeDataDescList dataDescriptionList) +
      Describe the result set of a statement that is processed by a pass-through operation.
      +
      protected voidexecute() +
      Execute a statement that returns a code and does not return a result set by a pass-through operation.
      +
      protected voidfetch() +
      Fetch a row from a pass-through cursor by copying a single-result row into the output data buffer.
      +
      java.lang.StringgetSQLStatement() +
      Retrieve the SQL statement for the remote pass-through operation.
      +
      protected voidopen() +
      Open a cursor for a pass-through operation and enable the data source + to return the first result row for the query.
      +
      protected voidprepare(RuntimeDataDescList dataDescriptionList) +
      Prepare a pass-through operation.
      +
      protected voidreportEof() +
      Report an end-of-file condition during a fetch operation.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        RemotePassthru

        +
        protected RemotePassthru(RemoteConnection activeConnection,
        +              long id)
        +
        Construct a new pass-through object for the specified connection.
        +
        Parameters:
        activeConnection - The connection through which the pass-through operation is executed.
        id - An integer value that represents the RemotePassthru object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteConnection
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        close

        +
        protected void close()
        +              throws java.lang.Exception
        +
        Close a pass-through cursor and allows the data source to clean up after pass-through statement processing.
        +
        Throws:
        +
        java.lang.Exception - if the close operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        describe

        +
        protected void describe(RuntimeDataDescList dataDescriptionList)
        +                 throws java.lang.Exception
        +
        Describe the result set of a statement that is processed by a pass-through operation. + Populate a RuntimeDataDescList instance that describes the number and type of + columns for each row of the result.
        +
        Parameters:
        dataDescriptionList - The list of data descriptors for the operation.
        +
        Throws:
        +
        java.lang.Exception - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RuntimeDataDescList
        +
      • +
      + + + +
        +
      • +

        execute

        +
        protected void execute()
        +                throws java.lang.Exception
        +
        Execute a statement that returns a code and does not return a result set by a pass-through operation.
        +
        Throws:
        +
        java.lang.Exception - if the execution process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        fetch

        +
        protected void fetch()
        +              throws java.lang.Exception
        +
        Fetch a row from a pass-through cursor by copying a single-result row into the output data buffer.
        +
        Throws:
        +
        java.lang.Exception - if the fetch operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getSQLStatement

        +
        public final java.lang.String getSQLStatement()
        +                                       throws WrapperException
        +
        Retrieve the SQL statement for the remote pass-through operation.
        +
        Returns:
        A string value that represents the SQL statement.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        open

        +
        protected void open()
        +             throws java.lang.Exception
        +
        Open a cursor for a pass-through operation and enable the data source + to return the first result row for the query.
        +
        Throws:
        +
        java.lang.Exception - if the open operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        prepare

        +
        protected void prepare(RuntimeDataDescList dataDescriptionList)
        +                throws java.lang.Exception
        +
        Prepare a pass-through operation. + Sends the pass-through string to the data source and determines + the number and type of the columns for each row of the result.
        +
        Parameters:
        dataDescriptionList - The list of data descriptors for the operation.
        +
        Throws:
        +
        java.lang.Exception - if the prepare operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RuntimeDataDescList
        +
      • +
      + + + +
        +
      • +

        reportEof

        +
        protected final void reportEof()
        +                        throws WrapperException
        +
        Report an end-of-file condition during a fetch operation. + The wrapper must call this method from the fetch + method when there are no more rows to retrieve.
        +
        +
        Overrides:
        +
        reportEof in class RemoteOperation
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteQuery.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteQuery.html new file mode 100644 index 0000000..c725316 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteQuery.html @@ -0,0 +1,1032 @@ + + + + + +RemoteQuery (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RemoteQuery

+
+
+ +
+
    +
  • +
    +
    +
    public class RemoteQuery
    +extends RemoteOperation
    +
    The RemoteQuery class represents SELECT statement operations on a remote data source. + An instance of your RemoteQuery subclass is created when the federated server invokes + the createRemoteQuery method on an instance of + the appropriate RemoteConnection subclass. + The federated server destroys the RemoteQuery object after the application that + submitted the query to the federated server closes its cursor over the result set of + the query.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Fields 
      Modifier and TypeField and Description
      static byteCLOSE_EOA +
      Status constant used in close method to indicate + that the wrapper is to finish necessary cleanup and + that the RemoteQuery object is destroyed after the close + method returns.
      +
      static byteCLOSE_EOS +
      Status constant used in close method + to indicate that the wrapper must leave the RemoteQuery in + a state so that the reopen or + reopenInputLob methods can be invoked.
      +
      static byteEOF +
      Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object finished fetching all the rows of + the result set.
      +
      static intFETCH_LOB_LAST +
      LOB fetching status constant: indicate that the last buffer of data for + the current LOB column has been fetched.
      +
      static intFETCH_LOB_MORE +
      LOB fetching status constant: indicate that more data is available for the current LOB column.
      +
      static intFETCH_LOB_NEXT +
      LOB fetching status constant: indicate that another LOB column is to be fetched next.
      +
      static intFETCH_NON_LOB_NEXT +
      LOB fetching status constant: indicate that a non-LOB column is to be fetched next.
      +
      static intFETCH_ROW_DONE +
      LOB fetching status constant: indicate that all the values for the current row have + been fetched.
      +
      static byteOPEN +
      Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object is in open state.
      +
      static intOPEN_LOB_INIT +
      LOB input status constant: indicate the start of processing for the input LOB values.
      +
      static intOPEN_LOB_LAST +
      LOB input status constant: indicate that this is the last fragment for the current input LOB value.
      +
      static intOPEN_LOB_MORE +
      LOB input status constant: indicate that more fragments are available for the current input LOB value.
      +
      static intOPEN_LOB_NEW +
      LOB input status constant: indicate that the wrapper expects data fragments for a new input LOB value.
      +
      static intOPEN_NON_LOB_NEXT +
      LOB input status constant: indicate that only input non-LOB values are to be processed.
      +
      static intOPEN_ROW_DONE +
      LOB input status constant: indicate that all the input values have been processed.
      +
      static byteREADY +
      Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object is ready to fetch the next row.
      +
      static byteUNREADY +
      Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object is not yet ready to fetch the next row.
      +
      +
    • +
    + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + +
      Constructors 
      ModifierConstructor and Description
      protected RemoteQuery(RemoteConnection activeConnection, + long id) +
      Construct a new query object for the specified connection.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      protected voidclose(short status) +
      Allow the wrapper and the data source to clean up after query statement processing.
      +
      protected voidfetch() +
      Fetch (retrieve) a single-result row from the remote data source into the output data buffers.
      +
      protected java.lang.ObjectfetchLob(int bufferSize, + int bytesWritten) +
      Retrieve a large object (LOB) fragment from the remote source.
      +
      protected intgetRowStatus() +
      Retrieve the current row status.
      +
      protected bytegetStatus() +
      Retrieve the status of the query.
      +
      protected voidlobDataReady(int columnNumber, + int bytesReady, + int status, + int intent) +
      Notify the federated server that a fragment of data from a LOB column is fetched (retrieved).
      +
      protected voidopen() +
      Allow the wrapper to prepare the remote data source to return the first result row for + the query.
      +
      protected intopenInputLob(int columnNumber, + int matSize, + int xferBytes, + java.lang.Object buffer) +
      Allow the wrapper to prepare the remote data source to return the first result row for + the query that contains input large object (LOB) parameters.
      +
      protected voidreopen(short action) +
      Reset a previously opened result stream and prepares the data source to return more result sets, + possibly based on different parameter bindings.
      +
      protected intreopenInputLob(short action, + int columnNumber, + int matSize, + int xferBytes, + java.lang.Object buffer) +
      Reset a previously opened result stream and prepares the data source to return more result sets, + possibly based on different parameter bindings for queries with input large object (LOB) parameters.
      +
      protected voidreportEof() +
      Report an end-of-file condition during a fetch operation.
      +
      protected voidsetLobNext() +
      Notify the federated server when a current fetched row contains large object (LOB) values and + that the fetchLob method is to be invoked.
      +
      protected voidsetRowStatus(int status) +
      Set the current row status.
      +
      protected voidsetStatus(byte status) +
      Set the query status.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Detail

      + + + +
        +
      • +

        CLOSE_EOA

        +
        public static final byte CLOSE_EOA
        +
        Status constant used in close method to indicate + that the wrapper is to finish necessary cleanup and + that the RemoteQuery object is destroyed after the close + method returns.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        CLOSE_EOS

        +
        public static final byte CLOSE_EOS
        +
        Status constant used in close method + to indicate that the wrapper must leave the RemoteQuery in + a state so that the reopen or + reopenInputLob methods can be invoked.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        EOF

        +
        public static final byte EOF
        +
        Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object finished fetching all the rows of + the result set.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        FETCH_LOB_LAST

        +
        public static final int FETCH_LOB_LAST
        +
        LOB fetching status constant: indicate that the last buffer of data for + the current LOB column has been fetched.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        FETCH_LOB_MORE

        +
        public static final int FETCH_LOB_MORE
        +
        LOB fetching status constant: indicate that more data is available for the current LOB column.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        FETCH_LOB_NEXT

        +
        public static final int FETCH_LOB_NEXT
        +
        LOB fetching status constant: indicate that another LOB column is to be fetched next.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        FETCH_NON_LOB_NEXT

        +
        public static final int FETCH_NON_LOB_NEXT
        +
        LOB fetching status constant: indicate that a non-LOB column is to be fetched next.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        FETCH_ROW_DONE

        +
        public static final int FETCH_ROW_DONE
        +
        LOB fetching status constant: indicate that all the values for the current row have + been fetched.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        OPEN

        +
        public static final byte OPEN
        +
        Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object is in open state.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        OPEN_LOB_INIT

        +
        public static final int OPEN_LOB_INIT
        +
        LOB input status constant: indicate the start of processing for the input LOB values.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        OPEN_LOB_LAST

        +
        public static final int OPEN_LOB_LAST
        +
        LOB input status constant: indicate that this is the last fragment for the current input LOB value.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        OPEN_LOB_MORE

        +
        public static final int OPEN_LOB_MORE
        +
        LOB input status constant: indicate that more fragments are available for the current input LOB value.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        OPEN_LOB_NEW

        +
        public static final int OPEN_LOB_NEW
        +
        LOB input status constant: indicate that the wrapper expects data fragments for a new input LOB value.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        OPEN_NON_LOB_NEXT

        +
        public static final int OPEN_NON_LOB_NEXT
        +
        LOB input status constant: indicate that only input non-LOB values are to be processed.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        OPEN_ROW_DONE

        +
        public static final int OPEN_ROW_DONE
        +
        LOB input status constant: indicate that all the input values have been processed.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        READY

        +
        public static final byte READY
        +
        Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object is ready to fetch the next row.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        UNREADY

        +
        public static final byte UNREADY
        +
        Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object is not yet ready to fetch the next row.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        RemoteQuery

        +
        protected RemoteQuery(RemoteConnection activeConnection,
        +           long id)
        +
        Construct a new query object for the specified connection.
        +
        Parameters:
        activeConnection - The connection through which the query is executed.
        id - An integer value that represents the RemoteQuery object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteConnection
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        close

        +
        protected void close(short status)
        +              throws java.lang.Exception
        +
        Allow the wrapper and the data source to clean up after query statement processing. + The wrapper must implement this method in the wrapper specific RemoteQuery subclass. + A single SQL statement that is submitted to the federated server can result in multiple query + requests to a wrapper. + So that wrappers can more easily optimize the translation and submission of queries to the + data source, the close method receives a status flag that indicates whether the close + represents an end-of-query (CLOSE_EOS) or an end-of-statement (CLOSE_EOA) status. + If the close method is called with an end-of-query status, the RemoteQuery object can + execute the reopen method successfully. If the close method is called with an end-of-statement + status, the federated server destroys the RemoteQuery object after the close method completes.
        +
        Parameters:
        status - the status of the operation.
        +
        Throws:
        +
        java.lang.Exception - if the close operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        fetch

        +
        protected void fetch()
        +              throws java.lang.Exception
        +
        Fetch (retrieve) a single-result row from the remote data source into the output data buffers. + The wrapper must implement this method in the wrapper-specific RemoteQuery subclass.
        +
        Throws:
        +
        java.lang.Exception - if the fetch operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        fetchLob

        +
        protected java.lang.Object fetchLob(int bufferSize,
        +                        int bytesWritten)
        +                             throws java.lang.Exception
        +
        Retrieve a large object (LOB) fragment from the remote source. + The wrapper must implement this method in the wrapper-specific RemoteQuery subclass + if the wrapper transfers large objects (LOB). + The fetchLob method includes a function argument that specifies the maximum + size of the fetched (retrieved) data fragment. + The fetchLob method must call the lobDataReady method + to inform the federated server of the fetch status.
        +
        Parameters:
        bufferSize - The maximum size of the data fragment to be fetched.
        bytesWritten - The number of bytes already fetched for the current LOB.
        +
        Returns:
        A data fragment in the form of a string for Clob data and a byte array for Blob data.
        +
        Throws:
        +
        java.lang.Exception - if the fetchLob operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getRowStatus

        +
        protected final int getRowStatus()
        +
        Retrieve the current row status.
        +
        Returns:
        The current row status.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getStatus

        +
        protected final byte getStatus()
        +
        Retrieve the status of the query.
        +
        Returns:
        The status.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        lobDataReady

        +
        protected final void lobDataReady(int columnNumber,
        +                int bytesReady,
        +                int status,
        +                int intent)
        +                           throws WrapperException
        +
        Notify the federated server that a fragment of data from a LOB column is fetched (retrieved). + Call this method from the fetchLob method.
        +
        Parameters:
        columnNumber - The index of the column that this data fragment belongs to.
        bytesReady - The length the fragment in bytes.
        status - The status of the LOB operation. The status value can be + FETCH_LOB_MORE or FETCH_LOB_LAST.
        intent - The flag that indicates if there are any more LOB or non-LOB + columns to fetch or if the complete row was fetched.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        open

        +
        protected void open()
        +             throws java.lang.Exception
        +
        Allow the wrapper to prepare the remote data source to return the first result row for + the query. + The wrapper must implement this method in the wrapper-specific RemoteQuery subclass.
        +
        Throws:
        +
        java.lang.Exception - if the open operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        openInputLob

        +
        protected int openInputLob(int columnNumber,
        +               int matSize,
        +               int xferBytes,
        +               java.lang.Object buffer)
        +                    throws java.lang.Exception
        +
        Allow the wrapper to prepare the remote data source to return the first result row for + the query that contains input large object (LOB) parameters. + The wrapper must implement this method in the wrapper-specific RemoteQuery subclass if + the wrapper supports input large object (LOB) parameters. +
        + The federated server calls this method if input LOB host variables are found. + Initially the openInputLob method is called with an empty buffer and the columnNumber + parameter set to -1. The wrapper must return the index of the host variable that receives + the next LOB fragment, then call setRowStatus to indicate that there are input LOB + parameters. When the wrapper indicates that there are more LOB input parameters to process, + the federated server calls this method with another LOB fragment. The LOB input value total + size, in bytes, is given as the matSize parameter. The size of the current LOB fragment, + in bytes, is given as the xferBytes parameter. The wrapper must use these parameter values + to advance to the next input variable or to signal that the entire input values have been read.
        +
        Parameters:
        columnNumber - The index of the input host variable that receives the current LOB fragment.
        matSize - The materialized size of the input data, in bytes.
        xferBytes - The size of the current data fragment, in bytes.
        buffer - The current LOB fragment object. + The object is a string for CLOB variables and a byte array for BLOB variables.
        +
        Returns:
        The index of the input host variable that receives the next LOB fragment.
        +
        Throws:
        +
        java.lang.Exception - if the openInputLob process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        reopen

        +
        protected void reopen(short action)
        +               throws java.lang.Exception
        +
        Reset a previously opened result stream and prepares the data source to return more result sets, + possibly based on different parameter bindings. + The wrapper must implement this method in the wrapper-specific RemoteQuery subclass. + This method will not be called unless the query was previously closed with an end-of-query status. + See also the close method.
        +
        Parameters:
        action - Unused.
        +
        Throws:
        +
        java.lang.Exception - if the reopen operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        reopenInputLob

        +
        protected int reopenInputLob(short action,
        +                 int columnNumber,
        +                 int matSize,
        +                 int xferBytes,
        +                 java.lang.Object buffer)
        +                      throws java.lang.Exception
        +
        Reset a previously opened result stream and prepares the data source to return more result sets, + possibly based on different parameter bindings for queries with input large object (LOB) parameters. + The wrapper must implement this method in the wrapper-specific RemoteQuery subclass if + the wrapper supports input large object (LOB) parameters. + This method will not be called unless the query was previously closed with an end-of-query status. + See also the close method. +
        + The federated server calls this method if input LOB host variables are found. + Initially the reopenInputLob method is called with an empty buffer and the columnNumber + parameter set to -1. The wrapper must return the index of the host variable that receives + the next LOB fragment, then call setRowStatus to indicate that there are input LOB + parameters. When the wrapper indicates that there are more LOB input parameters to process, + the federated server calls this method with another LOB fragment. The LOB input value total + size, in bytes, is given as the matSize parameter. The size of the current LOB fragment, + in bytes, is given as the xferBytes parameter. The wrapper must use these parameter values + to advance to the next input variable or to signal that the entire input values have been read.
        +
        Parameters:
        action - Unused.
        columnNumber - The index of the input host variable that receives the current LOB fragment.
        matSize - The materialized size of the input data, in bytes.
        xferBytes - The size of the current data fragment, in bytes.
        buffer - The current LOB fragment object. + The object is a string for CLOB variables and a byte array for BLOB variables.
        +
        Returns:
        The index of the input host variable that receives the next LOB fragment.
        +
        Throws:
        +
        java.lang.Exception - if the reopenInputLob process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        reportEof

        +
        protected final void reportEof()
        +                        throws WrapperException
        +
        Report an end-of-file condition during a fetch operation. + The wrapper specific RemoteQuery subclass invokes this method during + the fetch operation to indicate that the last row was fetched.
        +
        +
        Overrides:
        +
        reportEof in class RemoteOperation
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setLobNext

        +
        protected final void setLobNext()
        +
        Notify the federated server when a current fetched row contains large object (LOB) values and + that the fetchLob method is to be invoked. + Call this method from the fetch method if there is LOB data to transfer. + Do not call the setLobNext method from inside the fetchLob method. +
        + After the fetch method returns and setLobNext is called, the federated + server calls fetchLob to retrieve the LOB column values.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setRowStatus

        +
        protected final void setRowStatus(int status)
        +
        Set the current row status.
        +
        Parameters:
        status - The new row status to be set.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setStatus

        +
        protected final void setStatus(byte status)
        +
        Set the query status.
        +
        Parameters:
        status - The new query status to be set.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteUser.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteUser.html new file mode 100644 index 0000000..ba4a443 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RemoteUser.html @@ -0,0 +1,408 @@ + + + + + +RemoteUser (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RemoteUser

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.SqlqgBaseClass
    • +
    • +
        +
      • com.ibm.db2.wrapper.RemoteUser
      • +
      +
    • +
    +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    FencedRemoteUser, UnfencedRemoteUser
    +
    +
    +
    +
    public class RemoteUser
    +extends com.ibm.db2.wrapper.SqlqgBaseClass
    +
    The RemoteUser class represents the authorizations to use on a data source server. + Each instance of this class or its subclasses represents an authorization + to use on the data source server that the wrapper works with. + The RemoteUser base class implementation maintains the following information: +
      +
    • The local (DB2 Information Integrator) authorization ID of the user. +
    • A UserInfo object that contains information about the data source + server and user pair that was stored in the federated server's system + catalog as a result of running DDL statements. +
    • A reference to the data source server object that contains the user information. +
    + +

    Usage:
    + Do not use this class directly, but instantiate or subclass the + FencedGenericRemoteUser class and the UnfencedGenericRemoteUser + class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Summary

      + + + + + + + + + + + + + + +
      Fields 
      Modifier and TypeField and Description
      static java.lang.StringREMOTE_AUTHID_OPTION +
      Constant that represents the name of the remote authorization ID option.
      +
      static java.lang.StringREMOTE_PASSWORD_OPTION +
      Constant that represents the name of the remote authorization password option.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      protected voiddestroy() +
      Destroys this user mapping object and frees any resources associated with it.
      +
      UserInfogetInfo() +
      Retrieve the user mapping information that is stored in the federated server's system + catalog as a result of running DDL statements.
      +
      java.lang.StringgetLocalName() +
      Retrieve the name of the user on the local database.
      +
      WrappergetWrapper() +
      Retrieve the wrapper instance that this user mapping belongs to.
      +
      protected voidinitializeMyUser(UserInfo userInfo) +
      Perform the necessary user mapping initialization.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Detail

      + + + +
        +
      • +

        REMOTE_AUTHID_OPTION

        +
        public static final java.lang.String REMOTE_AUTHID_OPTION
        +
        Constant that represents the name of the remote authorization ID option.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        REMOTE_PASSWORD_OPTION

        +
        public static final java.lang.String REMOTE_PASSWORD_OPTION
        +
        Constant that represents the name of the remote authorization password option.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        destroy

        +
        protected void destroy()
        +                throws java.lang.Exception
        +
        Destroys this user mapping object and frees any resources associated with it. + The default implementation does nothing. This method is called by the + federated server before the user mapping object is removed and gives the + wrapper a chance to free any resources allocated. + If wrapper-specific resources need to be freed, the wrapper writer can + implement this method in the wrapper-specific subclass + of UnfencedGenericRemoteUser and + FencedGenericRemoteUser.
        +
        Throws:
        +
        java.lang.Exception - if the processing fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getInfo

        +
        public final UserInfo getInfo()
        +
        Retrieve the user mapping information that is stored in the federated server's system + catalog as a result of running DDL statements.
        +
        Returns:
        An instance of UserInfo that contains the user mapping information.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        UserInfo
        +
      • +
      + + + +
        +
      • +

        getLocalName

        +
        public final java.lang.String getLocalName()
        +
        Retrieve the name of the user on the local database.
        +
        Returns:
        The local user name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getWrapper

        +
        public final Wrapper getWrapper()
        +
        Retrieve the wrapper instance that this user mapping belongs to.
        +
        Returns:
        The wrapper object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        initializeMyUser

        +
        protected void initializeMyUser(UserInfo userInfo)
        +                         throws java.lang.Exception
        +
        Perform the necessary user mapping initialization. + This method is called by the DB2 Information Integrator engine when the user mapping + is created or when its options are changed. + This method can be implemented by the wrapper writer in the wrapper-specific + RemoteUser subclass to perform the user mapping initialization.
        +
        Parameters:
        userInfo - An instance of UserInfo that represents the user mapping information.
        +
        Throws:
        +
        java.lang.Exception - if the initialization process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        UserInfo
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Reply.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Reply.html new file mode 100644 index 0000000..b6d3c0d --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Reply.html @@ -0,0 +1,692 @@ + + + + + +Reply (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class Reply

+
+
+ +
+
    +
  • +
    +
    +
    public class Reply
    +extends ParsedQueryFragment
    +
    The Reply class represents the portion of a request that the wrapper processes. + In addition to the actions of the ParsedQueryFragment class, the Reply class adds + methods and data members to initiate the following actions: +
      +
    • Populate the reply by adding entries to the clauses. +
    • Store the execution descriptor structure. +
    • Chain the replies when the wrapper returns more than one plan for the same request. +
    • Store order information. The optimizer might use returned data to construct an + optimal plan. +
    + +

    Advanced Customization is available with the Reply class by using an + execution cost (estimated execution time) for the reply query fragment. + The wrapper writer can override the default implementation of the costing + methods with ones that more precisely describe the execution model of the + source. Overriding the default costing is dependent on the default + selectivity estimation for the predicates in the query fragment. + Selectivity estimates are obtained by calling the + UnfencedGenericServer.getSelectivity + method that can also be overloaded by the wrapper writer.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Summary

      + + + + + + + + + + + + + + +
      Fields 
      Modifier and TypeField and Description
      static intASC +
      Constant that indicates the ascending ordering for an order entry.
      +
      static intDESC +
      Constant that indicates the descending ordering for an order entry.
      +
      +
    • +
    + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      Reply(Request request, + UnfencedGenericServer server) +
      Instantiate a Reply for the specified data source (Server) and Request.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      voidaddHeadExp(RequestExp headExp) +
      Add a head expression in the SELECT clause of the query.
      +
      voidaddOrderEntry(int position, + int direction) +
      Add an order entry in the ORDER BY clause of the query.
      +
      voidaddPredicate(RequestExp predicate) +
      Add a predicate in the WHERE clause of the query.
      +
      voidaddQuantifier(Quantifier quantifier) +
      Add a quantifier in the FROM clause of the query.
      +
      doublecardinality() +
      Retrieve the cardinality of the result when running + the query fragment that is represented by the reply.
      +
      doublefirstTupleCost() +
      Retrieve the cost that is required to obtain the first result tuple for + the query fragment that is represented by the reply.
      +
      java.io.SerializablegetExecDesc() +
      Retrieve the execution descriptor object.
      +
      intgetNumberOfOrderEntries() +
      Retrieve the number of order entries.
      +
      int[]getOrderEntry(int position) +
      Retrieve the order entry at the specified position in the ORDER by clause.
      +
      int[]getParameterOrder() +
      Retrieve a list of parameter handles.
      +
      UnfencedGenericServergetServer() +
      Retrieve the data source server that this reply belongs to.
      +
      ReplynextReply() +
      Retrieve the next reply in the chain.
      +
      doublereExecCost() +
      Retrieve the cost needed to rerun the query fragment + that is represented by the reply.
      +
      voidsetDistinct(boolean distinct) +
      Set the DISTINCT indicator that is specified in the SELECT DISTINCT statement.
      +
      voidsetExecDesc(java.io.Serializable execDesc) +
      Set the execution descriptor object.
      +
      voidsetNextReply(Reply nextReply) +
      Specify the next reply in the chain.
      +
      doubletotalCost() +
      Retrieve the total execution cost that is needed + to run the query fragment that is represented by the reply.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Detail

      + + + +
        +
      • +

        ASC

        +
        public static final int ASC
        +
        Constant that indicates the ascending ordering for an order entry.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        DESC

        +
        public static final int DESC
        +
        Constant that indicates the descending ordering for an order entry.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        Reply

        +
        public Reply(Request request,
        +     UnfencedGenericServer server)
        +
        Instantiate a Reply for the specified data source (Server) and Request.
        +
        Parameters:
        request - The Request object for which the Reply is generated. + The Request object encapsulates a query fragment that + is to be analyzed and processed by the wrapper.
        server - The Server object that is processing the Request and + generates the Reply.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        addHeadExp

        +
        public final void addHeadExp(RequestExp headExp)
        +
        Add a head expression in the SELECT clause of the query.
        +
        Parameters:
        headExp - The head expression to be added in the SELECT clause.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RequestExp
        +
      • +
      + + + +
        +
      • +

        addOrderEntry

        +
        public final void addOrderEntry(int position,
        +                 int direction)
        +                         throws WrapperException
        +
        Add an order entry in the ORDER BY clause of the query. + An order entry consists of the head expression position and the direction + (ASC or DESC).
        +
        Parameters:
        position - The position of the head expression in the SELECT clause.
        direction - The type of ordering: ASC - ascending order or DESC - descending order.
        +
        Throws:
        +
        WrapperException - if the direction is not valid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        addPredicate

        +
        public final void addPredicate(RequestExp predicate)
        +
        Add a predicate in the WHERE clause of the query.
        +
        Parameters:
        predicate - The predicate expression to be added in the WHERE clause.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RequestExp
        +
      • +
      + + + +
        +
      • +

        addQuantifier

        +
        public final void addQuantifier(Quantifier quantifier)
        +
        Add a quantifier in the FROM clause of the query.
        +
        Parameters:
        quantifier - The quantifier to be added in the FROM clause.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Quantifier
        +
      • +
      + + + +
        +
      • +

        cardinality

        +
        public double cardinality()
        +
        Retrieve the cardinality of the result when running + the query fragment that is represented by the reply.
        +
        Returns:
        The cardinality.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        firstTupleCost

        +
        public double firstTupleCost()
        +
        Retrieve the cost that is required to obtain the first result tuple for + the query fragment that is represented by the reply.
        +
        Returns:
        The first tuple cost.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getExecDesc

        +
        public final java.io.Serializable getExecDesc()
        +
        Retrieve the execution descriptor object.
        +
        Returns:
        The execution descriptor.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNumberOfOrderEntries

        +
        public final int getNumberOfOrderEntries()
        +
        Retrieve the number of order entries.
        +
        Returns:
        The number of order entries.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getOrderEntry

        +
        public final int[] getOrderEntry(int position)
        +                          throws WrapperException
        +
        Retrieve the order entry at the specified position in the ORDER by clause. + An order entry consists of the head expression position and the direction + (ASC or DESC).
        +
        Parameters:
        position - The position of the order entry in the ORDER BY clause. + The first entry is at position 1.
        +
        Returns:
        An array of two integer values: the position of the head expression in + the SELECT clause and the order type, either ASC (ascending) or DESC (descending).
        +
        Throws:
        +
        WrapperException - if the requested position is not valid
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getParameterOrder

        +
        public final int[] getParameterOrder()
        +                              throws WrapperException
        +
        Retrieve a list of parameter handles. + The order of the list corresponds to the order of + the parameter values in the RemoteOperation object. + The wrapper calls this method after all the head expressions + and all the predicates that can be processed by the wrapper + have been added to the Reply object.
        +
        Returns:
        Array of the parameters handles.
        +
        Throws:
        +
        WrapperException - if the processing fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getServer

        +
        public final UnfencedGenericServer getServer()
        +
        Retrieve the data source server that this reply belongs to.
        +
        Returns:
        The data source server of the reply.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        UnfencedGenericServer
        +
      • +
      + + + +
        +
      • +

        nextReply

        +
        public final Reply nextReply()
        +
        Retrieve the next reply in the chain.
        +
        Returns:
        The next reply in the chain or null + if there are no more replies.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        reExecCost

        +
        public double reExecCost()
        +
        Retrieve the cost needed to rerun the query fragment + that is represented by the reply.
        +
        Returns:
        The re-execution cost.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setDistinct

        +
        public final void setDistinct(boolean distinct)
        +
        Set the DISTINCT indicator that is specified in the SELECT DISTINCT statement.
        +
        Parameters:
        distinct - The DISTINCT indicator.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setExecDesc

        +
        public final void setExecDesc(java.io.Serializable execDesc)
        +
        Set the execution descriptor object.
        +
        Parameters:
        execDesc - The execution descriptor.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNextReply

        +
        public final void setNextReply(Reply nextReply)
        +
        Specify the next reply in the chain. + Chain the replies when the wrapper returns more than one reply for a request.
        +
        Parameters:
        nextReply - The Reply object to be added in the chain.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        totalCost

        +
        public double totalCost()
        +
        Retrieve the total execution cost that is needed + to run the query fragment that is represented by the reply.
        +
        Returns:
        The total cost.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Request.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Request.html new file mode 100644 index 0000000..375b841 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Request.html @@ -0,0 +1,208 @@ + + + + + +Request (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class Request

+
+
+ +
+
    +
  • +
    +
    +
    public final class Request
    +extends ParsedQueryFragment
    +
    The Request class encapsulates a query fragment that is analyzed and processed by the wrapper. + + The federated server provides instances of this class to the + UnfencedGenericServer.planRequest method + which returns the appropriate Reply objects.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestConstant.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestConstant.html new file mode 100644 index 0000000..2ffe29b --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestConstant.html @@ -0,0 +1,432 @@ + + + + + +RequestConstant (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RequestConstant

+
+
+ +
+
    +
  • +
    +
    +
    public final class RequestConstant
    +extends Data
    +
    The RequestConstant class describes a constant that is used in a query + expression during query planning. + The RequestExp.getValue method returns an + instance of the RequestConstant class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getCodepage

        +
        public short getCodepage()
        +
        Retrieve the code page for character data types.
        +
        Returns:
        The code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getData

        +
        protected byte[] getData()
        +
        Retrieve the data buffer in an internal format.
        +
        +
        Specified by:
        +
        getData in class Data
        +
        Returns:
        The data buffer.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDataType

        +
        public short getDataType()
        +
        Retrieve the data type.
        +
        +
        Specified by:
        +
        getDataType in class Data
        +
        Returns:
        The data type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getForBitData

        +
        public boolean getForBitData()
        +
        Retrieve the FOR BIT DATA flag.
        +
        +
        Specified by:
        +
        getForBitData in class Data
        +
        Returns:
        The FOR BIT DATA flag.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getMaximumLength

        +
        public int getMaximumLength()
        +
        Retrieve the maximum length for the data type.
        +
        Returns:
        The maximum length.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getName

        +
        public java.lang.String getName()
        +
        Retrieve the name of the constant, if defined.
        +
        Returns:
        The constant name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNullIndicator

        +
        public short getNullIndicator()
        +
        Retrieve the null indicator.
        +
        Returns:
        The null indicator which is Data.SQL_NULLABLE or Data.SQL_NO_NULLS
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPrecision

        +
        public byte getPrecision()
        +
        Retrieve the precision for numeric data types.
        +
        Returns:
        The precision.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getScale

        +
        public byte getScale()
        +
        Retrieve the scale for numeric data types.
        +
        Returns:
        The scale.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isDataNull

        +
        public boolean isDataNull()
        +
        Indicate whether the constant is null.
        +
        Returns:
        true if the constant is null, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestExp.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestExp.html new file mode 100644 index 0000000..9312dba --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestExp.html @@ -0,0 +1,582 @@ + + + + + +RequestExp (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RequestExp

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.RequestExp
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public class RequestExp
    +extends java.lang.Object
    +
    The RequestExp class represents a node in an expression tree. + This node can be a column reference, a constant value, + an unbound parameter or an operator. + An unbound parameter is similar to a constant. However, its + value is unknown until the run-time phase when the federated + server passes the value to the wrapper. + +

    Usage:
    + A RequestExp object is never instantiated by the wrapper. The + federated server creates these objects and passes them to the + wrapper during query planning.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Fields 
      Modifier and TypeField and Description
      static intBADKIND +
      Constant to indicate that the expression is unknown.
      +
      static intCOLUMN +
      Constant to indicate that the expression is a column.
      +
      static intCONSTANT +
      Constant to indicate that the expression is a constant.
      +
      static intOPERATOR +
      Constant to indicate that the expression is an operator.
      +
      static intUNBOUND +
      Constant to indicate that the expression is an unbound parameter.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      java.lang.StringgetColumnName() +
      Column expression node: Retrieve the column name.
      +
      RequestExpTypegetDataType() +
      Retrieve the object that describes the data type of the expression.
      +
      RequestExpgetFirstChild() +
      Operator expression node: Retrieve the first child of the operator.
      +
      intgetHandle() +
      Retrieve the expression handle.
      +
      intgetKind() +
      Retrieve the kind of the expression.
      +
      RequestExpgetNextChild() +
      Retrieve the sibling of the expression.
      +
      intgetNumberOfChildren() +
      Operator expression node: Retrieve the number of children for the operator.
      +
      RequestExpgetParent() +
      Retrieve the parent node of the expression.
      +
      QuantifiergetQuantifier() +
      Column expression node: Retrieve the quantifier to which this column belongs.
      +
      java.lang.StringgetSignature() +
      Operator expression node: Retrieve the signature of the operator.
      +
      java.lang.StringgetToken() +
      Operator expression node: Retrieve the token of the operator.
      +
      RequestConstantgetValue() +
      Constant expression node: Retrieve the RequestConstant object that represents + the value of the constant.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Detail

      + + + +
        +
      • +

        BADKIND

        +
        public static final int BADKIND
        +
        Constant to indicate that the expression is unknown.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        COLUMN

        +
        public static final int COLUMN
        +
        Constant to indicate that the expression is a column.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        CONSTANT

        +
        public static final int CONSTANT
        +
        Constant to indicate that the expression is a constant.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        OPERATOR

        +
        public static final int OPERATOR
        +
        Constant to indicate that the expression is an operator.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      + + + +
        +
      • +

        UNBOUND

        +
        public static final int UNBOUND
        +
        Constant to indicate that the expression is an unbound parameter.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getColumnName

        +
        public java.lang.String getColumnName()
        +                               throws WrapperException
        +
        Column expression node: Retrieve the column name.
        +
        Returns:
        The column name.
        +
        Throws:
        +
        WrapperException - if the method is called for non-column expression nodes.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDataType

        +
        public RequestExpType getDataType()
        +
        Retrieve the object that describes the data type of the expression.
        +
        Returns:
        The expression type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RequestExpType
        +
      • +
      + + + +
        +
      • +

        getFirstChild

        +
        public RequestExp getFirstChild()
        +                         throws WrapperException
        +
        Operator expression node: Retrieve the first child of the operator.
        +
        Returns:
        The first child.
        +
        Throws:
        +
        WrapperException - if the method is called for non-operator expression nodes.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getHandle

        +
        public int getHandle()
        +
        Retrieve the expression handle.
        +
        Returns:
        The handle.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getKind

        +
        public int getKind()
        +
        Retrieve the kind of the expression.
        +
        Returns:
        The expression kind.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNextChild

        +
        public RequestExp getNextChild()
        +
        Retrieve the sibling of the expression.
        +
        Returns:
        The next sibling or null if the expression does not have a sibling.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNumberOfChildren

        +
        public int getNumberOfChildren()
        +                        throws WrapperException
        +
        Operator expression node: Retrieve the number of children for the operator.
        +
        Returns:
        The number of children.
        +
        Throws:
        +
        WrapperException - if the method is called for non-operator expression nodes.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getParent

        +
        public RequestExp getParent()
        +
        Retrieve the parent node of the expression.
        +
        Returns:
        The parent expression.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getQuantifier

        +
        public Quantifier getQuantifier()
        +                         throws WrapperException
        +
        Column expression node: Retrieve the quantifier to which this column belongs.
        +
        Returns:
        The quantifier.
        +
        Throws:
        +
        WrapperException - if the method is called for non-column expression nodes.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getSignature

        +
        public java.lang.String getSignature()
        +                              throws WrapperException
        +
        Operator expression node: Retrieve the signature of the operator.
        +
        Returns:
        The signature of the operator.
        +
        Throws:
        +
        WrapperException - if the method is called for non-operator expression nodes.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getToken

        +
        public java.lang.String getToken()
        +                          throws WrapperException
        +
        Operator expression node: Retrieve the token of the operator.
        +
        Returns:
        The token of the operator.
        +
        Throws:
        +
        WrapperException - if the method is called for non-operator expression nodes.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getValue

        +
        public RequestConstant getValue()
        +                         throws WrapperException
        +
        Constant expression node: Retrieve the RequestConstant object that represents + the value of the constant.
        +
        Returns:
        The value of the constant as a RequestConstant instance.
        +
        Throws:
        +
        WrapperException - if the method is called for non-constant expression nodes.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RequestConstant
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestExpType.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestExpType.html new file mode 100644 index 0000000..dbd6ea7 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RequestExpType.html @@ -0,0 +1,364 @@ + + + + + +RequestExpType (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RequestExpType

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.RequestExpType
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public final class RequestExpType
    +extends java.lang.Object
    +
    The RequestExpType class describes the type of node in an expression tree. + This node can be a column reference, a constant value, + an unbound parameter or an operator. + +

    Usage:
    + The wrapper never instantiates a RequestExpType object. + The federated server creates these objects and passes them + to the wrapper during query planning.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      shortgetCodepage() +
      Retrieve the code page for character data types.
      +
      shortgetDataType() +
      Retrieve the data type.
      +
      booleangetForBitData() +
      Retrieve the FOR BIT DATA flag which indicates whether the data is in binary format.
      +
      intgetMaximumLength() +
      Retrieve the maximum length for the data type.
      +
      java.lang.StringgetName() +
      Retrieve the name of the data type.
      +
      shortgetNullIndicator() +
      Retrieve the null indicator value.
      +
      bytegetPrecision() +
      Retrieve the precision for numeric data types.
      +
      bytegetScale() +
      Retrieve the scale for numeric data types.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getCodepage

        +
        public short getCodepage()
        +
        Retrieve the code page for character data types.
        +
        Returns:
        The code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDataType

        +
        public short getDataType()
        +
        Retrieve the data type.
        +
        Returns:
        The data type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getForBitData

        +
        public boolean getForBitData()
        +
        Retrieve the FOR BIT DATA flag which indicates whether the data is in binary format.
        +
        Returns:
        The FOR BIT DATA flag.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getMaximumLength

        +
        public int getMaximumLength()
        +
        Retrieve the maximum length for the data type.
        +
        Returns:
        The maximum length.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getName

        +
        public java.lang.String getName()
        +
        Retrieve the name of the data type.
        +
        Returns:
        The name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNullIndicator

        +
        public short getNullIndicator()
        +
        Retrieve the null indicator value.
        +
        Returns:
        The null indicator which is Data.SQL_NULLABLE or Data.SQL_NO_NULLS
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPrecision

        +
        public byte getPrecision()
        +
        Retrieve the precision for numeric data types.
        +
        Returns:
        The precision.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getScale

        +
        public byte getScale()
        +
        Retrieve the scale for numeric data types.
        +
        Returns:
        The scale.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeData.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeData.html new file mode 100644 index 0000000..1f5ea44 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeData.html @@ -0,0 +1,1062 @@ + + + + + +RuntimeData (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RuntimeData

+
+
+ +
+
    +
  • +
    +
    +
    public final class RuntimeData
    +extends Data
    +
    The RuntimeData class represents each column value that is transferred between the + federated server and a wrapper. + A column value can be part of a result row being transferred from the wrapper to + the federated server, or it can be a value to be bound to a runtime parameter in + a query that is submitted to the wrapper by the federated server.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + + + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      booleancheckFriendlyDivBy0() +
      Determine if the reason for a null indication is a divide by zero error.
      +
      booleancheckFriendlyException() +
      Determine if the reason for a null indication is a numeric exception.
      +
      voidclearNullIndicator() +
      Clear the null indicator for the data value.
      +
      intgetActualLength() +
      Retrieve the actual length for the data value.
      +
      shortgetCodepage() +
      Retrieve the code page for character data type values.
      +
      protected byte[]getData() +
      Retrieve the data value in an internal format.
      +
      intgetDataIndex() +
      Retrieve the column number for the data value.
      +
      shortgetDataType() +
      Retrieve the data type.
      +
      booleangetForBitData() +
      Retrieve the FOR BIT DATA flag which indicates binary data.
      +
      bytegetInvariant() +
      Retrieve the invariant value.
      +
      intgetMaximumLength() +
      Retrieve the maximum length of the data.
      +
      java.lang.StringgetName() +
      Retrieve the name for the data.
      +
      shortgetNullIndicator() +
      Retrieve the null indicator for the data value.
      +
      bytegetPrecision() +
      Retrieve the precision for numeric data type values.
      +
      intgetRemoteLength() +
      Retrieve the remote length of the data value.
      +
      bytegetRemotePrecision() +
      Retrieve the remote precision for the numeric data type values.
      +
      bytegetRemoteScale() +
      Retrieve the remote scale of the numeric data type values.
      +
      shortgetRemoteType() +
      Retrieve the remote type of the data value.
      +
      bytegetScale() +
      Retrieve the scale for numeric data type values.
      +
      booleanisDataNull() +
      Indicate whether the data value is null.
      +
      booleanisDataNullable() +
      Indicate whether the data value is nullable.
      +
      booleanisSemanticNull() +
      Indicate whether the data value is semantic null.
      +
      voidsetActualLength(int length) +
      Set the actual length for the data value.
      +
      voidsetBigDecimal(java.math.BigDecimal value) +
      Set the data value as a BigDecimal instance.
      +
      voidsetBinary(byte[] value) +
      Set the data value as a binary value.
      +
      voidsetByte(byte value) +
      Set the data value as a byte.
      +
      voidsetDataNull() +
      Mark the data value as null.
      +
      voidsetDate(java.sql.Date value) +
      Set the data value as a Date instance.
      +
      voidsetDouble(double value) +
      Set the data value as a double.
      +
      voidsetFloat(float value) +
      Set the data value as a float.
      +
      voidsetFriendlyDivBy0() +
      Indicate that a value is null because a divide by zero error occurred.
      +
      voidsetFriendlyException() +
      Indicate that a value is null because of a numeric exception.
      +
      voidsetInt(int value) +
      Set the data value as an int.
      +
      voidsetLong(long value) +
      Set the data value as a long.
      +
      voidsetNullIndicator(short indicator) +
      Set the null indicator for the data value.
      +
      voidsetObject(java.lang.Object value) +
      Set the data value as an Object instance.
      +
      voidsetPrecision(byte precision) +
      Set the precision for numeric data type values.
      +
      voidsetScale(byte scale) +
      Set the scale for numeric data type values.
      +
      voidsetShort(short value) +
      Set the data value as a short.
      +
      voidsetString(java.lang.String value) +
      Set the data value as a string.
      +
      voidsetTime(java.sql.Time value) +
      Set the data value as a Time instance.
      +
      voidsetTimestamp(java.sql.Timestamp value) +
      Set the data value as a Timestamp instance.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        checkFriendlyDivBy0

        +
        public boolean checkFriendlyDivBy0()
        +
        Determine if the reason for a null indication is a divide by zero error.
        +
        Returns:
        true if divide by zero error occurred, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        checkFriendlyException

        +
        public boolean checkFriendlyException()
        +
        Determine if the reason for a null indication is a numeric exception.
        +
        Returns:
        true if numeric exception occurred, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        clearNullIndicator

        +
        public void clearNullIndicator()
        +                        throws WrapperException
        +
        Clear the null indicator for the data value.
        +
        Throws:
        +
        WrapperException - if the operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getActualLength

        +
        public int getActualLength()
        +
        Retrieve the actual length for the data value.
        +
        Returns:
        The actual length.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getCodepage

        +
        public short getCodepage()
        +
        Retrieve the code page for character data type values.
        +
        Returns:
        The code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getData

        +
        protected byte[] getData()
        +                  throws WrapperException
        +
        Retrieve the data value in an internal format.
        +
        +
        Specified by:
        +
        getData in class Data
        +
        Returns:
        The data in an internal format.
        +
        Throws:
        +
        WrapperException - - if the processing fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDataIndex

        +
        public int getDataIndex()
        +
        Retrieve the column number for the data value.
        +
        Returns:
        The column number.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDataType

        +
        public short getDataType()
        +
        Retrieve the data type.
        +
        +
        Specified by:
        +
        getDataType in class Data
        +
        Returns:
        The data type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getForBitData

        +
        public boolean getForBitData()
        +
        Retrieve the FOR BIT DATA flag which indicates binary data.
        +
        +
        Specified by:
        +
        getForBitData in class Data
        +
        Returns:
        The FOR BIT DATA flag.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getInvariant

        +
        public byte getInvariant()
        +
        Retrieve the invariant value. The value of an invariant parameter will not change unless + the wrapper is notified via the "action" parameter of the RemoteQuery.reopen(short) method.
        +
        Returns:
        The invariant value.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getMaximumLength

        +
        public int getMaximumLength()
        +
        Retrieve the maximum length of the data.
        +
        Returns:
        The maximum length.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getName

        +
        public java.lang.String getName()
        +
        Retrieve the name for the data.
        +
        Returns:
        The name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNullIndicator

        +
        public short getNullIndicator()
        +
        Retrieve the null indicator for the data value.
        +
        Returns:
        The null indicator which is Data.SQL_NULLABLE or Data.SQL_NO_NULLS
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPrecision

        +
        public byte getPrecision()
        +
        Retrieve the precision for numeric data type values.
        +
        Returns:
        The precision.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getRemoteLength

        +
        public int getRemoteLength()
        +
        Retrieve the remote length of the data value.
        +
        Returns:
        The remote length.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getRemotePrecision

        +
        public byte getRemotePrecision()
        +
        Retrieve the remote precision for the numeric data type values.
        +
        Returns:
        The remote precision.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getRemoteScale

        +
        public byte getRemoteScale()
        +
        Retrieve the remote scale of the numeric data type values.
        +
        Returns:
        The remote scale.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getRemoteType

        +
        public short getRemoteType()
        +
        Retrieve the remote type of the data value.
        +
        Returns:
        The remote type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getScale

        +
        public byte getScale()
        +
        Retrieve the scale for numeric data type values.
        +
        Returns:
        The scale.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isDataNull

        +
        public boolean isDataNull()
        +
        Indicate whether the data value is null.
        +
        Returns:
        true if the data is null, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isDataNullable

        +
        public boolean isDataNullable()
        +
        Indicate whether the data value is nullable.
        +
        Returns:
        true if the data is nullable, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isSemanticNull

        +
        public boolean isSemanticNull()
        +
        Indicate whether the data value is semantic null.
        +
        Returns:
        true if the data is semantic null, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setActualLength

        +
        public void setActualLength(int length)
        +
        Set the actual length for the data value.
        +
        Parameters:
        length - The actual length.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setBigDecimal

        +
        public void setBigDecimal(java.math.BigDecimal value)
        +                   throws WrapperException
        +
        Set the data value as a BigDecimal instance.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setBinary

        +
        public void setBinary(byte[] value)
        +               throws WrapperException
        +
        Set the data value as a binary value.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setByte

        +
        public void setByte(byte value)
        +             throws WrapperException
        +
        Set the data value as a byte.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setDataNull

        +
        public void setDataNull()
        +                 throws WrapperException
        +
        Mark the data value as null.
        +
        Throws:
        +
        WrapperException - if data cannot be null.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setDate

        +
        public void setDate(java.sql.Date value)
        +             throws WrapperException
        +
        Set the data value as a Date instance.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setDouble

        +
        public void setDouble(double value)
        +               throws WrapperException
        +
        Set the data value as a double.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setFloat

        +
        public void setFloat(float value)
        +              throws WrapperException
        +
        Set the data value as a float.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setFriendlyDivBy0

        +
        public void setFriendlyDivBy0()
        +                       throws WrapperException
        +
        Indicate that a value is null because a divide by zero error occurred. + The wrapper should call setDataNull() before.
        +
        Throws:
        +
        WrapperException - if the operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setFriendlyException

        +
        public void setFriendlyException()
        +                          throws WrapperException
        +
        Indicate that a value is null because of a numeric exception. + The wrapper should call setDataNull() before.
        +
        Throws:
        +
        WrapperException - if the operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setInt

        +
        public void setInt(int value)
        +            throws WrapperException
        +
        Set the data value as an int.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setLong

        +
        public void setLong(long value)
        +             throws WrapperException
        +
        Set the data value as a long.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setNullIndicator

        +
        public void setNullIndicator(short indicator)
        +
        Set the null indicator for the data value.
        +
        Parameters:
        indicator - The null indicator.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setObject

        +
        public void setObject(java.lang.Object value)
        +               throws WrapperException
        +
        Set the data value as an Object instance.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setPrecision

        +
        public void setPrecision(byte precision)
        +
        Set the precision for numeric data type values.
        +
        Parameters:
        precision - The precision.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setScale

        +
        public void setScale(byte scale)
        +
        Set the scale for numeric data type values.
        +
        Parameters:
        scale - The scale.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setShort

        +
        public void setShort(short value)
        +              throws WrapperException
        +
        Set the data value as a short.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setString

        +
        public void setString(java.lang.String value)
        +               throws WrapperException
        +
        Set the data value as a string.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setTime

        +
        public void setTime(java.sql.Time value)
        +             throws WrapperException
        +
        Set the data value as a Time instance.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setTimestamp

        +
        public void setTimestamp(java.sql.Timestamp value)
        +                  throws WrapperException
        +
        Set the data value as a Timestamp instance.
        +
        Parameters:
        value - The data value.
        +
        Throws:
        +
        WrapperException - if the data type is not compatible.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataDesc.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataDesc.html new file mode 100644 index 0000000..1dfc293 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataDesc.html @@ -0,0 +1,586 @@ + + + + + +RuntimeDataDesc (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RuntimeDataDesc

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.RuntimeDataDesc
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public final class RuntimeDataDesc
    +extends java.lang.Object
    +
    The RuntimeDataDesc class is created by the federated server to describe each column + value that is transferred between the federated server and a wrapper. + A column value can be part of a result row that is transferred from the wrapper to the + federated server, or a value to be bound to a run-time parameter in a query that is + submitted to the wrapper by the federated server. + +

    Usage:
    + For both RemoteQuery and RemotePassthru objects, the federated server + creates a RuntimeDataDesc instance for each RuntimeData object in the input data list that + represents the parameter values. The federated server supplies the column descriptions. + For RemoteQuery objects, the federated server also creates a RuntimeDataDesc instance + for each RuntimeData object in the output data list that represents values in result rows. + The federated server supplies these column descriptions as well. + The wrapper writer creates instances of the RuntimeDataDesc class to describe the result set of + a pass-through session in the RemotePassthru.describe method.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + + + + + + + + + + + +
      Constructors 
      Constructor and Description
      RuntimeDataDesc(short type, + int maxLength, + short codepage, + short nullIndicator) +
      Construct a new RuntimeDataDesc object with the specified attributes + to describe a column of a result set.
      +
      RuntimeDataDesc(short type, + int maxLength, + short codepage, + short nullIndicator, + byte precision) +
      Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
      +
      RuntimeDataDesc(short type, + int maxLength, + short codepage, + short nullIndicator, + byte precision, + byte scale) +
      Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
      +
      RuntimeDataDesc(short type, + int maxLength, + short codepage, + short nullIndicator, + byte precision, + byte scale, + java.lang.String name) +
      Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
      +
      RuntimeDataDesc(short type, + int maxLength, + short codepage, + short nullIndicator, + byte precision, + byte scale, + java.lang.String name, + short remoteType) +
      Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      shortgetCodepage() +
      Retrieve the code page for character data type values.
      +
      shortgetDataType() +
      Retrieve the type of data.
      +
      booleangetForBitData() +
      Retrieve the FOR BIT DATA flag which indicates binary data.
      +
      intgetMaximumLength() +
      Retrieve the maximum length of the data.
      +
      java.lang.StringgetName() +
      Retrieve the name for the data.
      +
      shortgetNullIndicator() +
      Retrieve the null indicator for the data value.
      +
      bytegetPrecision() +
      Retrieve the precision for numeric data type values.
      +
      shortgetRemoteType() +
      Retrieve the remote type of the data.
      +
      bytegetScale() +
      Retrieve the scale for numeric data type values.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        RuntimeDataDesc

        +
        public RuntimeDataDesc(short type,
        +               int maxLength,
        +               short codepage,
        +               short nullIndicator)
        +                throws WrapperException
        +
        Construct a new RuntimeDataDesc object with the specified attributes + to describe a column of a result set.
        +
        Parameters:
        type - The type ID of the data.
        maxLength - The maximum length of the data.
        codepage - The code page in which data is represented. + This parameter is valid for character data types only.
        nullIndicator - The indicator of a null value.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        RuntimeDataDesc

        +
        public RuntimeDataDesc(short type,
        +               int maxLength,
        +               short codepage,
        +               short nullIndicator,
        +               byte precision)
        +                throws WrapperException
        +
        Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
        +
        Parameters:
        type - The type ID of the data.
        maxLength - The maximum length of the data.
        codepage - The code page in which data is represented. + This parameter is valid for character data types only.
        nullIndicator - The indicator of a null value.
        precision - The precision of the data. + This parameter is valid for numeric and decimal data types only.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        RuntimeDataDesc

        +
        public RuntimeDataDesc(short type,
        +               int maxLength,
        +               short codepage,
        +               short nullIndicator,
        +               byte precision,
        +               byte scale)
        +                throws WrapperException
        +
        Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
        +
        Parameters:
        type - The type ID of the data.
        maxLength - The maximum length of the data.
        codepage - The code page in which data is represented. + This parameter is valid for character data types only.
        nullIndicator - The indicator of a null value.
        precision - The precision of the data. + This parameter is valid for numeric and decimal data types only.
        scale - The scale of the data. + This parameter is valid for numeric and decimal data types only.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        RuntimeDataDesc

        +
        public RuntimeDataDesc(short type,
        +               int maxLength,
        +               short codepage,
        +               short nullIndicator,
        +               byte precision,
        +               byte scale,
        +               java.lang.String name)
        +                throws WrapperException
        +
        Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
        +
        Parameters:
        type - The type ID of the data.
        maxLength - The maximum length of the data.
        codepage - The codepage in which data is represented. + This parameter is valid for character data types only.
        nullIndicator - The indicator of a null value.
        precision - The precision of the data. + This parameter is valid for numeric and decimal data types only.
        scale - The scale of the data. + This parameter is valid for numeric and decimal data types only.
        name - The name of the data column.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        RuntimeDataDesc

        +
        public RuntimeDataDesc(short type,
        +               int maxLength,
        +               short codepage,
        +               short nullIndicator,
        +               byte precision,
        +               byte scale,
        +               java.lang.String name,
        +               short remoteType)
        +                throws WrapperException
        +
        Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
        +
        Parameters:
        type - The type ID of the data.
        maxLength - The maximum length of the data.
        codepage - The code page in which data is represented. + This parameter is valid for character data types only.
        nullIndicator - The indicator of a null value.
        precision - The precision of the data. + This parameter is valid for numeric and decimal data types only.
        scale - The scale of the data. + This parameter is valid for numeric and decimal data types only.
        name - The name of the data column.
        remoteType - The type of the data at the remote data source.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getCodepage

        +
        public short getCodepage()
        +
        Retrieve the code page for character data type values.
        +
        Returns:
        The code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDataType

        +
        public short getDataType()
        +
        Retrieve the type of data.
        +
        Returns:
        The data type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getForBitData

        +
        public boolean getForBitData()
        +
        Retrieve the FOR BIT DATA flag which indicates binary data.
        +
        Returns:
        The FOR BIT DATA flag.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getMaximumLength

        +
        public int getMaximumLength()
        +
        Retrieve the maximum length of the data.
        +
        Returns:
        The maximum length.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getName

        +
        public java.lang.String getName()
        +                         throws WrapperException
        +
        Retrieve the name for the data.
        +
        Returns:
        The name.
        +
        Throws:
        +
        WrapperException
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getNullIndicator

        +
        public short getNullIndicator()
        +
        Retrieve the null indicator for the data value.
        +
        Returns:
        The null indicator which is Data.SQL_NULLABLE or Data.SQL_NO_NULLS
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPrecision

        +
        public byte getPrecision()
        +
        Retrieve the precision for numeric data type values.
        +
        Returns:
        The precision.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getRemoteType

        +
        public short getRemoteType()
        +
        Retrieve the remote type of the data.
        +
        Returns:
        The remote type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getScale

        +
        public byte getScale()
        +
        Retrieve the scale for numeric data type values.
        +
        Returns:
        The scale.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataDescList.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataDescList.html new file mode 100644 index 0000000..02faca6 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataDescList.html @@ -0,0 +1,299 @@ + + + + + +RuntimeDataDescList (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RuntimeDataDescList

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.RuntimeDataDescList
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public final class RuntimeDataDescList
    +extends java.lang.Object
    +
    The RuntimeDataDescList class encapsulates a list of RuntimeDataDesc + objects that describe a row in a result set or a list of input parameters.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      intgetNumberOfValues() +
      Retrieve the number of data descriptors in the list.
      +
      RuntimeDataDescgetValue(int position) +
      Retrieve the data descriptor at the specified position in the list.
      +
      voidsetNumberOfValues(int newNumber) +
      Set the number of data descriptors in the list.
      +
      voidsetValue(RuntimeDataDesc runtimeDataDesc, + int position) +
      Set the data descriptor at the specified position in the list.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getNumberOfValues

        +
        public int getNumberOfValues()
        +
        Retrieve the number of data descriptors in the list.
        +
        Returns:
        The number of data descriptors.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getValue

        +
        public RuntimeDataDesc getValue(int position)
        +
        Retrieve the data descriptor at the specified position in the list.
        +
        Parameters:
        position - The position of the data descriptor to be returned. + The first data descriptor is at position zero in the list.
        +
        Returns:
        The data descriptor.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RuntimeDataDesc
        +
      • +
      + + + +
        +
      • +

        setNumberOfValues

        +
        public void setNumberOfValues(int newNumber)
        +                       throws WrapperException
        +
        Set the number of data descriptors in the list.
        +
        Parameters:
        newNumber - The number of data descriptors.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setValue

        +
        public void setValue(RuntimeDataDesc runtimeDataDesc,
        +            int position)
        +              throws WrapperException
        +
        Set the data descriptor at the specified position in the list.
        +
        Parameters:
        runtimeDataDesc - The data descriptor that is saved in the list.
        position - The position where the data descriptor is placed. + The first data descriptor is at position zero in the list.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RuntimeDataDesc
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataList.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataList.html new file mode 100644 index 0000000..b020454 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/RuntimeDataList.html @@ -0,0 +1,253 @@ + + + + + +RuntimeDataList (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class RuntimeDataList

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.RuntimeDataList
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public final class RuntimeDataList
    +extends java.lang.Object
    +
    The RuntimeDataList class encapsulates a list of RuntimeData objects + that represent either a row in a result set or a list of input parameters.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      intgetNumberOfValues() +
      Retrieve the number of values in the list.
      +
      RuntimeDatagetValue(int position) +
      Retrieve the value at the specified position in the list.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getNumberOfValues

        +
        public int getNumberOfValues()
        +
        Retrieve the number of values in the list.
        +
        Returns:
        The number of values.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getValue

        +
        public RuntimeData getValue(int position)
        +
        Retrieve the value at the specified position in the list.
        +
        Parameters:
        position - The position of the value to be returned. + The first value is at position zero in the list.
        +
        Returns:
        The data value object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RuntimeDataDesc
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Server.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Server.html new file mode 100644 index 0000000..81af2a3 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Server.html @@ -0,0 +1,461 @@ + + + + + +Server (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class Server

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.SqlqgBaseClass
    • +
    • +
        +
      • com.ibm.db2.wrapper.Server
      • +
      +
    • +
    +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    FencedServer, UnfencedServer
    +
    +
    +
    +
    public class Server
    +extends com.ibm.db2.wrapper.SqlqgBaseClass
    +
    The Server class is the abstract base class for all server functionality. + The Server class maps to a specific data source that is supported by the wrapper. + The class maintains the following information: +
      +
    • The data source server name. +
    • A ServerInfo object that contains information for this data source server. + This information is stored in the federated server's system catalog after you issue the + DDL statements. +
    • A reference to the containing wrapper object. +
    + +

    Usage:
    + Do not use this class directly but subclass the FencedGenericServer class + and the UnfencedGenericServer class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      protected NicknamecreateNickname(java.lang.String schemaName, + java.lang.String nickname) +
      Instantiate an appropriate Nickname subclass for this data source server.
      +
      protected RemoteUsercreateRemoteUser(java.lang.String userName) +
      Instantiate an appropriate RemoteUser subclass for this data source server.
      +
      protected voiddestroy() +
      Destroys this server object and frees any resources associated with it.
      +
      RemoteUserfindRemoteUser(java.lang.String userName) +
      Search for a remote user mapping with the local name + that is specified in the federated server's system catalog.
      +
      ServerInfogetInfo() +
      Retrieve the data source server information that is stored + in the federated server's system catalog as a result of + running DDL statements.
      +
      java.lang.StringgetName() +
      Retrieve the name of the data source server.
      +
      java.lang.StringgetType() +
      Retrieve the data source server type.
      +
      java.lang.StringgetVersion() +
      Retrieve the version of the data source server.
      +
      WrappergetWrapper() +
      Retrieve the wrapper object that this data source server belongs to.
      +
      protected voidinitializeMyServer(ServerInfo serverInfo) +
      Initialize the data source server with valid federated server's system catalog information.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        createNickname

        +
        protected Nickname createNickname(java.lang.String schemaName,
        +                      java.lang.String nickname)
        +                           throws java.lang.Exception
        +
        Instantiate an appropriate Nickname subclass for this data source server. + The wrapper writer must implement this method in the wrapper-specific + data source server subclass.
        +
        Parameters:
        schemaName - The local schema name of the nickname + to be created.
        nickname - The local name of the nickname to be created.
        +
        Returns:
        The newly created Nickname instance.
        +
        Throws:
        +
        java.lang.Exception - if a new Nickname instance cannot be created.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Nickname
        +
      • +
      + + + +
        +
      • +

        createRemoteUser

        +
        protected RemoteUser createRemoteUser(java.lang.String userName)
        +                               throws java.lang.Exception
        +
        Instantiate an appropriate RemoteUser subclass for this data source server. + The wrapper can implement this method in the wrapper-specific data + source server subclass. The wrapper writer must implement this method + if a wrapper-specific subclass of the RemoteUser class is implemented.
        +
        Parameters:
        userName - The name of the remote user mapping to be created as + specified in the CREATE USER MAPPING statement.
        +
        Returns:
        The newly created RemoteUser instance.
        +
        Throws:
        +
        java.lang.Exception - if a new RemoteUser instance cannot be created.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteUser
        +
      • +
      + + + +
        +
      • +

        destroy

        +
        protected void destroy()
        +                throws java.lang.Exception
        +
        Destroys this server object and frees any resources associated with it. + The default implementation does nothing. This method is called by the + federated server before the server object is removed and gives the + wrapper a chance to free any resources allocated. + If wrapper-specific resources need to be freed, the wrapper writer can + implement this method in the wrapper-specific subclass + of UnfencedGenericServer and FencedGenericServer.
        +
        Throws:
        +
        java.lang.Exception - if the processing fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        findRemoteUser

        +
        public final RemoteUser findRemoteUser(java.lang.String userName)
        +
        Search for a remote user mapping with the local name + that is specified in the federated server's system catalog. + If no remote user mapping with that name is found, returns null.
        +
        Parameters:
        userName - The name of the remote user mapping.
        +
        Returns:
        The RemoteUser instance with the specified name or null if the + remote user mapping is not found.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteUser
        +
      • +
      + + + +
        +
      • +

        getInfo

        +
        public final ServerInfo getInfo()
        +
        Retrieve the data source server information that is stored + in the federated server's system catalog as a result of + running DDL statements.
        +
        Returns:
        The instance that contains the server information.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        ServerInfo
        +
      • +
      + + + +
        +
      • +

        getName

        +
        public final java.lang.String getName()
        +
        Retrieve the name of the data source server.
        +
        Returns:
        The name of the data source server as specified on CREATE SERVER statement.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getType

        +
        public java.lang.String getType()
        +
        Retrieve the data source server type.
        +
        Returns:
        The type of the data source server.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getVersion

        +
        public java.lang.String getVersion()
        +
        Retrieve the version of the data source server.
        +
        Returns:
        The version of the data source server.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getWrapper

        +
        public final Wrapper getWrapper()
        +
        Retrieve the wrapper object that this data source server belongs to.
        +
        Returns:
        The wrapper object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Wrapper
        +
      • +
      + + + +
        +
      • +

        initializeMyServer

        +
        protected void initializeMyServer(ServerInfo serverInfo)
        +                           throws java.lang.Exception
        +
        Initialize the data source server with valid federated server's system catalog information. + The wrapper can implement this method in the wrapper-specific data source server subclass. + The wrapper writer must implement this method if wrapper-specific data source server options + are supported.
        +
        Parameters:
        serverInfo - The ServerInfo instance that contains the data source server information.
        +
        Throws:
        +
        java.lang.Exception - if the initialization process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        WrapperInfo
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ServerInfo.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ServerInfo.html new file mode 100644 index 0000000..155172b --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/ServerInfo.html @@ -0,0 +1,833 @@ + + + + + +ServerInfo (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class ServerInfo

+
+
+ +
+
    +
  • +
    +
    +
    public final class ServerInfo
    +extends CatalogInfo
    +
    The ServerInfo class encapsulates the catalog information for a server object + from the CREATE SERVER and ALTER SERVER statements. + +

    + The ServerInfo class is one of the catalog classes for the Java API. + +

    Usage:
    + The ServerInfo class is instantiated by the DB2 federated server to contain + information from a CREATE SERVER or an ALTER SERVER statement + or to contain information from the federated server's system catalog. + This class is instantiated by the wrapper when information is added during + CREATE SERVER or ALTER SERVER statement operations.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + + +
      Constructors 
      Constructor and Description
      ServerInfo() +
      Construct a default (empty) server information object.
      +
      ServerInfo(java.lang.String name, + java.lang.String type, + java.lang.String version, + java.lang.String wrapperName) +
      Construct a fully initialized server information object.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      voidaddOption(java.lang.String optionName, + java.lang.String optionValue, + int action) +
      Add a single-value option to the options chain.
      +
      voidaddOption(java.lang.String optionName, + java.lang.String optionValue, + java.sql.Timestamp timestamp, + java.lang.String valueID, + int action) +
      Add a multi-value option to the options chain.
      +
      voiddropOption(CatalogOption option) +
      Delete an option from the options chain.
      +
      voiddropOption(CatalogOption option, + java.lang.String valueID) +
      Delete a value from a multi-value option and delete the option if no values remain.
      +
      voiddropRemoteFunction(RemoteFunctionInfo remoteFunctionInfo) +
      Drop a remote function mapping object from the chain.
      +
      java.lang.StringgetAuthID() +
      Retrieve the authorization ID for the server.
      +
      RemoteFunctionInfogetFirstRemoteFunction() +
      Retrieve the first remote function mapping object from the chain.
      +
      RemoteFunctionInfogetNextRemoteFunction(RemoteFunctionInfo remoteFunctionInfo) +
      Retrieve the next remote function mapping object from the chain.
      +
      java.lang.StringgetPassword() +
      Retrieve the password for the server.
      +
      RemoteFunctionInfogetRemoteFunction(java.lang.String functionName) +
      Retrieve the remote function mapping object with the specified name from the chain.
      +
      java.lang.StringgetServerName() +
      Retrieve the name of the server.
      +
      java.lang.StringgetType() +
      Retrieve the type of the server.
      +
      java.lang.StringgetVersion() +
      Retrieve the version string for the server.
      +
      java.lang.StringgetWrapperName() +
      Retrieve the name of the wrapper that contains the server.
      +
      voidinsertRemoteFunction(RemoteFunctionInfo remoteFunctionInfo) +
      Insert a remote function mapping object into the chain.
      +
      booleanisAuthIDValid() +
      Verify whether an authorization ID value is specified.
      +
      booleanisNameValid() +
      Verify whether the value of server name is specified.
      +
      booleanisPasswordValid() +
      Verify whether a password value is specified.
      +
      booleanisTypeValid() +
      Verify whether a type value is specified.
      +
      booleanisVersionValid() +
      Verify whether a version value is specified.
      +
      booleanisWrapperNameValid() +
      Verify if a wrapper name value is specified.
      +
      voidsetAuthID(java.lang.String authID) +
      Set the authorization ID for the server.
      +
      voidsetPassword(java.lang.String password) +
      Set the password for the server.
      +
      voidsetServerName(java.lang.String name) +
      Set the server name.
      +
      voidsetType(java.lang.String type) +
      Set the type of the server.
      +
      voidsetVersion(java.lang.String version) +
      Set the version string for the server.
      +
      voidsetWrapperName(java.lang.String name) +
      Set the name of the wrapper that contains the server.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        ServerInfo

        +
        public ServerInfo()
        +
        Construct a default (empty) server information object.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        ServerInfo

        +
        public ServerInfo(java.lang.String name,
        +          java.lang.String type,
        +          java.lang.String version,
        +          java.lang.String wrapperName)
        +
        Construct a fully initialized server information object.
        +
        Parameters:
        name - The server name.
        type - The server type.
        version - The version.
        wrapperName - The name of the wrapper that contains the server.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        addOption

        +
        public void addOption(java.lang.String optionName,
        +             java.lang.String optionValue,
        +             int action)
        +               throws WrapperException
        +
        Add a single-value option to the options chain.
        +
        Parameters:
        optionName - The name of the option.
        optionValue - The value of the option.
        action - The action flag for the option.
        +
        Throws:
        +
        WrapperException - if the option already exists in the chain or if the action is invalid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        SingleValueOption
        +
      • +
      + + + +
        +
      • +

        addOption

        +
        public void addOption(java.lang.String optionName,
        +             java.lang.String optionValue,
        +             java.sql.Timestamp timestamp,
        +             java.lang.String valueID,
        +             int action)
        +               throws WrapperException
        +
        Add a multi-value option to the options chain.
        +
        Parameters:
        optionName - The name of the option.
        optionValue - The value of the option.
        timestamp - The timestamp of the value.
        valueID - The ID of the value.
        action - The action flag for the option.
        +
        Throws:
        +
        WrapperException - if a duplicate value ID is specified or if the action is invalid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        MultiValueOption
        +
      • +
      + + + + + + + +
        +
      • +

        dropOption

        +
        public void dropOption(CatalogOption option,
        +              java.lang.String valueID)
        +                throws WrapperException
        +
        Delete a value from a multi-value option and delete the option if no values remain.
        +
        Parameters:
        option - The option.
        valueID - The ID of the value to be deleted.
        +
        Throws:
        +
        WrapperException - if the option object is null or the value ID is not found.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        CatalogOption
        +
      • +
      + + + +
        +
      • +

        dropRemoteFunction

        +
        public void dropRemoteFunction(RemoteFunctionInfo remoteFunctionInfo)
        +                        throws WrapperException
        +
        Drop a remote function mapping object from the chain.
        +
        Parameters:
        remoteFunctionInfo - The function mapping object to be dropped.
        +
        Throws:
        +
        WrapperException - if the remote function is null.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteFunctionInfo
        +
      • +
      + + + +
        +
      • +

        getAuthID

        +
        public java.lang.String getAuthID()
        +
        Retrieve the authorization ID for the server.
        +
        Returns:
        The authorization ID.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getFirstRemoteFunction

        +
        public RemoteFunctionInfo getFirstRemoteFunction()
        +
        Retrieve the first remote function mapping object from the chain.
        +
        Returns:
        The first function mapping object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteFunctionInfo
        +
      • +
      + + + +
        +
      • +

        getNextRemoteFunction

        +
        public RemoteFunctionInfo getNextRemoteFunction(RemoteFunctionInfo remoteFunctionInfo)
        +
        Retrieve the next remote function mapping object from the chain.
        +
        Parameters:
        remoteFunctionInfo - The current function mapping object.
        +
        Returns:
        The next function mapping object.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteFunctionInfo
        +
      • +
      + + + +
        +
      • +

        getPassword

        +
        public java.lang.String getPassword()
        +
        Retrieve the password for the server.
        +
        Returns:
        The password.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getRemoteFunction

        +
        public RemoteFunctionInfo getRemoteFunction(java.lang.String functionName)
        +                                     throws WrapperException
        +
        Retrieve the remote function mapping object with the specified name from the chain.
        +
        Parameters:
        functionName - The name of the function mapping.
        +
        Returns:
        The function mapping object.
        +
        Throws:
        +
        WrapperException - if the function name is null or is not found.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteFunctionInfo
        +
      • +
      + + + +
        +
      • +

        getServerName

        +
        public java.lang.String getServerName()
        +
        Retrieve the name of the server.
        +
        Returns:
        The server name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getType

        +
        public java.lang.String getType()
        +
        Retrieve the type of the server.
        +
        Returns:
        The server type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getVersion

        +
        public java.lang.String getVersion()
        +
        Retrieve the version string for the server.
        +
        Returns:
        The version.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getWrapperName

        +
        public java.lang.String getWrapperName()
        +
        Retrieve the name of the wrapper that contains the server.
        +
        Returns:
        The wrapper name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        insertRemoteFunction

        +
        public void insertRemoteFunction(RemoteFunctionInfo remoteFunctionInfo)
        +                          throws WrapperException
        +
        Insert a remote function mapping object into the chain.
        +
        Parameters:
        remoteFunctionInfo - The function mapping object to be inserted.
        +
        Throws:
        +
        WrapperException - if the remote function is null.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteFunctionInfo
        +
      • +
      + + + +
        +
      • +

        isAuthIDValid

        +
        public boolean isAuthIDValid()
        +
        Verify whether an authorization ID value is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isNameValid

        +
        public boolean isNameValid()
        +
        Verify whether the value of server name is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isPasswordValid

        +
        public boolean isPasswordValid()
        +
        Verify whether a password value is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isTypeValid

        +
        public boolean isTypeValid()
        +
        Verify whether a type value is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isVersionValid

        +
        public boolean isVersionValid()
        +
        Verify whether a version value is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isWrapperNameValid

        +
        public boolean isWrapperNameValid()
        +
        Verify if a wrapper name value is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setAuthID

        +
        public void setAuthID(java.lang.String authID)
        +
        Set the authorization ID for the server.
        +
        Parameters:
        authID - The authorization ID
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setPassword

        +
        public void setPassword(java.lang.String password)
        +
        Set the password for the server.
        +
        Parameters:
        password - The password.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setServerName

        +
        public void setServerName(java.lang.String name)
        +
        Set the server name.
        +
        Parameters:
        name - The server name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setType

        +
        public void setType(java.lang.String type)
        +
        Set the type of the server.
        +
        Parameters:
        type - The server type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setVersion

        +
        public void setVersion(java.lang.String version)
        +
        Set the version string for the server.
        +
        Parameters:
        version - The version.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setWrapperName

        +
        public void setWrapperName(java.lang.String name)
        +
        Set the name of the wrapper that contains the server.
        +
        Parameters:
        name - The name of the wrapper.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericNickname.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericNickname.html new file mode 100644 index 0000000..dcc387d --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericNickname.html @@ -0,0 +1,281 @@ + + + + + +UnfencedGenericNickname (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class UnfencedGenericNickname

+
+
+ +
+
    +
  • +
    +
    +
    public class UnfencedGenericNickname
    +extends UnfencedNickname
    +
    The UnfencedGenericNickname class represents a nonrelational nickname + in the unfenced (trusted) process space. This class is responsible for validating + information from the CREATE NICKNAME and ALTER NICKNAME statements. + +

    Usage:
    + The wrapper must implement a subclass of UnfencedGenericNickname. This class is + instantiated by the wrapper in the createNickname + method of the wrapper-specific subclass of UnfencedGenericServer.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        UnfencedGenericNickname

        +
        protected UnfencedGenericNickname(java.lang.String schema,
        +                       java.lang.String name,
        +                       UnfencedGenericServer server)
        +
        Construct a nickname with the specified schema and name for the specified data source server.
        +
        Parameters:
        schema - The local DB2 Information Integrator schema name + for the remote data set that is defined for this nickname.
        name - The local DB2 Information Integrator name for the remote + data set that is defined for this nickname.
        server - The data source server object that contains the nickname.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericRemoteUser.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericRemoteUser.html new file mode 100644 index 0000000..5b966ae --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericRemoteUser.html @@ -0,0 +1,294 @@ + + + + + +UnfencedGenericRemoteUser (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class UnfencedGenericRemoteUser

+
+
+ +
+
    +
  • +
    +
    +
    public class UnfencedGenericRemoteUser
    +extends UnfencedRemoteUser
    +
    The UnfencedGenericRemoteUser class represents a user mapping + for a nonrelational data source in the unfenced (trusted) process space. + +

    Usage:
    + This class is instantiated by the wrapper in the + createRemoteUser method of + the wrapper-specific subclass of the UnfencedGenericServer class. + The wrapper must implement a subclass of UnfencedGenericRemoteUser if + wrapper-specific user mapping options for the CREATE USER MAPPING or the + ALTER USER MAPPING statement are used.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        UnfencedGenericRemoteUser

        +
        public UnfencedGenericRemoteUser(java.lang.String localName,
        +                         UnfencedGenericServer server)
        +
        Construct a user mapping with a specified name for the specified server.
        +
        Parameters:
        localName - The local DB2 Information Integrator name for the user mapping.
        server - The server object that contains the user mapping.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        UnfencedRemoteUser, +UnfencedGenericServer
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericServer.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericServer.html new file mode 100644 index 0000000..cfc47c7 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericServer.html @@ -0,0 +1,406 @@ + + + + + +UnfencedGenericServer (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class UnfencedGenericServer

+
+
+ +
+
    +
  • +
    +
    +
    public class UnfencedGenericServer
    +extends UnfencedServer
    +
    The UnfencedGenericServer class is a subclass of the Server class and is the + abstract base class for all nonrelational data source server functionality that operates + in the unfenced (trusted) process space. This class is responsible for validation + and for performing the query planning. + +

    Usage:
    + The wrapper must implement a subclass of the UnfencedGenericServer class. + This class is instantiated by the wrapper in the createServer + method of the wrapper-specific subclass of the UnfencedGenericWrapper class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        UnfencedGenericServer

        +
        protected UnfencedGenericServer(java.lang.String name,
        +                     UnfencedGenericWrapper wrapper)
        +
        Construct a UnfencedGenericServer object for the specified wrapper with the specified name.
        +
        Parameters:
        name - The name of the data source server.
        wrapper - The wrapper object that contains the data source server.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        UnfencedGenericWrapper, +UnfencedServer
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        createRemoteUser

        +
        protected RemoteUser createRemoteUser(java.lang.String userName)
        +                               throws java.lang.Exception
        +
        Instantiate an appropriate RemoteUser subclass for this data source server. + By default, this method creates an instance of the UnfencedGenericRemoteUser class. + The wrapper can implement this method in the wrapper-specific + data source server subclass. If a wrapper-specific subclass of the + UnfencedGenericRemoteUser class is implemented, this method must also + be implemented.
        +
        +
        Overrides:
        +
        createRemoteUser in class Server
        +
        Parameters:
        userName - The name of the remote user mapping to be created and that is + specified in the CREATE USER MAPPING statement.
        +
        Returns:
        The newly created UnfencedGenericRemoteUser instance.
        +
        Throws:
        +
        java.lang.Exception - if a new RemoteUser instance cannot be created.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteUser
        +
      • +
      + + + +
        +
      • +

        createReply

        +
        public final Reply createReply(Request request)
        +                        throws java.lang.Exception
        +
        Create a new empty Reply object for the given Request. + The planRequest method + invokes this method to create the Reply objects.
        +
        Parameters:
        request - The Request object that the Reply object is created for.
        +
        Returns:
        The newly created Reply instance.
        +
        Throws:
        +
        java.lang.Exception - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Request, +Reply
        +
      • +
      + + + +
        +
      • +

        getSelectivity

        +
        public float getSelectivity(PredicateList predicateList)
        +                     throws java.lang.Exception
        +
        Calculate the selectivity of a list of predicates.
        +
        Parameters:
        predicateList - The PredicateList instance.
        +
        Returns:
        The selectivity value.
        +
        Throws:
        +
        java.lang.Exception - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        PredicateList
        +
      • +
      + + + +
        +
      • +

        planRequest

        +
        protected Reply planRequest(Request request)
        +                     throws java.lang.Exception
        +
        Analyze a proposed plan and determine what part of the plan (if any) + can be pushed down to the remote data source. + The wrapper writer implements this method in the wrapper-specific + data source server subclass.
        +
        Parameters:
        request - The Request object that contains the planned query.
        +
        Returns:
        The Reply object or the first Reply in a list of Replies. + Each Reply describes the query fragment that the wrapper is able + to push down to the remote data source.
        +
        Throws:
        +
        java.lang.Exception - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Request, +Reply
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericWrapper.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericWrapper.html new file mode 100644 index 0000000..2f2abf8 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedGenericWrapper.html @@ -0,0 +1,314 @@ + + + + + +UnfencedGenericWrapper (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class UnfencedGenericWrapper

+
+
+ +
+
    +
  • +
    +
    +
    public class UnfencedGenericWrapper
    +extends UnfencedWrapper
    +
    The UnfencedGenericWrapper class represents a nonrelational wrapper on + the unfenced (trusted) process space. + +

    Usage:
    + The wrapper must implement a subclass of UnfencedGenericWrapper. + The name of the user-specific unfenced generic wrapper subclass is specified + as the value of the UNFENCED_WRAPPER_CLASS option in the + CREATE WRAPPER statement.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        UnfencedGenericWrapper

        +
        protected UnfencedGenericWrapper()
        +
        Construct a new UnfencedGenericWrapper object.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        UnfencedWrapper
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getType

        +
        public char getType()
        +
        Retrieve the wrapper type. + A default implementation returns a value of N. N is the only valid value.
        +
        +
        Overrides:
        +
        getType in class Wrapper
        +
        Returns:
        The type of the wrapper. By default, this method returns a value of N.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Wrapper
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedNickname.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedNickname.html new file mode 100644 index 0000000..a4d5a77 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedNickname.html @@ -0,0 +1,271 @@ + + + + + +UnfencedNickname (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class UnfencedNickname

+
+
+
    +
  • java.lang.Object
  • +
  • + +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    UnfencedGenericNickname
    +
    +
    +
    +
    public class UnfencedNickname
    +extends Nickname
    +
    The UnfencedNickname class represents a nickname + in the unfenced (trusted) process space. + This class is responsible for validating + information from the CREATE NICKNAME and ALTER NICKNAME statements. + +

    Usage:
    + Do not use this class directly. Instantiating or subclassing the + UnfencedNickname class directly results in incorrect wrapper behavior. + Subclass the UnfencedGenericNickname class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        verifyMyAlterNicknameInfo

        +
        protected NicknameInfo verifyMyAlterNicknameInfo(NicknameInfo nicknameInfo)
        +                                          throws java.lang.Exception
        +
        Validate the nickname information that is specified in ALTER NICKNAME statements. + By default, this method allows only reserved options and does not return additional information. + The wrapper can implement this method in the wrapper-specific nickname subclass. + This method must be implemented if the wrapper-specific nickname or column options are + supported. Because the verifyMyAlterNicknameInfo method is part of the trusted process space, + this method cannot interact with the remote data source.
        +
        Parameters:
        nicknameInfo - An object that contains the + information that is provided in an ALTER NICKNAME statement.
        +
        Returns:
        An object with the information that is added by the nickname.
        +
        Throws:
        +
        java.lang.Exception - if the verification process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        NicknameInfo
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedRemoteUser.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedRemoteUser.html new file mode 100644 index 0000000..ce3cdd9 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedRemoteUser.html @@ -0,0 +1,308 @@ + + + + + +UnfencedRemoteUser (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class UnfencedRemoteUser

+
+
+
    +
  • java.lang.Object
  • +
  • + +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    UnfencedGenericRemoteUser
    +
    +
    +
    +
    public class UnfencedRemoteUser
    +extends RemoteUser
    +
    The UnfencedRemoteUser class represents a user mapping in the unfenced (trusted) process space. + This class is instantiated to validate the information that is specified in the + CREATE USER MAPPING and ALTER USER MAPPING statements. + +

    Usage:
    + Do not use the UnfencedRemoteUser class directly. + Instantiating or subclassing the UnfencedRemoteUser class + directly results in incorrect wrapper behavior. + Instantiate or subclass the UnfencedGenericRemoteUser + class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        verifyMyAlterUserInfo

        +
        protected UserInfo verifyMyAlterUserInfo(UserInfo userInfo)
        +                                  throws java.lang.Exception
        +
        Validate the user mapping information that is specified in the ALTER USER MAPPING statements. + By default, this method allows only reserved options and does not return additional information. + This method must be implemented if wrapper-specific user mapping options are supported.
        +
        Parameters:
        userInfo - A UserInfo object that contains the information that is provided in ALTER USER MAPPING statements.
        +
        Returns:
        A UserInfo object with the information that was added by the wrapper.
        +
        Throws:
        +
        java.lang.Exception - if the verification process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        UserInfo
        +
      • +
      + + + +
        +
      • +

        verifyMyRegisterUserInfo

        +
        protected UserInfo verifyMyRegisterUserInfo(UserInfo userInfo)
        +                                     throws java.lang.Exception
        +
        Validate the user mapping information that is specified in the CREATE USER MAPPING statements. + By default, this method allows only reserved options and does not return additional information. + This method must be implemented if wrapper-specific user mapping options are supported.
        +
        Parameters:
        userInfo - A UserInfo object that contains the information that is provided in CREATE USER MAPPING statements.
        +
        Returns:
        A UserInfo object with the information that was added by the wrapper.
        +
        Throws:
        +
        java.lang.Exception - if the verification process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        WrapperInfo
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedServer.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedServer.html new file mode 100644 index 0000000..1dd43a9 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedServer.html @@ -0,0 +1,474 @@ + + + + + +UnfencedServer (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class UnfencedServer

+
+
+
    +
  • java.lang.Object
  • +
  • + +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    UnfencedGenericServer
    +
    +
    +
    +
    public class UnfencedServer
    +extends Server
    +
    The UnfencedServer class is a subclass of the Server class and is the + abstract base class for all data source server functionality that operates in the unfenced + (trusted) process space. + This class is responsible for validation and for performing the query planning. + + +

    Usage:
    + Do not use this class directly. Instantiating or subclassing the + UnfencedServer class directly results in incorrect wrapper behavior. + Subclass the UnfencedGenericServer class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        UnfencedServer

        +
        protected UnfencedServer(java.lang.String name,
        +              int kind,
        +              UnfencedWrapper wrapper)
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        findNickname

        +
        public final Nickname findNickname(java.lang.String schema,
        +                    java.lang.String name)
        +
        Search for a nickname with the specified schema name and nickname name.
        +
        Parameters:
        schema - The schema name of the nickname to locate.
        name - The name of the nickname to locate.
        +
        Returns:
        The nickname with the specified schema and name or null if the nickname is not found.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Nickname
        +
      • +
      + + + + + + + + + + + +
        +
      • +

        isReservedFunctionOption

        +
        public static final boolean isReservedFunctionOption(java.lang.String functionOption)
        +
        Returns true if an option is a reserved function option
        +
        Parameters:
        functionOption - the option name to be checked
        Since:
        +
        IBM WebSphere Information Integrator Version 9.1
        +
      • +
      + + + + + + + +
        +
      • +

        verifyMyAlterServerInfo

        +
        protected ServerInfo verifyMyAlterServerInfo(ServerInfo serverInfo)
        +                                      throws java.lang.Exception
        +
        Validate the data source server information that is specified in ALTER SERVER statements. + By default, this method allows only reserved options and does not return additional information. + The wrapper can implement this method in the wrapper-specific unfenced server + subclass. The wrapper must implement this method if wrapper-specific data source server + options are supported.
        +
        Parameters:
        serverInfo - An object that contains the information that is provided in ALTER SERVER statements.
        +
        Returns:
        An object with the information that is added by the wrapper.
        +
        Throws:
        +
        java.lang.Exception - if the verification fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        ServerInfo
        +
      • +
      + + + +
        +
      • +

        verifyMyFunctionMappingInfo

        +
        protected void verifyMyFunctionMappingInfo(RemoteFunctionInfo remoteFunctionInfo)
        +                                    throws java.lang.Exception
        +
        Validates function mapping information that is specified in CREATE FUNCTION MAPPING statements. By default this method + does accept any function mapping. The wrapper can implement this mehod in the wrapper-specific unfenced server class if + validation of the function mapping is required. If a function mapping is not accepted the wrapper can throw an Exception.
        +
        Parameters:
        remoteFunctionInfo - A RemoteFunctionInfo instance that contains the function mapping information.
        +
        Throws:
        +
        java.lang.Exception - if the verification fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        RemoteFunctionInfo
        +
      • +
      + + + +
        +
      • +

        verifyMyRegisterServerInfo

        +
        protected ServerInfo verifyMyRegisterServerInfo(ServerInfo serverInfo)
        +                                         throws java.lang.Exception
        +
        Validate the data source server information that is specified in CREATE SERVER statements. + By default, this method allows only reserved options and does not return additional information. + The wrapper can implement this method in the wrapper-specific unfenced server subclass. + The wrapper must implement this method if wrapper-specific data source server options are supported.
        +
        Parameters:
        serverInfo - An object that contains the information that is provided in CREATE SERVER statements.
        +
        Returns:
        An object with the information that is added by the wrapper.
        +
        Throws:
        +
        java.lang.Exception - if the verification fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        ServerInfo
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedWrapper.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedWrapper.html new file mode 100644 index 0000000..e217259 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UnfencedWrapper.html @@ -0,0 +1,348 @@ + + + + + +UnfencedWrapper (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class UnfencedWrapper

+
+
+
    +
  • java.lang.Object
  • +
  • + +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    UnfencedGenericWrapper
    +
    +
    +
    +
    public class UnfencedWrapper
    +extends Wrapper
    +
    The UnfencedWrapper class that represents the wrapper on the unfenced (trusted) process space. + +

    Usage:
    + Do not use this class directly. Instantiating or subclassing the + UnfencedWrapper class directly results in incorrect wrapper behavior. + Subclass the UnfencedGenericWrapper class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getFencedWrapperClass

        +
        public final java.lang.String getFencedWrapperClass(WrapperInfo wrapperInfo)
        +                                             throws WrapperException
        +
        Retrieve the wrapper-specific FencedWrapper subclass name from the WrapperInfo object. +

        Usage:
        + This method retrieves the name of the class that needs to be loaded + for the fenced part of the wrapper. The class name is specified as the + value of the FENCED_WRAPPER_CLASS wrapper option.
        +
        Parameters:
        wrapperInfo - The WrapperInfo object which stores the wrapper catalog information.
        +
        Returns:
        The FencedWrapper subclass name or null, if no class name was specified.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        WrapperInfo
        +
      • +
      + + + +
        +
      • +

        setFencedWrapperClass

        +
        public final void setFencedWrapperClass(WrapperInfo wrapperInfo,
        +                         java.lang.String className)
        +                                 throws WrapperException
        +
        Add the wrapper-specific FencedWrapper subclass name to the WrapperInfo object. +

        Usage:
        + This method indicates which class needs to be loaded for the fenced part of the wrapper, + and passes this information to the federated server.
        +
        Parameters:
        wrapperInfo - The WrapperInfo object where the option is added.
        className - The FencedWrapper subclass name.
        +
        Throws:
        +
        WrapperException - if the method fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        WrapperInfo
        +
      • +
      + + + +
        +
      • +

        verifyMyAlterWrapperInfo

        +
        protected WrapperInfo verifyMyAlterWrapperInfo(WrapperInfo wrapperInfo)
        +                                        throws java.lang.Exception
        +
        Validate the information that is specified on an ALTER WRAPPER statement. + This method is for verification only. Therefore, do not update the internal state of the Wrapper object with + the new information that is obtained from the ALTER WRAPPER statement. If the execution of the statement is successful, + DB2 ensures that the Wrapper object is destroyed and re-created with the new information. + Default implementation allows only reserved options and does not return more information. + This method can be implemented by the wrapper in the wrapper-specific unfenced wrapper subclass + and must be implemented if wrapper-specific wrapper options are supported.
        +
        Parameters:
        wrapperInfo - A WrapperInfo object that contains the information that is provided in the ALTER WRAPPER statement.
        +
        Returns:
        A WrapperInfo object with the information that is added by the wrapper.
        +
        Throws:
        +
        java.lang.Exception - if the verification process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        WrapperInfo
        +
      • +
      + + + +
        +
      • +

        verifyMyRegisterWrapperInfo

        +
        protected WrapperInfo verifyMyRegisterWrapperInfo(WrapperInfo wrapperInfo)
        +                                           throws java.lang.Exception
        +
        Validate the information that is specified on a CREATE WRAPPER statement. + Default implementation allows only reserved options and does not return more information. + This method can be implemented by the wrapper in the wrapper-specific unfenced wrapper subclass + and must be implemented if wrapper-specific wrapper options are supported.
        +
        Parameters:
        wrapperInfo - A WrapperInfo object that contains the information that is provided in the CREATE WRAPPER statement.
        +
        Returns:
        A WrapperInfo object with the information that is added by the wrapper.
        +
        Throws:
        +
        java.lang.Exception - if the verification process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        WrapperInfo
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UserInfo.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UserInfo.html new file mode 100644 index 0000000..c2c25fa --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/UserInfo.html @@ -0,0 +1,429 @@ + + + + + +UserInfo (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class UserInfo

+
+
+ +
+
    +
  • +
    +
    +
    public final class UserInfo
    +extends CatalogInfo
    +
    The UserInfo class encapsulates the catalog information for a user mapping + from the CREATE USER MAPPING and ALTER USER MAPPING statements. + +

    + The UserInfo class is one of the catalog classes for the Java API. + +

    Usage:
    + The UserInfo class is instantiated by the DB2 federated server to contain + information from a CREATE USER MAPPING or an ALTER USER MAPPING statement + or to contain information from the federated server's system catalog. + This class is instantiated by the wrapper when information is added during + CREATE USER MAPPING or ALTER USER MAPPING statement operations.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      UserInfo() +
      Construct a default (empty) user information object.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      voidaddOption(java.lang.String optionName, + java.lang.String optionValue, + int action) +
      Add an option to the options chain.
      +
      java.lang.StringgetAuthID() +
      Retrieve the authorization ID for this user mapping.
      +
      java.lang.StringgetPassword() +
      Retrieve the password for this user mapping.
      +
      java.lang.StringgetServerName() +
      Retrieve the data source server name for this user mapping.
      +
      booleanisAuthIDValid() +
      Verify whether an authorization ID is specified.
      +
      booleanisServerNameValid() +
      Verify whether a data source server name is specified.
      +
      voidsetAuthID(java.lang.String authID) +
      Set the authorization ID for this user mapping.
      +
      voidsetServerName(java.lang.String serverName) +
      Set the data source server name for this user mapping.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        UserInfo

        +
        public UserInfo()
        +
        Construct a default (empty) user information object.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        addOption

        +
        public void addOption(java.lang.String optionName,
        +             java.lang.String optionValue,
        +             int action)
        +               throws WrapperException
        +
        Add an option to the options chain.
        +
        Parameters:
        optionName - The name of the option.
        optionValue - The value of the option.
        action - The action flag for the option. + Valid actions for the options are specified in CatalogOption class.
        +
        Throws:
        +
        WrapperException - if the option already exists in the chain or if the action is invalid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getAuthID

        +
        public java.lang.String getAuthID()
        +
        Retrieve the authorization ID for this user mapping.
        +
        Returns:
        The authorization ID.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getPassword

        +
        public java.lang.String getPassword()
        +
        Retrieve the password for this user mapping. + Obtains the value of the REMOTE_PASSWORD option specified for this user mapping, if any.
        +
        Returns:
        The password specified as the value of the REMOTE_PASSWORD option + for this user mapping or null if the option is not found.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getServerName

        +
        public java.lang.String getServerName()
        +
        Retrieve the data source server name for this user mapping.
        +
        Returns:
        The data source server name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isAuthIDValid

        +
        public boolean isAuthIDValid()
        +
        Verify whether an authorization ID is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isServerNameValid

        +
        public boolean isServerNameValid()
        +
        Verify whether a data source server name is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setAuthID

        +
        public void setAuthID(java.lang.String authID)
        +
        Set the authorization ID for this user mapping.
        +
        Parameters:
        authID - The authorization ID.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setServerName

        +
        public void setServerName(java.lang.String serverName)
        +
        Set the data source server name for this user mapping.
        +
        Parameters:
        serverName - The data source server name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Wrapper.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Wrapper.html new file mode 100644 index 0000000..aef51b3 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/Wrapper.html @@ -0,0 +1,418 @@ + + + + + +Wrapper (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class Wrapper

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.SqlqgBaseClass
    • +
    • +
        +
      • com.ibm.db2.wrapper.Wrapper
      • +
      +
    • +
    +
  • +
+
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    FencedWrapper, UnfencedWrapper
    +
    +
    +
    +
    public class Wrapper
    +extends com.ibm.db2.wrapper.SqlqgBaseClass
    +
    The Wrapper class represents the base class for a set of data sources. + This class provides library initialization services and access to the + data source servers that the wrapper supports. + + The Wrapper class maintains the following information: +
      +
    • The wrapper name. +
    • The wrapper core library name. The returned name is the name of + the native library that loaded the wrapper. +
    • A WrapperInfo object that contains all the information + that pertains to this wrapper. This information gets stored in the + federated server's system catalog as a result of issuing the DDL + statements CREATE WRAPPER or ALTER WRAPPER. +
    + +

    Usage:
    + Do not use this class directly, but subclass the + FencedGenericWrapper class and the + UnfencedGenericWrapper class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      protected ServercreateServer(java.lang.String serverName) +
      Instantiate the appropriate subclass of Server for the wrapper.
      +
      protected voiddestroy() +
      Destroys this wrapper object and frees any resources associated with it.
      +
      java.lang.StringgetCorelib() +
      Retrieve the wrapper core library name.
      +
      WrapperInfogetInfo() +
      Retrieve the wrapper information that is stored in the federated + server's system catalog as a result of running DDL statements.
      +
      java.lang.StringgetName() +
      Retrieve the wrapper name.
      +
      chargetType() +
      Retrieve the wrapper type.
      +
      intgetVersion() +
      Retrieve the version of the wrapper, which represents the version that + is currently running.
      +
      protected voidinitializeMyWrapper(WrapperInfo wrapperInfo) +
      Initialize the wrapper object state from the catalog information object.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        createServer

        +
        protected Server createServer(java.lang.String serverName)
        +                       throws java.lang.Exception
        +
        Instantiate the appropriate subclass of Server for the wrapper. + The wrapper writer must implement this method to create an instance of the + wrapper-specific Server subclass.
        +
        Parameters:
        serverName - The name of the data source server to be created, + which is specified on the CREATE SERVER statement.
        +
        Returns:
        The newly created Server instance.
        +
        Throws:
        +
        java.lang.Exception - if a new Server instance cannot be created.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Server
        +
      • +
      + + + +
        +
      • +

        destroy

        +
        protected void destroy()
        +                throws java.lang.Exception
        +
        Destroys this wrapper object and frees any resources associated with it. + The default implementation does nothing. This method is called by the + federated server before the wrapper object is removed and gives the + wrapper a chance to free any resources allocated. + If wrapper-specific resources need to be freed, the wrapper writer can + implement this method in the wrapper-specific subclass + of UnfencedGenericWrapper and FencedGenericWrapper.
        +
        Throws:
        +
        java.lang.Exception - if the processing fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getCorelib

        +
        public final java.lang.String getCorelib()
        +
        Retrieve the wrapper core library name. + The returned name is the name of the native library that loaded the wrapper.
        +
        Returns:
        The name of the library that loaded the wrapper.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getInfo

        +
        public final WrapperInfo getInfo()
        +
        Retrieve the wrapper information that is stored in the federated + server's system catalog as a result of running DDL statements.
        +
        Returns:
        The WrapperInfo object that contains the catalog information + for the wrapper.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        WrapperInfo
        +
      • +
      + + + +
        +
      • +

        getName

        +
        public final java.lang.String getName()
        +
        Retrieve the wrapper name.
        +
        Returns:
        The name of the wrapper as specified in the CREATE WRAPPER statement.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getType

        +
        public char getType()
        +
        Retrieve the wrapper type. + A default implementation returns a value of N. N is the only valid value.
        +
        Returns:
        The type of the wrapper. By default, this method returns a value of N.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getVersion

        +
        public int getVersion()
        +
        Retrieve the version of the wrapper, which represents the version that + is currently running. + This value can be compared with the version from the time that the wrapper + was registered with DB2 UDB to assure compatibility.
        +
        Returns:
        The version of the wrapper.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        initializeMyWrapper

        +
        protected void initializeMyWrapper(WrapperInfo wrapperInfo)
        +                            throws java.lang.Exception
        +
        Initialize the wrapper object state from the catalog information object. + The default implementation does nothing. + If wrapper-specific wrapper options are supported, + the wrapper writer can implement this method in the wrapper-specific subclass + of UnfencedGenericWrapper and FencedGenericWrapper.
        +
        Parameters:
        wrapperInfo - The WrapperInfo instance that contains the catalog information for the wrapper.
        +
        Throws:
        +
        java.lang.Exception - if the initialization process fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        WrapperInfo
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperException.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperException.html new file mode 100644 index 0000000..fe539fc --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperException.html @@ -0,0 +1,549 @@ + + + + + +WrapperException (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class WrapperException

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • java.lang.Throwable
    • +
    • +
        +
      • java.lang.Exception
      • +
      • +
          +
        • com.ibm.db2.wrapper.WrapperException
        • +
        +
      • +
      +
    • +
    +
  • +
+
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    java.io.Serializable
    +
    +
    +
    +
    public class WrapperException
    +extends java.lang.Exception
    +
    The WrapperException class is the Exception subclass + that is used by the Java API to report exceptions. + +

    Usage:
    + This class is instantiated by the wrapper to report an + exception that contains either a string message or an SQL error + code, caller function name and tokens that map to a DB2 + Information Integrator error message.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
    See Also:
    Serialized Form
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + + +
      Constructors 
      Constructor and Description
      WrapperException(int errorCode, + java.lang.String functionName, + java.lang.String[] tokens) +
      Construct an exception object that reports a DB2 Information Integrator error by its SQL + code, caller function name, and tokens.
      +
      WrapperException(java.lang.String message) +
      Construct a new exception object with the specified message.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      intgetAndResetErrorCode() +
      Retrieve and reset the SQL error code to report a DB2 Information Integrator error.
      +
      java.lang.StringgetAndResetFunctionName() +
      Retrieve and reset the caller function name that reports a DB2 Information Integrator error.
      +
      java.lang.String[]getAndResetTokens() +
      Retrieve and reset the substitution tokens that are used to report a DB2 Information Integrator error.
      +
      intgetErrorCode() +
      Retrieve the SQL error code to report a DB2 Information Integrator error.
      +
      java.lang.StringgetFunctionName() +
      Retrieve the caller function name that reports a DB2 Information Integrator error.
      +
      java.lang.StringgetMessage() +
      Retrieve the error message string of this exception object.
      +
      static java.lang.StringgetStackTrace(java.lang.Throwable throwable) +
      Save the stack trace of the exception into a string.
      +
      java.lang.String[]getTokens() +
      Retrieve the substitution tokens that are used to report a DB2 Information Integrator error.
      +
      voidsetErrorCode(int errorCode) +
      Set the SQL error code for reporting a DB2 Information Integrator error.
      +
      voidsetFunctionName(java.lang.String functionName) +
      Set the caller function name for reporting a DB2 Information Integrator error.
      +
      voidsetTokens(java.lang.String[] tokens) +
      Set the substitution tokens that are used for reporting a DB2 Information Integrator error.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Throwable

        +addSuppressed, fillInStackTrace, getCause, getLocalizedMessage, getStackTrace, getSuppressed, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toString
      • +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        WrapperException

        +
        public WrapperException(int errorCode,
        +                java.lang.String functionName,
        +                java.lang.String[] tokens)
        +
        Construct an exception object that reports a DB2 Information Integrator error by its SQL + code, caller function name, and tokens. + Each valid SQL code identifies an error message. The error message might contain placeholders + that are replaced with the given tokens before the message is reported to the user.
        +
        Parameters:
        errorCode - The predefined SQL code of the error that is reported.
        functionName - The name of the function that reports the error. + The string value cannot be greater than five characters. + The client program can access this string value through the + SQLERRP field of the SQLCA. The string value is in uppercase + letters with a prefix of SQL.
        tokens - The substitution tokens for the message.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        WrapperException

        +
        public WrapperException(java.lang.String message)
        +
        Construct a new exception object with the specified message. + If an error code is not specified in the exception that is thrown to + DB2 Information Integrator, an SQL0901 error is reported and the + exception message replaces the SQL0901 error message placeholder.
        +
        Parameters:
        message - The message that describes the exception.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Exception
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getAndResetErrorCode

        +
        public final int getAndResetErrorCode()
        +
        Retrieve and reset the SQL error code to report a DB2 Information Integrator error. + Each DB2 Information Integrator error is identified by a SQL error code.
        +
        Returns:
        The predefined SQL code of the error that is reported.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getAndResetFunctionName

        +
        public final java.lang.String getAndResetFunctionName()
        +
        Retrieve and reset the caller function name that reports a DB2 Information Integrator error. + The caller function name is reported with a DB2 Information Integrator error in the SQLERRP field of the SQLCA + structure.
        +
        Returns:
        The name of the function that reports the error. + The string value cannot be greater than five characters. + The client program can access this string value through the + SQLERRP field of the SQLCA. The string value is in uppercase + letters with a prefix of SQL.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getAndResetTokens

        +
        public final java.lang.String[] getAndResetTokens()
        +
        Retrieve and reset the substitution tokens that are used to report a DB2 Information Integrator error. + The substitution tokens replace the placeholders in the DB2 Information Integrator error message.
        +
        Returns:
        The substitution tokens that are used in the error message + when a DB2 Information Integrator error is reported.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getErrorCode

        +
        public final int getErrorCode()
        +
        Retrieve the SQL error code to report a DB2 Information Integrator error. + Each DB2 Information Integrator error is identified by a SQL error code.
        +
        Returns:
        The predefined SQL code of the error that is reported.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getFunctionName

        +
        public final java.lang.String getFunctionName()
        +
        Retrieve the caller function name that reports a DB2 Information Integrator error. + The caller function name is reported with a DB2 Information Integrator error in the SQLERRP field of the SQLCA + structure.
        +
        Returns:
        The name of the function that reports the error. + The string value cannot be greater than five characters. + The client program can access this string value through the + SQLERRP field of the SQLCA. The string value is in uppercase + letters with a prefix of SQL.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getMessage

        +
        public java.lang.String getMessage()
        +
        Retrieve the error message string of this exception object.
        +
        +
        Overrides:
        +
        getMessage in class java.lang.Throwable
        +
        Returns:
        If the WraperException object was created with + an error message string, the error message + string of this WrapperException object. If the + WraperException object was created with an SQL + error code, a string showing the SQL error code, + the caller function name and the set of tokens.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getStackTrace

        +
        public static java.lang.String getStackTrace(java.lang.Throwable throwable)
        +
        Save the stack trace of the exception into a string.
        +
        Parameters:
        throwable - The throwable object that the stack trace is extracted from.
        +
        Returns:
        The string that contains the stack trace information.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Throwable
        +
      • +
      + + + +
        +
      • +

        getTokens

        +
        public final java.lang.String[] getTokens()
        +
        Retrieve the substitution tokens that are used to report a DB2 Information Integrator error. + The substitution tokens replace the placeholders in the DB2 Information Integrator error message.
        +
        Returns:
        The substitution tokens that are used in the error message + when a DB2 Information Integrator error is reported.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setErrorCode

        +
        public final void setErrorCode(int errorCode)
        +
        Set the SQL error code for reporting a DB2 Information Integrator error. + Each DB2 Information Integrator error is identified by a SQL error code.
        +
        Parameters:
        errorCode - The predefined SQL code of the error that is reported.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setFunctionName

        +
        public final void setFunctionName(java.lang.String functionName)
        +
        Set the caller function name for reporting a DB2 Information Integrator error. + The caller function name is reported with a DB2 Information Integrator error in the SQLERRP field of the SQLCA + structure.
        +
        Parameters:
        functionName - The name of the function that reports the error. + The string value cannot be greater than five characters. + The client program can access this string value through the + SQLERRP field of the SQLCA. The string value is in uppercase + letters with a prefix of SQL.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setTokens

        +
        public final void setTokens(java.lang.String[] tokens)
        +
        Set the substitution tokens that are used for reporting a DB2 Information Integrator error. + The substitution tokens replace the placeholders in the DB2 Information Integrator error message.
        +
        Parameters:
        tokens - The substitution tokens that are used in the error message + when a DB2 Information Integrator error is reported.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperInfo.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperInfo.html new file mode 100644 index 0000000..452b14b --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperInfo.html @@ -0,0 +1,499 @@ + + + + + +WrapperInfo (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class WrapperInfo

+
+
+ +
+
    +
  • +
    +
    +
    public final class WrapperInfo
    +extends CatalogInfo
    +
    The WrapperInfo class encapsulates the catalog information for a wrapper object + from the CREATE WRAPPER and ALTER WRAPPER statements. + +

    + The WrapperInfo class is one of the catalog classes for the Java API. + +

    Usage:
    + The WrapperInfo class is instantiated by the DB2 federated server to contain + information from a CREATE WRAPPER or an ALTER WRAPPER statement or to contain + information from the federated server's system catalog. + This class is instantiated by the wrapper when information is added during + CREATE WRAPPER or ALTER WRAPPER statement operations.

    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      WrapperInfo() +
      Construct a new default (empty) wrapper information object.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      voidaddOption(java.lang.String optionName, + java.lang.String optionValue, + int action) +
      Add an option to the options chain.
      +
      java.lang.StringgetCorelib() +
      Retrieve the core library name.
      +
      chargetType() +
      Retrieve the wrapper type.
      +
      intgetVersion() +
      Retrieve the wrapper version.
      +
      java.lang.StringgetWrapperName() +
      Retrieve the wrapper name.
      +
      booleanisCorelibValid() +
      Verify whether a core library is specified.
      +
      booleanisNameValid() +
      Verify whether a name is specified.
      +
      booleanisTypeValid() +
      Verify whether a type is specified.
      +
      booleanisVersionValid() +
      Verify whether a version is specified.
      +
      voidsetType(char type) +
      Set the wrapper type.
      +
      voidsetVersion(int version) +
      Set the wrapper version.
      +
      voidsetWrapperName(java.lang.String name) +
      Set the wrapper name.
      +
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        WrapperInfo

        +
        public WrapperInfo()
        +
        Construct a new default (empty) wrapper information object.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        addOption

        +
        public void addOption(java.lang.String optionName,
        +             java.lang.String optionValue,
        +             int action)
        +               throws WrapperException
        +
        Add an option to the options chain.
        +
        Parameters:
        optionName - The name of the option.
        optionValue - The value of the option.
        action - The action flag for the option. + Valid actions for the options are specified in CatalogOption class.
        +
        Throws:
        +
        WrapperException - if the option already exists in the chain or if the action is invalid.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getCorelib

        +
        public java.lang.String getCorelib()
        +
        Retrieve the core library name.
        +
        Returns:
        The core library name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getType

        +
        public char getType()
        +
        Retrieve the wrapper type.
        +
        Returns:
        The type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getVersion

        +
        public int getVersion()
        +
        Retrieve the wrapper version.
        +
        Returns:
        The version.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getWrapperName

        +
        public java.lang.String getWrapperName()
        +
        Retrieve the wrapper name.
        +
        Returns:
        The wrapper name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isCorelibValid

        +
        public boolean isCorelibValid()
        +
        Verify whether a core library is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isNameValid

        +
        public boolean isNameValid()
        +
        Verify whether a name is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isTypeValid

        +
        public boolean isTypeValid()
        +
        Verify whether a type is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        isVersionValid

        +
        public boolean isVersionValid()
        +
        Verify whether a version is specified.
        +
        Returns:
        true if a value is specified, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setType

        +
        public void setType(char type)
        +
        Set the wrapper type.
        +
        Parameters:
        type - The type.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setVersion

        +
        public void setVersion(int version)
        +
        Set the wrapper version.
        +
        Parameters:
        version - The version.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        setWrapperName

        +
        public void setWrapperName(java.lang.String name)
        +
        Set the wrapper name.
        +
        Parameters:
        name - The wrapper name.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperUtilities.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperUtilities.html new file mode 100644 index 0000000..786b2cc --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/WrapperUtilities.html @@ -0,0 +1,647 @@ + + + + + +WrapperUtilities (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + + +
+
com.ibm.db2.wrapper
+

Class WrapperUtilities

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.ibm.db2.wrapper.WrapperUtilities
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public final class WrapperUtilities
    +extends java.lang.Object
    +
    The WrapperUtilities class is a container for several static utility functions. + Do not instantiate or subclass the WrapperUtilities class.
    +
    Since:
    +
    IBM DB2 Information Integrator Version 8.2
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Summary

      + + + + + + + + + + +
      Fields 
      Modifier and TypeField and Description
      static intEXT_WRAPPERS_TRACE_COMPONENT +
      Trace component ID for wrappers not provided by IBM.
      +
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Methods 
      Modifier and TypeMethod and Description
      static intgetAppCBStatus() +
      Retrieve the status of the application control block.
      +
      static java.lang.StringgetAuthid() +
      Retrieve the authorization ID for the current database.
      +
      static intgetCodepage() +
      Retrieve the current database code page.
      +
      static java.lang.StringgetDB2InstallPath() +
      Retrieve the DB2 Universal Database installation path.
      +
      static java.lang.StringgetDB2InstancePath() +
      Retrieve the DB2 Universal Database instance path.
      +
      static intgetDB2Release() +
      Get the DB2 Universal Database release and the fix pack that + this wrapper is currently running under.
      +
      static intgetDoubleByteDBCodepage() +
      Retrieve the double-byte database code page.
      +
      static intgetIsolationLevel() +
      Retrieve the isolation level for the current database.
      +
      static intgetSingleByteDBCodepage() +
      Retrieve the single-byte database code page.
      +
      static voidreportWarning(int sqlCode, + java.lang.String funcName, + java.lang.String[] tokens) +
      Report a warning to the DB2 Information Integrator user.
      +
      static booleantraceEnabled() +
      Verify whether the DB2 Information Integrator tracing is enabled.
      +
      static voidtraceError(int funcID, + java.lang.String funcName, + int probe, + java.lang.String errorData) +
      Trace an error message.
      +
      static voidtraceException(int funcID, + java.lang.String funcName, + int probe, + java.lang.Throwable exception) +
      Trace an exception and its call stack.
      +
      static voidtraceFunctionData(int funcID, + java.lang.String funcName, + int probe, + java.lang.String data) +
      Trace function data using a single data trace parameter.
      +
      static voidtraceFunctionData(int funcID, + java.lang.String funcName, + int probe, + java.lang.String data1, + java.lang.String data2) +
      Trace function data using two data trace parameters.
      +
      static voidtraceFunctionData(int funcID, + java.lang.String funcName, + int probe, + java.lang.String data1, + java.lang.String data2, + java.lang.String data3) +
      Trace function data using three data trace parameters.
      +
      static voidtraceFunctionEntry(int funcID, + java.lang.String funcName) +
      Trace a function entry.
      +
      static voidtraceFunctionReturnCode(int funcID, + java.lang.String funcName, + int returnCode) +
      Trace a function return code.
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Field Detail

      + + + +
        +
      • +

        EXT_WRAPPERS_TRACE_COMPONENT

        +
        public static final int EXT_WRAPPERS_TRACE_COMPONENT
        +
        Trace component ID for wrappers not provided by IBM.
        +
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
        See Also:
        Constant Field Values
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getAppCBStatus

        +
        public static final int getAppCBStatus()
        +
        Retrieve the status of the application control block.
        +
        Returns:
        The application control block status.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getAuthid

        +
        public static final java.lang.String getAuthid()
        +                                        throws WrapperException
        +
        Retrieve the authorization ID for the current database.
        +
        Returns:
        The database authorization ID.
        +
        Throws:
        +
        WrapperException - if the operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getCodepage

        +
        public static final int getCodepage()
        +
        Retrieve the current database code page.
        +
        Returns:
        The code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDB2InstallPath

        +
        public static final java.lang.String getDB2InstallPath()
        +                                                throws WrapperException
        +
        Retrieve the DB2 Universal Database installation path.
        +
        Returns:
        The DB2 Universal Database installation path.
        +
        Throws:
        +
        WrapperException - if the operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDB2InstancePath

        +
        public static final java.lang.String getDB2InstancePath()
        +                                                 throws WrapperException
        +
        Retrieve the DB2 Universal Database instance path.
        +
        Returns:
        The DB2 Universal Database instance path.
        +
        Throws:
        +
        WrapperException - if the operation fails.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDB2Release

        +
        public static final int getDB2Release()
        +
        Get the DB2 Universal Database release and the fix pack that + this wrapper is currently running under. + This value will be updated at each DB2 Universal Database fix pack.
        +
        Returns:
        The DB2 Universal Database release.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getDoubleByteDBCodepage

        +
        public static final int getDoubleByteDBCodepage()
        +
        Retrieve the double-byte database code page.
        +
        Returns:
        The double-byte code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getIsolationLevel

        +
        public static final int getIsolationLevel()
        +
        Retrieve the isolation level for the current database.
        +
        Returns:
        The isolation level.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        getSingleByteDBCodepage

        +
        public static final int getSingleByteDBCodepage()
        +
        Retrieve the single-byte database code page.
        +
        Returns:
        The single-byte code page.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        reportWarning

        +
        public static final void reportWarning(int sqlCode,
        +                 java.lang.String funcName,
        +                 java.lang.String[] tokens)
        +                                throws WrapperException
        +
        Report a warning to the DB2 Information Integrator user. + A DB2 Information Integrator warning is composed of a SQL code, the caller function name and a set of tokens. + Each valid SQL code identifies a warning message. The message might contain placeholders + which are replaced with the given tokens before the message is reported to the user.
        +
        Parameters:
        sqlCode - The predefined SQL code of the warning that is reported.
        funcName - The name of the function that reports the warning. + The string cannot be greater than five characters. + The client program can access this string value through the + SQLERRP field of the SQLCA. The string value is in uppercase + letters with a prefix of SQL.
        tokens - The substitution tokens for the message.
        +
        Throws:
        +
        WrapperException - if the operation fails.
        +
      • +
      + + + +
        +
      • +

        traceEnabled

        +
        public static final boolean traceEnabled()
        +
        Verify whether the DB2 Information Integrator tracing is enabled.
        +
        Returns:
        true if tracing is enabled, false otherwise.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        traceError

        +
        public static final void traceError(int funcID,
        +              java.lang.String funcName,
        +              int probe,
        +              java.lang.String errorData)
        +
        Trace an error message.
        +
        Parameters:
        funcID - The trace ID of the caller function.
        funcName - The name of the caller function.
        probe - The probe ID.
        errorData - The error data to trace.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        traceException

        +
        public static final void traceException(int funcID,
        +                  java.lang.String funcName,
        +                  int probe,
        +                  java.lang.Throwable exception)
        +
        Trace an exception and its call stack.
        +
        Parameters:
        funcID - The trace ID of the caller function.
        funcName - The name of the caller function.
        probe - The probe ID.
        exception - The exception to trace.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        traceFunctionData

        +
        public static final void traceFunctionData(int funcID,
        +                     java.lang.String funcName,
        +                     int probe,
        +                     java.lang.String data)
        +
        Trace function data using a single data trace parameter.
        +
        Parameters:
        funcID - The trace ID of the caller function.
        funcName - The name of the caller function.
        probe - The probe ID.
        data - The data to trace.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        traceFunctionData

        +
        public static final void traceFunctionData(int funcID,
        +                     java.lang.String funcName,
        +                     int probe,
        +                     java.lang.String data1,
        +                     java.lang.String data2)
        +
        Trace function data using two data trace parameters.
        +
        Parameters:
        funcID - The trace ID of the caller function.
        funcName - The name of the caller function.
        probe - The probe ID.
        data1 - The first data to trace.
        data2 - The second data to trace.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        traceFunctionData

        +
        public static final void traceFunctionData(int funcID,
        +                     java.lang.String funcName,
        +                     int probe,
        +                     java.lang.String data1,
        +                     java.lang.String data2,
        +                     java.lang.String data3)
        +
        Trace function data using three data trace parameters.
        +
        Parameters:
        funcID - The trace ID of the caller function.
        funcName - The name of the caller function.
        probe - The probe ID.
        data1 - The first data to trace.
        data2 - The second data to trace.
        data3 - The third data to trace.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        traceFunctionEntry

        +
        public static final void traceFunctionEntry(int funcID,
        +                      java.lang.String funcName)
        +
        Trace a function entry.
        +
        Parameters:
        funcID - The trace ID of the caller function.
        funcName - The name of the caller function.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      + + + +
        +
      • +

        traceFunctionReturnCode

        +
        public static final void traceFunctionReturnCode(int funcID,
        +                           java.lang.String funcName,
        +                           int returnCode)
        +
        Trace a function return code.
        +
        Parameters:
        funcID - The trace ID of the caller function.
        funcName - The name of the caller function.
        returnCode - The return code.
        Since:
        +
        IBM DB2 Information Integrator Version 8.2
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-frame.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-frame.html new file mode 100644 index 0000000..fcbe442 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-frame.html @@ -0,0 +1,72 @@ + + + + + +com.ibm.db2.wrapper (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + +

com.ibm.db2.wrapper

+
+ + + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-summary.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-summary.html new file mode 100644 index 0000000..1214f2e --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-summary.html @@ -0,0 +1,490 @@ + + + + + +com.ibm.db2.wrapper (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +
+

Package com.ibm.db2.wrapper

+
+
Provides classes that you can use when you develop a wrapper for a data source and, after, you can use the data source in a federated database system.
+
+

See: Description

+
+
+
    +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Class Summary 
    ClassDescription
    CatalogInfo +
    CatalogInfo represents the base class for all the catalog classes + and provides the infrastructure to manage a list of options.
    +
    CatalogOption +
    The CatalogOption class represents the base class for options of the catalog objects.
    +
    ColumnInfo +
    The ColumnInfo class encapsulates catalog information for a column of a nickname.
    +
    Data +
    The Data class is the base class that manages cell values, + constants, and parameter values.
    +
    DefaultRemoteFunction +
    The DefaultRemoteFunction class represents a simple remote function + mapping.
    +
    FencedGenericNickname +
    The FencedGenericNickname class represents a nonrelational nickname + in the fenced (untrusted) process space.
    +
    FencedGenericRemoteUser +
    The FencedGenericRemoteUser class represents a user mapping + for a nonrelational data source in the fenced (untrusted) process space.
    +
    FencedGenericServer +
    The FencedGenericServer class is a subclass of the Server class and is the + abstract base class for all nonrelational data source server functionality + that operates in the fenced (untrusted) process space.
    +
    FencedGenericWrapper +
    The FencedGenericWrapper class represents a nonrelational wrapper on the + fenced (untrusted) process space.
    +
    FencedNickname +
    The FencedNickname class represents a nickname + in the fenced (untrusted) process space.
    +
    FencedRemoteUser +
    The FencedRemoteUser class represents a user mapping in the fenced (untrusted) process space.
    +
    FencedServer +
    The FencedServer class is a subclass of the Server class and is the + abstract base class for all server functionality that operates in the fenced + (untrusted) process space.
    +
    FencedWrapper +
    The FencedWrapper class represents the wrapper on the fenced (untrusted) process space.
    +
    IndexInfo 
    Nickname +
    The Nickname class models collections of data that a data source server manages.
    +
    NicknameInfo +
    The NicknameInfo class encapsulates the catalog information for a nickname + object including column definitions from the CREATE NICKNAME and ALTER + NICKNAME statements.
    +
    ParsedQueryFragment +
    The ParsedQueryFragment class represents the base class of both the + Request class and Reply class.
    +
    PredicateList +
    The PredicateList describes two lists of predicates to + estimate the selectivity factor.
    +
    Quantifier +
    The Quantifier class encapsulates information for a quantifier of a Request.
    +
    RemoteConnection +
    The RemoteConnection class represents a connection (session) with a data source server.
    +
    RemoteFunctionInfo +
    The RemoteFunctionInfo class represents the catalog information + and describes the function mapping with a remote source.
    +
    RemoteOperation +
    The RemoteOperation class serves as the base class for classes that represent + various remote operations.
    +
    RemotePassthru +
    The RemotePassthru class represents a pass-through session on a remote data source.
    +
    RemoteQuery +
    The RemoteQuery class represents SELECT statement operations on a remote data source.
    +
    RemoteUser +
    The RemoteUser class represents the authorizations to use on a data source server.
    +
    Reply +
    The Reply class represents the portion of a request that the wrapper processes.
    +
    Request +
    The Request class encapsulates a query fragment that is analyzed and processed by the wrapper.
    +
    RequestConstant +
    The RequestConstant class describes a constant that is used in a query + expression during query planning.
    +
    RequestExp +
    The RequestExp class represents a node in an expression tree.
    +
    RequestExpType +
    The RequestExpType class describes the type of node in an expression tree.
    +
    RFuncParmInfo +
    The RFuncParmInfo class represents the information that describes a function parameter + in a function mapping.
    +
    RuntimeData +
    The RuntimeData class represents each column value that is transferred between the + federated server and a wrapper.
    +
    RuntimeDataDesc +
    The RuntimeDataDesc class is created by the federated server to describe each column + value that is transferred between the federated server and a wrapper.
    +
    RuntimeDataDescList +
    The RuntimeDataDescList class encapsulates a list of RuntimeDataDesc + objects that describe a row in a result set or a list of input parameters.
    +
    RuntimeDataList +
    The RuntimeDataList class encapsulates a list of RuntimeData objects + that represent either a row in a result set or a list of input parameters.
    +
    Server +
    The Server class is the abstract base class for all server functionality.
    +
    ServerInfo +
    The ServerInfo class encapsulates the catalog information for a server object + from the CREATE SERVER and ALTER SERVER statements.
    +
    UnfencedGenericNickname +
    The UnfencedGenericNickname class represents a nonrelational nickname + in the unfenced (trusted) process space.
    +
    UnfencedGenericRemoteUser +
    The UnfencedGenericRemoteUser class represents a user mapping + for a nonrelational data source in the unfenced (trusted) process space.
    +
    UnfencedGenericServer +
    The UnfencedGenericServer class is a subclass of the Server class and is the + abstract base class for all nonrelational data source server functionality that operates + in the unfenced (trusted) process space.
    +
    UnfencedGenericWrapper +
    The UnfencedGenericWrapper class represents a nonrelational wrapper on + the unfenced (trusted) process space.
    +
    UnfencedNickname +
    The UnfencedNickname class represents a nickname + in the unfenced (trusted) process space.
    +
    UnfencedRemoteUser +
    The UnfencedRemoteUser class represents a user mapping in the unfenced (trusted) process space.
    +
    UnfencedServer +
    The UnfencedServer class is a subclass of the Server class and is the + abstract base class for all data source server functionality that operates in the unfenced + (trusted) process space.
    +
    UnfencedWrapper +
    The UnfencedWrapper class that represents the wrapper on the unfenced (trusted) process space.
    +
    UserInfo +
    The UserInfo class encapsulates the catalog information for a user mapping + from the CREATE USER MAPPING and ALTER USER MAPPING statements.
    +
    Wrapper +
    The Wrapper class represents the base class for a set of data sources.
    +
    WrapperInfo +
    The WrapperInfo class encapsulates the catalog information for a wrapper object + from the CREATE WRAPPER and ALTER WRAPPER statements.
    +
    WrapperUtilities +
    The WrapperUtilities class is a container for several static utility functions.
    +
    +
  • +
  • + + + + + + + + + + + + +
    Exception Summary 
    ExceptionDescription
    WrapperException +
    The WrapperException class is the Exception subclass + that is used by the Java API to report exceptions.
    +
    +
  • +
+ + + +

Package com.ibm.db2.wrapper Description

+
Provides classes that you can use when you develop a wrapper for a data source and, after, you can use the data source in a federated database system. +
This documentation is intended for DBAs and wrapper developers who use Java APIs with DB2 Information Integrator that is offered by IBM. +

Related Documentation

+ +For more information, please see: +
    +
  • IBM DB2 Information Integrator Developer?s Guide that shows you how to use IBM DB2 Information Integrator solutions to help you integrate data through unified views and data placement. +
+
+ +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-tree.html b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-tree.html new file mode 100644 index 0000000..f774381 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/com/ibm/db2/wrapper/package-tree.html @@ -0,0 +1,234 @@ + + + + + +com.ibm.db2.wrapper Class Hierarchy (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +
+

Hierarchy For Package com.ibm.db2.wrapper

+
+
+

Class Hierarchy

+ +
+ +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/constant-values.html b/wrappers/wrapper_sdk_java/javadoc/constant-values.html new file mode 100644 index 0000000..97b98fd --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/constant-values.html @@ -0,0 +1,836 @@ + + + + + +Constant Field Values (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +
+

Constant Field Values

+

Contents

+ +
+
+ + +

com.ibm.*

+
    +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    com.ibm.db2.wrapper.CatalogOption 
    Modifier and TypeConstant FieldValue
    + +public static final intADD1
    + +public static final intDROP3
    + +public static final intNONE0
    + +public static final intSET2
    +
  • +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    com.ibm.db2.wrapper.Data 
    Modifier and TypeConstant FieldValue
    + +public static final shortBLOB404
    + +public static final shortCHAR452
    + +public static final shortCLOB408
    + +public static final shortDATE384
    + +public static final shortDECIMAL484
    + +public static final shortDOUBLE480
    + +public static final shortFLOAT483
    + +public static final shortINT496
    + +public static final shortLONG492
    + +public static final shortNONE-1
    + +public static final shortSHORT500
    + +public static final shortSQL_NO_NULLS0
    + +public static final shortSQL_NULLABLE1
    + +public static final shortSQL_NULLABLE_UNKNOWN2
    + +public static final shortTIME388
    + +public static final shortTIMESTAMP392
    + +public static final shortVARCHAR448
    +
  • +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    com.ibm.db2.wrapper.com.ibm.db2.wrapper.Messages 
    Modifier and TypeConstant FieldValue
    + +public static final java.lang.StringemsgAddOrderEntryDir"addOrderEntry: invalid direction"
    + +public static final java.lang.StringemsgDuplicateNickname"Duplicate nickname"
    + +public static final java.lang.StringemsgDuplicateUser"Duplicate user mapping"
    + +public static final java.lang.StringemsgDuplicateValueID"Duplicate value id"
    + +public static final java.lang.StringemsgFetchLobNotSupported"RemoteQuery.fetchLob is not supported"
    + +public static final java.lang.StringemsgGetOrderEntryIndex"getOrderEntry: index out of bonds"
    + +public static final java.lang.StringemsgGetSelectivityCall"getSelectivity cannot be called by the wrapper"
    + +public static final java.lang.StringemsgInvalidDataType"Invalid data type"
    + +public static final java.lang.StringemsgInvalidDataTypeInFetchLob"Invalid/unknown data type in RemoteQuery.fetchLob"
    + +public static final java.lang.StringemsgInvalidOptionAction"Invalid action for the option"
    + +public static final java.lang.StringemsgLobDataReadyFromFetchLob"lobDataReady should have been called from fetchLob"
    + +public static final java.lang.StringemsgMethodNotImplemented"Method not implemented"
    + +public static final java.lang.StringemsgMethodNotSupported"Method not supported"
    + +public static final java.lang.StringemsgMultiValueOptionMismatch"Multi value option expected"
    + +public static final java.lang.StringemsgNullColumnInfo"The ColumnInfo object is null"
    + +public static final java.lang.StringemsgNullIndexInfo"The IndexInfo object is null"
    + +public static final java.lang.StringemsgNullLocalTypeInfo"The LocalTypeInfo object is null"
    + +public static final java.lang.StringemsgNullLocalTypeName"The LocalType name is null"
    + +public static final java.lang.StringemsgNullLocalTypeNotFound"The LocalType could not be found"
    + +public static final java.lang.StringemsgNullOption"Null option"
    + +public static final java.lang.StringemsgNullOptionName"Null option name"
    + +public static final java.lang.StringemsgNullOptionValue"The OptionValue object is null"
    + +public static final java.lang.StringemsgNullPredicateList"The predicate list is null"
    + +public static final java.lang.StringemsgNullRemoteFunctionInfo"The RemoteFunctionInfo object is null"
    + +public static final java.lang.StringemsgNullRemoteFunctionName"The RemoteFunction name is null"
    + +public static final java.lang.StringemsgNullRemoteFunctionNotFound"The RemoteFunction could not be found"
    + +public static final java.lang.StringemsgNullRFuncParmInfo"The RFuncParmInfo object is null"
    + +public static final java.lang.StringemsgRequestExpGetColumnName"Invalid call to RequestExp.getColumnName"
    + +public static final java.lang.StringemsgRequestExpGetFirstChild"Invalid call to RequestExp.getFirstChild"
    + +public static final java.lang.StringemsgRequestExpGetNumberOfChildren"Invalid call to RequestExp.getNumberOfChildren"
    + +public static final java.lang.StringemsgRequestExpGetQuantifier"Invalid call to RequestExp.getQuantifier"
    + +public static final java.lang.StringemsgRequestExpGetSignature"Invalid call to RequestExp.getSignature"
    + +public static final java.lang.StringemsgRequestExpGetToken"Invalid call to RequestExp.getToken"
    + +public static final java.lang.StringemsgRequestExpGetValue"Invalid call to RequestExp.getValue"
    + +public static final java.lang.StringemsgUnknownDataType"Data type not specified or not supported"
    + +public static final java.lang.StringemsgUnknownValueID"Value id not found"
    +
  • +
  • + + + + + + + + + + + + + + + + + + + +
    com.ibm.db2.wrapper.RemoteConnection 
    Modifier and TypeConstant FieldValue
    + +public static final intNO_PHASE_KIND0
    + +public static final intONE_PHASE_KIND1
    +
  • +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    com.ibm.db2.wrapper.RemoteQuery 
    Modifier and TypeConstant FieldValue
    + +public static final byteCLOSE_EOA2
    + +public static final byteCLOSE_EOS0
    + +public static final byteEOF3
    + +public static final intFETCH_LOB_LAST1
    + +public static final intFETCH_LOB_MORE0
    + +public static final intFETCH_LOB_NEXT0
    + +public static final intFETCH_NON_LOB_NEXT1
    + +public static final intFETCH_ROW_DONE2
    + +public static final byteOPEN2
    + +public static final intOPEN_LOB_INIT2
    + +public static final intOPEN_LOB_LAST16
    + +public static final intOPEN_LOB_MORE8
    + +public static final intOPEN_LOB_NEW4
    + +public static final intOPEN_NON_LOB_NEXT1
    + +public static final intOPEN_ROW_DONE32
    + +public static final byteREADY1
    + +public static final byteUNREADY0
    +
  • +
  • + + + + + + + + + + + + + + + + + + + +
    com.ibm.db2.wrapper.RemoteUser 
    Modifier and TypeConstant FieldValue
    + +public static final java.lang.StringREMOTE_AUTHID_OPTION"REMOTE_AUTHID"
    + +public static final java.lang.StringREMOTE_PASSWORD_OPTION"REMOTE_PASSWORD"
    +
  • +
  • + + + + + + + + + + + + + + + + + + + +
    com.ibm.db2.wrapper.Reply 
    Modifier and TypeConstant FieldValue
    + +public static final intASC0
    + +public static final intDESC1
    +
  • +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    com.ibm.db2.wrapper.RequestExp 
    Modifier and TypeConstant FieldValue
    + +public static final intBADKIND0
    + +public static final intCOLUMN1
    + +public static final intCONSTANT3
    + +public static final intOPERATOR4
    + +public static final intUNBOUND2
    +
  • +
  • + + + + + + + + + + + + + + +
    com.ibm.db2.wrapper.WrapperUtilities 
    Modifier and TypeConstant FieldValue
    + +public static final intEXT_WRAPPERS_TRACE_COMPONENT135
    +
  • +
+
+ +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/help-doc.html b/wrappers/wrapper_sdk_java/javadoc/help-doc.html new file mode 100644 index 0000000..bdf4207 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/help-doc.html @@ -0,0 +1,209 @@ + + + + + +API Help (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +
+

How This API Document Is Organized

+
This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
+
+
+
    +
  • +

    Package

    +

    Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain six categories:

    +
      +
    • Interfaces (italic)
    • +
    • Classes
    • +
    • Enums
    • +
    • Exceptions
    • +
    • Errors
    • +
    • Annotation Types
    • +
    +
  • +
  • +

    Class/Interface

    +

    Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:

    +
      +
    • Class inheritance diagram
    • +
    • Direct Subclasses
    • +
    • All Known Subinterfaces
    • +
    • All Known Implementing Classes
    • +
    • Class/interface declaration
    • +
    • Class/interface description
    • +
    +
      +
    • Nested Class Summary
    • +
    • Field Summary
    • +
    • Constructor Summary
    • +
    • Method Summary
    • +
    +
      +
    • Field Detail
    • +
    • Constructor Detail
    • +
    • Method Detail
    • +
    +

    Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.

    +
  • +
  • +

    Annotation Type

    +

    Each annotation type has its own separate page with the following sections:

    +
      +
    • Annotation Type declaration
    • +
    • Annotation Type description
    • +
    • Required Element Summary
    • +
    • Optional Element Summary
    • +
    • Element Detail
    • +
    +
  • +
  • +

    Enum

    +

    Each enum has its own separate page with the following sections:

    +
      +
    • Enum declaration
    • +
    • Enum description
    • +
    • Enum Constant Summary
    • +
    • Enum Constant Detail
    • +
    +
  • +
  • +

    Tree (Class Hierarchy)

    +

    There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with java.lang.Object. The interfaces do not inherit from java.lang.Object.

    +
      +
    • When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.
    • +
    • When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.
    • +
    +
  • +
  • +

    Index

    +

    The Index contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.

    +
  • +
  • +

    Prev/Next

    +

    These links take you to the next or previous class, interface, package, or related page.

    +
  • +
  • +

    Frames/No Frames

    +

    These links show and hide the HTML frames. All pages are available with or without frames.

    +
  • +
  • +

    All Classes

    +

    The All Classes link shows all classes and interfaces except non-static nested types.

    +
  • +
  • +

    Serialized Form

    +

    Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.

    +
  • +
  • +

    Constant Field Values

    +

    The Constant Field Values page lists the static final fields and their values.

    +
  • +
+This help file applies to API documentation generated using the standard doclet.
+ +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/index-all.html b/wrappers/wrapper_sdk_java/javadoc/index-all.html new file mode 100644 index 0000000..f839d34 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/index-all.html @@ -0,0 +1,2904 @@ + + + + + +Index (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +
A B C D E F G I L M N O P Q R S T U V W  + + +

A

+
+
ADD - Static variable in class com.ibm.db2.wrapper.CatalogOption
+
+
Action constant; indicates that the option is added to the catalog.
+
+
addColumn(String, int) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Add a column specification to the index specification
+
+
addHeadExp(RequestExp) - Method in class com.ibm.db2.wrapper.Reply
+
+
Add a head expression in the SELECT clause of the query.
+
+
addOption(String, String, int, String, String) - Method in class com.ibm.db2.wrapper.CatalogInfo
+
+
Add an option to the options chain.
+
+
addOption(String, String, int) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Add an option to the options chain.
+
+
addOption(String, String, int) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Add an option to the options chain.
+
+
addOption(String, String, int) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Add an option to the options chain.
+
+
addOption(String, String, int) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Add an option to the options chain.
+
+
addOption(String, String, int) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Add a single-value option to the options chain.
+
+
addOption(String, String, Timestamp, String, int) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Add a multi-value option to the options chain.
+
+
addOption(String, String, int) - Method in class com.ibm.db2.wrapper.UserInfo
+
+
Add an option to the options chain.
+
+
addOption(String, String, int) - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Add an option to the options chain.
+
+
addOrderEntry(int, int) - Method in class com.ibm.db2.wrapper.Reply
+
+
Add an order entry in the ORDER BY clause of the query.
+
+
addPredicate(RequestExp) - Method in class com.ibm.db2.wrapper.Reply
+
+
Add a predicate in the WHERE clause of the query.
+
+
addQuantifier(Quantifier) - Method in class com.ibm.db2.wrapper.Reply
+
+
Add a quantifier in the FROM clause of the query.
+
+
ASC - Static variable in class com.ibm.db2.wrapper.Reply
+
+
Constant that indicates the ascending ordering for an order entry.
+
+
+ + + +

B

+
+
BADKIND - Static variable in class com.ibm.db2.wrapper.RequestExp
+
+
Constant to indicate that the expression is unknown.
+
+
BLOB - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a BLOB data type.
+
+
+ + + +

C

+
+
cardinality() - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve the cardinality of the result when running + the query fragment that is represented by the reply.
+
+
CatalogInfo - Class in com.ibm.db2.wrapper
+
+
CatalogInfo represents the base class for all the catalog classes + and provides the infrastructure to manage a list of options.
+
+
CatalogOption - Class in com.ibm.db2.wrapper
+
+
The CatalogOption class represents the base class for options of the catalog objects.
+
+
CHAR - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a CHAR data type.
+
+
checkFriendlyDivBy0() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Determine if the reason for a null indication is a divide by zero error.
+
+
checkFriendlyException() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Determine if the reason for a null indication is a numeric exception.
+
+
clearNullIndicator() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Clear the null indicator for the data value.
+
+
CLOB - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a CLOB data type.
+
+
close() - Method in class com.ibm.db2.wrapper.RemotePassthru
+
+
Close a pass-through cursor and allows the data source to clean up after pass-through statement processing.
+
+
close(short) - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Allow the wrapper and the data source to clean up after query statement processing.
+
+
CLOSE_EOA - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
Status constant used in close method to indicate + that the wrapper is to finish necessary cleanup and + that the RemoteQuery object is destroyed after the close + method returns.
+
+
CLOSE_EOS - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
Status constant used in close method + to indicate that the wrapper must leave the RemoteQuery in + a state so that the reopen or + reopenInputLob methods can be invoked.
+
+
COLUMN - Static variable in class com.ibm.db2.wrapper.RequestExp
+
+
Constant to indicate that the expression is a column.
+
+
ColumnInfo - Class in com.ibm.db2.wrapper
+
+
The ColumnInfo class encapsulates catalog information for a column of a nickname.
+
+
ColumnInfo() - Constructor for class com.ibm.db2.wrapper.ColumnInfo
+
+
Construct a default (empty) column information object.
+
+
com.ibm.db2.wrapper - package com.ibm.db2.wrapper
+
+
Provides classes that you can use when you develop a wrapper for a data source and, after, you can use the data source in a federated database system.
+
+
commit() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Indicate the successful completion of a transaction and + that the remote data source then commits the transaction.
+
+
connect() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Invoke the code to connect to the data source server.
+
+
CONSTANT - Static variable in class com.ibm.db2.wrapper.RequestExp
+
+
Constant to indicate that the expression is a constant.
+
+
createNickname(String, String) - Method in class com.ibm.db2.wrapper.Server
+
+
Instantiate an appropriate Nickname subclass for this data source server.
+
+
createRemoteConnection(FencedRemoteUser, int, long) - Method in class com.ibm.db2.wrapper.FencedServer
+
+
Create a new connection for the specified user mapping and of the specified kind.
+
+
createRemotePassthru(long) - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Create a RemotePassthru object to run pass-through statements.
+
+
createRemoteQuery(long) - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Create a RemoteQuery object to run SQL statements.
+
+
createRemoteUser(String) - Method in class com.ibm.db2.wrapper.FencedGenericServer
+
+
Instantiate an appropriate RemoteUser subclass for this data source server.
+
+
createRemoteUser(String) - Method in class com.ibm.db2.wrapper.Server
+
+
Instantiate an appropriate RemoteUser subclass for this data source server.
+
+
createRemoteUser(String) - Method in class com.ibm.db2.wrapper.UnfencedGenericServer
+
+
Instantiate an appropriate RemoteUser subclass for this data source server.
+
+
createReply(Request) - Method in class com.ibm.db2.wrapper.UnfencedGenericServer
+
+
Create a new empty Reply object for the given Request.
+
+
createServer(String) - Method in class com.ibm.db2.wrapper.Wrapper
+
+
Instantiate the appropriate subclass of Server for the wrapper.
+
+
+ + + +

D

+
+
Data - Class in com.ibm.db2.wrapper
+
+
The Data class is the base class that manages cell values, + constants, and parameter values.
+
+
DATE - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a DATE data type.
+
+
DECIMAL - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a DECIMAL or NUMERIC data type.
+
+
DefaultRemoteFunction - Class in com.ibm.db2.wrapper
+
+
The DefaultRemoteFunction class represents a simple remote function + mapping.
+
+
DefaultRemoteFunction() - Constructor for class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Class constructor
+
+
DefaultRemoteFunction(String, String, short, double, double, double, double, short, double, double) - Constructor for class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Construct an instance with the specified values.
+
+
DESC - Static variable in class com.ibm.db2.wrapper.Reply
+
+
Constant that indicates the descending ordering for an order entry.
+
+
describe(RuntimeDataDescList) - Method in class com.ibm.db2.wrapper.RemotePassthru
+
+
Describe the result set of a statement that is processed by a pass-through operation.
+
+
destroy() - Method in class com.ibm.db2.wrapper.Nickname
+
+
Destroys this nickname object and frees any resources associated with it.
+
+
destroy() - Method in class com.ibm.db2.wrapper.RemoteUser
+
+
Destroys this user mapping object and frees any resources associated with it.
+
+
destroy() - Method in class com.ibm.db2.wrapper.Server
+
+
Destroys this server object and frees any resources associated with it.
+
+
destroy() - Method in class com.ibm.db2.wrapper.Wrapper
+
+
Destroys this wrapper object and frees any resources associated with it.
+
+
disconnect() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Invoke the code to disconnect from the data source server.
+
+
DOUBLE - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a DOUBLE data type.
+
+
DROP - Static variable in class com.ibm.db2.wrapper.CatalogOption
+
+
Action constant; indicates that the option is dropped from the catalog.
+
+
dropOption(CatalogOption) - Method in class com.ibm.db2.wrapper.CatalogInfo
+
+
Delete an option from the options chain.
+
+
dropOption(CatalogOption) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Delete an option from the options chain.
+
+
dropOption(CatalogOption, String) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Delete a value from a multi-value option and delete the option if no values remain.
+
+
dropRemoteFunction(RemoteFunctionInfo) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Drop a remote function mapping object from the chain.
+
+
+ + + +

E

+
+
EOF - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object finished fetching all the rows of + the result set.
+
+
execute() - Method in class com.ibm.db2.wrapper.RemotePassthru
+
+
Execute a statement that returns a code and does not return a result set by a pass-through operation.
+
+
EXT_WRAPPERS_TRACE_COMPONENT - Static variable in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Trace component ID for wrappers not provided by IBM.
+
+
+ + + +

F

+
+
FencedGenericNickname - Class in com.ibm.db2.wrapper
+
+
The FencedGenericNickname class represents a nonrelational nickname + in the fenced (untrusted) process space.
+
+
FencedGenericNickname(String, String, FencedGenericServer) - Constructor for class com.ibm.db2.wrapper.FencedGenericNickname
+
+
Construct a nickname with the specified schema and name for the specified data source server.
+
+
FencedGenericRemoteUser - Class in com.ibm.db2.wrapper
+
+
The FencedGenericRemoteUser class represents a user mapping + for a nonrelational data source in the fenced (untrusted) process space.
+
+
FencedGenericRemoteUser(String, FencedGenericServer) - Constructor for class com.ibm.db2.wrapper.FencedGenericRemoteUser
+
+
Construct a user mapping with a specified name for the specified data source server.
+
+
FencedGenericServer - Class in com.ibm.db2.wrapper
+
+
The FencedGenericServer class is a subclass of the Server class and is the + abstract base class for all nonrelational data source server functionality + that operates in the fenced (untrusted) process space.
+
+
FencedGenericServer(String, FencedGenericWrapper) - Constructor for class com.ibm.db2.wrapper.FencedGenericServer
+
+
Construct a FencedGenericServer object for the specified wrapper with the specified name.
+
+
FencedGenericWrapper - Class in com.ibm.db2.wrapper
+
+
The FencedGenericWrapper class represents a nonrelational wrapper on the + fenced (untrusted) process space.
+
+
FencedGenericWrapper() - Constructor for class com.ibm.db2.wrapper.FencedGenericWrapper
+
+
Construct a new FencedGenricWrapper object.
+
+
FencedNickname - Class in com.ibm.db2.wrapper
+
+
The FencedNickname class represents a nickname + in the fenced (untrusted) process space.
+
+
FencedRemoteUser - Class in com.ibm.db2.wrapper
+
+
The FencedRemoteUser class represents a user mapping in the fenced (untrusted) process space.
+
+
FencedServer - Class in com.ibm.db2.wrapper
+
+
The FencedServer class is a subclass of the Server class and is the + abstract base class for all server functionality that operates in the fenced + (untrusted) process space.
+
+
FencedWrapper - Class in com.ibm.db2.wrapper
+
+
The FencedWrapper class represents the wrapper on the fenced (untrusted) process space.
+
+
fetch() - Method in class com.ibm.db2.wrapper.RemotePassthru
+
+
Fetch a row from a pass-through cursor by copying a single-result row into the output data buffer.
+
+
fetch() - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Fetch (retrieve) a single-result row from the remote data source into the output data buffers.
+
+
FETCH_LOB_LAST - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB fetching status constant: indicate that the last buffer of data for + the current LOB column has been fetched.
+
+
FETCH_LOB_MORE - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB fetching status constant: indicate that more data is available for the current LOB column.
+
+
FETCH_LOB_NEXT - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB fetching status constant: indicate that another LOB column is to be fetched next.
+
+
FETCH_NON_LOB_NEXT - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB fetching status constant: indicate that a non-LOB column is to be fetched next.
+
+
FETCH_ROW_DONE - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB fetching status constant: indicate that all the values for the current row have + been fetched.
+
+
fetchLob(int, int) - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Retrieve a large object (LOB) fragment from the remote source.
+
+
findConnection() - Method in class com.ibm.db2.wrapper.FencedServer
+
+
Retrieve the current active connection for the data source server.
+
+
findNickname(String, String) - Method in class com.ibm.db2.wrapper.UnfencedServer
+
+
Search for a nickname with the specified schema name and nickname name.
+
+
findRemoteUser(String) - Method in class com.ibm.db2.wrapper.Server
+
+
Search for a remote user mapping with the local name + that is specified in the federated server's system catalog.
+
+
firstTupleCost() - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve the cost that is required to obtain the first result tuple for + the query fragment that is represented by the reply.
+
+
FLOAT - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a FLOAT data type.
+
+
+ + + +

G

+
+
getAction() - Method in class com.ibm.db2.wrapper.CatalogOption
+
+
Retrieve the action for the option.
+
+
getAction() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the action value.
+
+
getActualLength() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the actual length for the data value.
+
+
getAndResetErrorCode() - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Retrieve and reset the SQL error code to report a DB2 Information Integrator error.
+
+
getAndResetFunctionName() - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Retrieve and reset the caller function name that reports a DB2 Information Integrator error.
+
+
getAndResetTokens() - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Retrieve and reset the substitution tokens that are used to report a DB2 Information Integrator error.
+
+
getAppCBStatus() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Retrieve the status of the application control block.
+
+
getAppliedPredicate(int) - Method in class com.ibm.db2.wrapper.PredicateList
+
+
Retrieve a RequestExp object that describes the applied predicate at the specified position.
+
+
getAuthID() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Retrieve the authorization ID for the server.
+
+
getAuthID() - Method in class com.ibm.db2.wrapper.UserInfo
+
+
Retrieve the authorization ID for this user mapping.
+
+
getAuthid() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Retrieve the authorization ID for the current database.
+
+
getAvgLength() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the average length of the column.
+
+
getBigDecimal() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a BigDecimal instance.
+
+
getByte() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a byte value.
+
+
getCard() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the cardinality value.
+
+
getClusterRatio() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the cluster ratio.
+
+
getCodepage() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Retrieve the code page for the connection.
+
+
getCodepage() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Retrieve the code page for character data types.
+
+
getCodepage() - Method in class com.ibm.db2.wrapper.RequestExpType
+
+
Retrieve the code page for character data types.
+
+
getCodepage() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the code page for character data type values.
+
+
getCodepage() - Method in class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Retrieve the code page for character data type values.
+
+
getCodepage() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Retrieve the current database code page.
+
+
getCodepage1() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the single-byte character set (SBCS) code page for the column.
+
+
getCodepage2() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the double-byte character set (DBCS) code page for the column.
+
+
getColCard() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the cardinality of the column.
+
+
getColCount() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the number of columns in the index.
+
+
getColDir(int) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the sort direction of an indexed column.
+
+
getColName(int) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the name of an indexed column.
+
+
getColNames() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the names of the indexed columns.
+
+
getColumn(String) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the column with the specified name.
+
+
getColumnID() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the column ID.
+
+
getColumnName() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the name of the column.
+
+
getColumnName() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Column expression node: Retrieve the column name.
+
+
getColumnType() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the type of the column.
+
+
getColumnWithRemoteColumnName(String) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the column with the specified remote column name.
+
+
getConnection() - Method in class com.ibm.db2.wrapper.RemoteOperation
+
+
Retrieve the connection for the remote operation.
+
+
getCorelib() - Method in class com.ibm.db2.wrapper.Wrapper
+
+
Retrieve the wrapper core library name.
+
+
getCorelib() - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Retrieve the core library name.
+
+
getData() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a byte array.
+
+
getData() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Retrieve the data buffer in an internal format.
+
+
getData() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the data value in an internal format.
+
+
getDataIndex() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the column number for the data value.
+
+
getDataType() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data type.
+
+
getDataType() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Retrieve the data type.
+
+
getDataType() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Retrieve the object that describes the data type of the expression.
+
+
getDataType() - Method in class com.ibm.db2.wrapper.RequestExpType
+
+
Retrieve the data type.
+
+
getDataType() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the data type.
+
+
getDataType() - Method in class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Retrieve the type of data.
+
+
getDate() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a Date instance.
+
+
getDB2InstallPath() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Retrieve the DB2 Universal Database installation path.
+
+
getDB2InstancePath() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Retrieve the DB2 Universal Database instance path.
+
+
getDB2Release() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Get the DB2 Universal Database release and the fix pack that + this wrapper is currently running under.
+
+
getDefault() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the default value for the column.
+
+
getDefiner() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the definer.
+
+
getDefinerType() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the definer type.
+
+
getDistinct() - Method in class com.ibm.db2.wrapper.ParsedQueryFragment
+
+
Test the DISTINCT indicator (SELECT DISTINCT clause).
+
+
getDouble() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a double value.
+
+
getDoubleByteDBCodepage() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Retrieve the double-byte database code page.
+
+
getErrorCode() - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Retrieve the SQL error code to report a DB2 Information Integrator error.
+
+
getExecDesc() - Method in class com.ibm.db2.wrapper.RemoteOperation
+
+
Retrieve the execution descriptor for the remote operation.
+
+
getExecDesc() - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve the execution descriptor object.
+
+
getFencedWrapperClass(WrapperInfo) - Method in class com.ibm.db2.wrapper.UnfencedWrapper
+
+
Retrieve the wrapper-specific FencedWrapper subclass name from the WrapperInfo object.
+
+
getFirstChild() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Operator expression node: Retrieve the first child of the operator.
+
+
getFirstColumn() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the first column information object.
+
+
getFirstKeycard() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the first key cardinality.
+
+
getFirstLocalParm() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the first local parameter.
+
+
getFirstOption() - Method in class com.ibm.db2.wrapper.CatalogInfo
+
+
Retrieve the first option from the chain.
+
+
getFirstRemoteFunction() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Retrieve the first remote function mapping object from the chain.
+
+
getFirstRemoteParm() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the first remote parameter.
+
+
getFloat() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a float value.
+
+
getForBitData() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the FOR BIT DATA flag for the column.
+
+
getForBitData() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the FOR BIT DATA flag.
+
+
getForBitData() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Retrieve the FOR BIT DATA flag.
+
+
getForBitData() - Method in class com.ibm.db2.wrapper.RequestExpType
+
+
Retrieve the FOR BIT DATA flag which indicates whether the data is in binary format.
+
+
getForBitData() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the FOR BIT DATA flag which indicates binary data.
+
+
getForBitData() - Method in class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Retrieve the FOR BIT DATA flag which indicates binary data.
+
+
getFPages() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the fpages statistics for the nickname.
+
+
getFullKeycard() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the full key cardinality.
+
+
getFuncID() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the local function ID.
+
+
getFunctionName() - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Retrieve the caller function name that reports a DB2 Information Integrator error.
+
+
getHandle() - Method in class com.ibm.db2.wrapper.Quantifier
+
+
Retrieve the handle of the quantifier.
+
+
getHandle() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Retrieve the expression handle.
+
+
getHeadExp(int) - Method in class com.ibm.db2.wrapper.ParsedQueryFragment
+
+
Retrieve the expression at the specified position in the SELECT clause.
+
+
getHigh2Key() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the second-highest value for the column.
+
+
getIndexName() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the name of the index.
+
+
getInfo() - Method in class com.ibm.db2.wrapper.Nickname
+
+
Retrieve the nickname information stored in the federated server's system + catalog as a result of running DDL statements.
+
+
getInfo() - Method in class com.ibm.db2.wrapper.RemoteUser
+
+
Retrieve the user mapping information that is stored in the federated server's system + catalog as a result of running DDL statements.
+
+
getInfo() - Method in class com.ibm.db2.wrapper.Server
+
+
Retrieve the data source server information that is stored + in the federated server's system catalog as a result of + running DDL statements.
+
+
getInfo() - Method in class com.ibm.db2.wrapper.Wrapper
+
+
Retrieve the wrapper information that is stored in the federated + server's system catalog as a result of running DDL statements.
+
+
getInitialInsts() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Returns the number of machine instructions executed the first time the function is executed
+
+
getInitialIos() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Returns the number of I/O operations the first time the function is executed
+
+
getInputData() - Method in class com.ibm.db2.wrapper.RemoteOperation
+
+
Retrieve the list of input values for the remote operation.
+
+
getInstsPerArgByte() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Returns the number of machine instructions per byte of argument for one invocation of the function.
+
+
getInstsPerInvoke() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Returns the number of machine instructions per invocation of the function.
+
+
getInt() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as an integer (int) value.
+
+
getInvariant() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the invariant value.
+
+
getIosPerArgByte() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Returns the number of I/O operations per byte of argument for one invocation of the function.
+
+
getIosPerInvoke() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Returns the number of I/O operations per invocation of the function.
+
+
getIsolationLevel() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Retrieve the isolation level for the current database.
+
+
getKind() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Retrieve the connection type.
+
+
getKind() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Retrieve the kind of the expression.
+
+
getLocalName() - Method in class com.ibm.db2.wrapper.Nickname
+
+
Retrieve the local name for this nickname.
+
+
getLocalName() - Method in class com.ibm.db2.wrapper.RemoteUser
+
+
Retrieve the name of the user on the local database.
+
+
getLocalSchema() - Method in class com.ibm.db2.wrapper.Nickname
+
+
Retrieve the local schema for this nickname.
+
+
getLocalSchema() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the local schema name.
+
+
getLocalSignature() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Returns the local signature of the function
+
+
getLocalSignature() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the signature.
+
+
getLong() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a long value.
+
+
getLow2Key() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the second-lowest value for the column.
+
+
getMappingName() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the mapping name.
+
+
getMaximumLength() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Retrieve the maximum length for the data type.
+
+
getMaximumLength() - Method in class com.ibm.db2.wrapper.RequestExpType
+
+
Retrieve the maximum length for the data type.
+
+
getMaximumLength() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the maximum length of the data.
+
+
getMaximumLength() - Method in class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Retrieve the maximum length of the data.
+
+
getMessage() - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Retrieve the error message string of this exception object.
+
+
getName() - Method in class com.ibm.db2.wrapper.CatalogOption
+
+
Retrieve the name of the option.
+
+
getName() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Retrieve the name of the constant, if defined.
+
+
getName() - Method in class com.ibm.db2.wrapper.RequestExpType
+
+
Retrieve the name of the data type.
+
+
getName() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the name for the data.
+
+
getName() - Method in class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Retrieve the name for the data.
+
+
getName() - Method in class com.ibm.db2.wrapper.Server
+
+
Retrieve the name of the data source server.
+
+
getName() - Method in class com.ibm.db2.wrapper.Wrapper
+
+
Retrieve the wrapper name.
+
+
getNewColumnName() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the new column name that is specified in an ALTER COLUMN + statement that includes an ALTER (or SET) COLUMN clause to rename the column.
+
+
getNextChild() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Retrieve the sibling of the expression.
+
+
getNextColumn() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the next column in the columns chain.
+
+
getNextColumn(ColumnInfo) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the next column information object.
+
+
getNextFunction() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the next function in the chain.
+
+
getNextIndex() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the next index in the chain.
+
+
getNextOption(CatalogOption) - Method in class com.ibm.db2.wrapper.CatalogInfo
+
+
Retrieve the next option from the chain.
+
+
getNextOption() - Method in class com.ibm.db2.wrapper.CatalogOption
+
+
Retrieve the next option in the chain that this option belongs to.
+
+
getNextRemoteFunction(RemoteFunctionInfo) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Retrieve the next remote function mapping object from the chain.
+
+
getNextRFuncParm() - Method in class com.ibm.db2.wrapper.RFuncParmInfo
+
+
Retrieve the next function parameter in the chain.
+
+
getNickname() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the name of the nickname.
+
+
getNickname(int) - Method in class com.ibm.db2.wrapper.ParsedQueryFragment
+
+
Retrieve the nickname that corresponds to the specified position in the FROM clause.
+
+
getNickname() - Method in class com.ibm.db2.wrapper.Quantifier
+
+
Retrieve the nickname that is referenced by this quantifier.
+
+
getNLeaf() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the number of leafs.
+
+
getNLevels() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the number of levels.
+
+
getNPages() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the npages statistics for the nickname.
+
+
getNullIndicator() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Retrieve the null indicator.
+
+
getNullIndicator() - Method in class com.ibm.db2.wrapper.RequestExpType
+
+
Retrieve the null indicator value.
+
+
getNullIndicator() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the null indicator for the data value.
+
+
getNullIndicator() - Method in class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Retrieve the null indicator for the data value.
+
+
getNulls() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the nulls-allowed flag.
+
+
getNumberOfAppliedPredicates() - Method in class com.ibm.db2.wrapper.PredicateList
+
+
Retrieve the number of applied predicates.
+
+
getNumberOfChildren() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Operator expression node: Retrieve the number of children for the operator.
+
+
getNumberOfHeadExp() - Method in class com.ibm.db2.wrapper.ParsedQueryFragment
+
+
Retrieve the number of elements in the SELECT clause.
+
+
getNumberOfOrderEntries() - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve the number of order entries.
+
+
getNumberOfPredicates() - Method in class com.ibm.db2.wrapper.ParsedQueryFragment
+
+
Retrieve the number of elements (predicates) in the WHERE clause.
+
+
getNumberOfPredicates() - Method in class com.ibm.db2.wrapper.PredicateList
+
+
Retrieve the number of predicates in the list.
+
+
getNumberOfQuantifiers() - Method in class com.ibm.db2.wrapper.ParsedQueryFragment
+
+
Retrieve the number of elements (quantifiers) in the FROM clause.
+
+
getNumberOfValues() - Method in class com.ibm.db2.wrapper.RuntimeDataDescList
+
+
Retrieve the number of data descriptors in the list.
+
+
getNumberOfValues() - Method in class com.ibm.db2.wrapper.RuntimeDataList
+
+
Retrieve the number of values in the list.
+
+
getNumColumns() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the number of columns.
+
+
getNumNulls() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the number of null values in the column, -1 if statistics are not collected.
+
+
getObject() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as an Object instance.
+
+
getOption(String) - Method in class com.ibm.db2.wrapper.CatalogInfo
+
+
Retrieve the option object for the specified option name.
+
+
getOrderEntry(int) - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve the order entry at the specified position in the ORDER by clause.
+
+
getOrdinal() - Method in class com.ibm.db2.wrapper.RFuncParmInfo
+
+
Retrieve the ordinal value.
+
+
getOrgLength() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the maximum length (in bytes) for the column.
+
+
getOrgScale() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the numeric scale of the column.
+
+
getOutputData() - Method in class com.ibm.db2.wrapper.RemoteOperation
+
+
Retrieve the list of output data buffers for the remote operation.
+
+
getOverflow() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the overflow statistics for the nickname.
+
+
getParameterOrder() - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve a list of parameter handles.
+
+
getParent() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Retrieve the parent node of the expression.
+
+
getPassword() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Retrieve the password for the server.
+
+
getPassword() - Method in class com.ibm.db2.wrapper.UserInfo
+
+
Retrieve the password for this user mapping.
+
+
getPercentArgByte() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Retruns the precentage of arguments bytes
+
+
getPrecision() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Retrieve the precision for numeric data types.
+
+
getPrecision() - Method in class com.ibm.db2.wrapper.RequestExpType
+
+
Retrieve the precision for numeric data types.
+
+
getPrecision() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the precision for numeric data type values.
+
+
getPrecision() - Method in class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Retrieve the precision for numeric data type values.
+
+
getPredicate(int) - Method in class com.ibm.db2.wrapper.ParsedQueryFragment
+
+
Retrieve the predicate expression at the specified position in the WHERE clause.
+
+
getPredicate(int) - Method in class com.ibm.db2.wrapper.PredicateList
+
+
Retrieve a RequestExp object that describes the predicate at the specified position.
+
+
getPrevFunction() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the previous function in the chain.
+
+
getPrevIndex() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the previous index in the chain.
+
+
getPrevOption() - Method in class com.ibm.db2.wrapper.CatalogOption
+
+
Retrieve the previous option in the chain that this option belongs to.
+
+
getQuantifier(int) - Method in class com.ibm.db2.wrapper.ParsedQueryFragment
+
+
Retrieve the quantifier at the specified position in the FROM clause.
+
+
getQuantifier() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Column expression node: Retrieve the quantifier to which this column belongs.
+
+
getQuantifierByHandle(int) - Method in class com.ibm.db2.wrapper.ParsedQueryFragment
+
+
Retrieve the quantifier with the specified handle in the FROM clause.
+
+
getRemoteConnectionKind() - Method in class com.ibm.db2.wrapper.FencedServer
+
+
Retrieve the type of connection that this data source server supports as indicated by the + RemoteConnection.NO_PHASE_KIND or RemoteConnection.ONE_PHASE_KIND + constants.
+
+
getRemoteFunction(String) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Retrieve the remote function mapping object with the specified name from the chain.
+
+
getRemoteFunctionName() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Returns the remote name of the function
+
+
getRemoteLength() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the remote length of the data value.
+
+
getRemotePrecision() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the remote precision for the numeric data type values.
+
+
getRemoteResultType() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Returns the result type of the function.
+
+
getRemoteScale() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the remote scale of the numeric data type values.
+
+
getRemoteType() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the remote type of the data value.
+
+
getRemoteType() - Method in class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Retrieve the remote type of the data.
+
+
getRowStatus() - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Retrieve the current row status.
+
+
getScale() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Retrieve the scale for numeric data types.
+
+
getScale() - Method in class com.ibm.db2.wrapper.RequestExpType
+
+
Retrieve the scale for numeric data types.
+
+
getScale() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Retrieve the scale for numeric data type values.
+
+
getScale() - Method in class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Retrieve the scale for numeric data type values.
+
+
getSchema() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the local schema name of the nickname.
+
+
getSelectivity(PredicateList) - Method in class com.ibm.db2.wrapper.UnfencedGenericServer
+
+
Calculate the selectivity of a list of predicates.
+
+
getServer() - Method in class com.ibm.db2.wrapper.Nickname
+
+
Retrieve the data source server that contains this nickname.
+
+
getServer() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Retrieve the data source server object that contains this connection.
+
+
getServer() - Method in class com.ibm.db2.wrapper.RemoteOperation
+
+
Retrieve the data source server that owns the remote operation.
+
+
getServer() - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve the data source server that this reply belongs to.
+
+
getServerName() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Retrieve the server name of the nickname.
+
+
getServerName() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Retrieve the name of the server.
+
+
getServerName() - Method in class com.ibm.db2.wrapper.UserInfo
+
+
Retrieve the data source server name for this user mapping.
+
+
getShort() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a short value.
+
+
getSignature() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Operator expression node: Retrieve the signature of the operator.
+
+
getSingleByteDBCodepage() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Retrieve the single-byte database code page.
+
+
getSpecificName() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the specific name.
+
+
getSQLStatement() - Method in class com.ibm.db2.wrapper.RemotePassthru
+
+
Retrieve the SQL statement for the remote pass-through operation.
+
+
getStackTrace(Throwable) - Static method in exception com.ibm.db2.wrapper.WrapperException
+
+
Save the stack trace of the exception into a string.
+
+
getStatus() - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Retrieve the status of the query.
+
+
getString() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a string.
+
+
getTime() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a Time instance.
+
+
getTimestamp() - Method in class com.ibm.db2.wrapper.Data
+
+
Retrieve the data as a Timestamp instance.
+
+
getTimestamp() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Retrieve the timestamp value.
+
+
getToken() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Operator expression node: Retrieve the token of the operator.
+
+
getTokens() - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Retrieve the substitution tokens that are used to report a DB2 Information Integrator error.
+
+
getType() - Method in class com.ibm.db2.wrapper.FencedGenericWrapper
+
+
Retrieve the wrapper type.
+
+
getType() - Method in class com.ibm.db2.wrapper.Server
+
+
Retrieve the data source server type.
+
+
getType() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Retrieve the type of the server.
+
+
getType() - Method in class com.ibm.db2.wrapper.UnfencedGenericWrapper
+
+
Retrieve the wrapper type.
+
+
getType() - Method in class com.ibm.db2.wrapper.Wrapper
+
+
Retrieve the wrapper type.
+
+
getType() - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Retrieve the wrapper type.
+
+
getTypeName() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the name of the local column type.
+
+
getTypeSchema() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Retrieve the schema of the local column type.
+
+
getUniqueColCount() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the number of unique columns in the index.
+
+
getUniqueRule() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Retrieve the flag to indicate whether or not the index has a unique rule.
+
+
getUser() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Retrieve the user mapping to authenticate this connection.
+
+
getValue() - Method in class com.ibm.db2.wrapper.CatalogOption
+
+
Retrieve the option value.
+
+
getValue() - Method in class com.ibm.db2.wrapper.RequestExp
+
+
Constant expression node: Retrieve the RequestConstant object that represents + the value of the constant.
+
+
getValue(int) - Method in class com.ibm.db2.wrapper.RuntimeDataDescList
+
+
Retrieve the data descriptor at the specified position in the list.
+
+
getValue(int) - Method in class com.ibm.db2.wrapper.RuntimeDataList
+
+
Retrieve the value at the specified position in the list.
+
+
getVersion() - Method in class com.ibm.db2.wrapper.Server
+
+
Retrieve the version of the data source server.
+
+
getVersion() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Retrieve the version string for the server.
+
+
getVersion() - Method in class com.ibm.db2.wrapper.Wrapper
+
+
Retrieve the version of the wrapper, which represents the version that + is currently running.
+
+
getVersion() - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Retrieve the wrapper version.
+
+
getWrapper() - Method in class com.ibm.db2.wrapper.Nickname
+
+
Retrieve the wrapper instance that this nickname belongs to.
+
+
getWrapper() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Retrieve the wrapper object.
+
+
getWrapper() - Method in class com.ibm.db2.wrapper.RemoteOperation
+
+
Get the wrapper object.
+
+
getWrapper() - Method in class com.ibm.db2.wrapper.RemoteUser
+
+
Retrieve the wrapper instance that this user mapping belongs to.
+
+
getWrapper() - Method in class com.ibm.db2.wrapper.Server
+
+
Retrieve the wrapper object that this data source server belongs to.
+
+
getWrapperName() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Retrieve the name of the wrapper that contains the server.
+
+
getWrapperName() - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Retrieve the wrapper name.
+
+
+ + + +

I

+
+
IndexInfo - Class in com.ibm.db2.wrapper
+
 
+
IndexInfo() - Constructor for class com.ibm.db2.wrapper.IndexInfo
+
+
Class constructor.
+
+
initializeMyNickname(NicknameInfo) - Method in class com.ibm.db2.wrapper.Nickname
+
+
Perform the necessary nickname initialization.
+
+
initializeMyServer(ServerInfo) - Method in class com.ibm.db2.wrapper.Server
+
+
Initialize the data source server with valid federated server's system catalog information.
+
+
initializeMyUser(UserInfo) - Method in class com.ibm.db2.wrapper.RemoteUser
+
+
Perform the necessary user mapping initialization.
+
+
initializeMyWrapper(WrapperInfo) - Method in class com.ibm.db2.wrapper.Wrapper
+
+
Initialize the wrapper object state from the catalog information object.
+
+
insertColumn(ColumnInfo) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Insert a column information object at the position given by its column ID field.
+
+
insertLocalParm(RFuncParmInfo) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Insert a local parameter in the local parameters list.
+
+
insertRemoteFunction(RemoteFunctionInfo) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Insert a remote function mapping object into the chain.
+
+
insertRemoteFunction(RemoteFunctionInfo) - Method in class com.ibm.db2.wrapper.UnfencedServer
+
+
This function adds a temporary remote function mapping based on the RemoteFunctionInfo + object to the server.
+
+
insertRemoteFunction(DefaultRemoteFunction) - Method in class com.ibm.db2.wrapper.UnfencedServer
+
+
This function adds a temporary remote function mapping based on the DefaultRemoteFunction + object to the server.
+
+
insertRemoteParm(RFuncParmInfo) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Insert a remote parameter in the remote parameters list.
+
+
INT - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates an INTEGER (INT) data type.
+
+
isActionValid() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Check to see if an action was specified.
+
+
isAuthIDValid() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Verify whether an authorization ID value is specified.
+
+
isAuthIDValid() - Method in class com.ibm.db2.wrapper.UserInfo
+
+
Verify whether an authorization ID is specified.
+
+
isAvgLengthValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether an average length is specified for the column.
+
+
isCachingAllowed() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Returns true if it is allowed to use the Nickname in local caches like MQTs
+
+
isCachingAllowedValid() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Verify whether isCachingAllowed is specified.
+
+
isCardValid() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Verify whether a cardinality value is specified.
+
+
isClusterRatioValid() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Check to see if the cluster ratio is specified.
+
+
isCodepage1Valid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a single-byte character set (SBCS) code page is specified for the column.
+
+
isCodepage2Valid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a double-byte character set (DBCS) code page is specified for the column.
+
+
isColCardValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a cardinality value is specified for the column.
+
+
isColumnIDValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a column ID (position) is specified for the column.
+
+
isColumnNameValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a name is specified for the column.
+
+
isColumnTypeValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a local type is specified for the column.
+
+
isConnected() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Verify whether the connection with the data source server exists.
+
+
isCorelibValid() - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Verify whether a core library is specified.
+
+
isDataNull() - Method in class com.ibm.db2.wrapper.RequestConstant
+
+
Indicate whether the constant is null.
+
+
isDataNull() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Indicate whether the data value is null.
+
+
isDataNullable() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Indicate whether the data value is nullable.
+
+
isDefaultValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a default value is specified for the column.
+
+
isDefinerTypeValid() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Check to see if a definer type was specified.
+
+
isDefinerValid() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Check to see if a definer was specified.
+
+
isFirstKeycardValid() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Check to see if the first key cardinality is specified.
+
+
isForBitDataValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a FOR BIT DATA flag is specified for the column.
+
+
isFPagesValid() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Verify whether the fpages statistics is specified.
+
+
isFullKeycardValid() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Check to see if the full key cardinality is specified.
+
+
isFuncIDValid() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Check to see if a function ID was specified.
+
+
isHigh2KeyValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a second-highest value is specified for the column.
+
+
isIndexNameValid() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Check to see if an index name is specified.
+
+
isInitialInstsValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a value for the number of machine instructions executed the first time the function is executed was specified
+
+
isInitialIosValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a value for the number of I/O operations the first time the function is executed was specified
+
+
isInstsPerArgByteValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a value for the number of machine instructions per byte of argument for one invocation was specified
+
+
isInstsPerInvokeValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a value for the number of machine instructions per invocation was specified
+
+
isIosPerArgByteValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a value for the number of I/O operations per byte of argument for one invocation was specified
+
+
isIosPerInvokeValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a value for the number of I/O operations per invocation was specified
+
+
isLocalSignatureValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a local function signature was specified
+
+
isLow2KeyValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a second-lowest value is specified for the column.
+
+
isMappingNameValid() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Check to see if a mapping name was specified.
+
+
isNameValid() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Verify whether the value of server name is specified.
+
+
isNameValid() - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Verify whether a name is specified.
+
+
isNewColumnNameValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a new name is specified for the column.
+
+
isNicknameValid() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Verify whether the name of the nickname is specified.
+
+
isNLeafValid() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Check to see if the number of leafs is specified.
+
+
isNLevelsValid() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Check to see if the number of levels is specified.
+
+
isNPagesValid() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Verify whether the npages statistics is specified.
+
+
isNullsValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a nulls-allowed flag is specified for the column.
+
+
isNumNullsValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether numNulls is specified for the column.
+
+
isOrdinalValid() - Method in class com.ibm.db2.wrapper.RFuncParmInfo
+
+
check if an ordinal value was specified.
+
+
isOrgLengthValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether an original length is specified for the column.
+
+
isOrgScaleValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether an original scale is specified for the column.
+
+
isOverflowValid() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Verify whether an overflow statistics is specified.
+
+
isPasswordValid() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Verify whether a password value is specified.
+
+
isPercentArgByteValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a value for the percentage of arguments bytes was specified
+
+
isRemoteFunctionNameValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a remote function name was specified
+
+
isRemoteResultTypeValid() - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Check to see if a remote result type was specified
+
+
isReserved() - Method in class com.ibm.db2.wrapper.CatalogOption
+
+
Indicate whether the option is a DB2-reserved option.
+
+
isReservedFunctionOption(String) - Static method in class com.ibm.db2.wrapper.UnfencedServer
+
+
Returns true if an option is a reserved function option
+
+
isSchemaValid() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Verify whether a schema name is specified.
+
+
isSchemaValid() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Check to see if a schema name was specified.
+
+
isSemanticNull() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Indicate whether the data value is semantic null.
+
+
isServerNameValid() - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Verify whether a server name is specified.
+
+
isServerNameValid() - Method in class com.ibm.db2.wrapper.UserInfo
+
+
Verify whether a data source server name is specified.
+
+
isSignatureValid() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Check to see if a signature was specified.
+
+
isSpecificNameValid() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Check to see if a specific name was specified.
+
+
isTimestampValid() - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Check to see if a timestamp was specified.
+
+
isTypeNameValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a local type name is specified for the column.
+
+
isTypeSchemaValid() - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Verify whether a local type schema is specified for the column.
+
+
isTypeValid() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Verify whether a type value is specified.
+
+
isTypeValid() - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Verify whether a type is specified.
+
+
isUniqueColCountValid() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Check to see if the number of unique columns is specified.
+
+
isUniqueRuleValid() - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Check to see if the unique rule flag is specified.
+
+
isVersionValid() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Verify whether a version value is specified.
+
+
isVersionValid() - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Verify whether a version is specified.
+
+
isWrapperNameValid() - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Verify if a wrapper name value is specified.
+
+
+ + + +

L

+
+
lobDataReady(int, int, int, int) - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Notify the federated server that a fragment of data from a LOB column is fetched (retrieved).
+
+
LONG - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a LONG data type.
+
+
+ + + +

M

+
+
markDisconnected() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Set the flag to indicate that the connection with the data source server finished.
+
+
+ + + +

N

+
+
nextReply() - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve the next reply in the chain.
+
+
Nickname - Class in com.ibm.db2.wrapper
+
+
The Nickname class models collections of data that a data source server manages.
+
+
NicknameInfo - Class in com.ibm.db2.wrapper
+
+
The NicknameInfo class encapsulates the catalog information for a nickname + object including column definitions from the CREATE NICKNAME and ALTER + NICKNAME statements.
+
+
NicknameInfo() - Constructor for class com.ibm.db2.wrapper.NicknameInfo
+
+
Construct a default (empty) nickname information object.
+
+
NO_PHASE_KIND - Static variable in class com.ibm.db2.wrapper.RemoteConnection
+
+
Constant to indicate that no transactions are supported.
+
+
NONE - Static variable in class com.ibm.db2.wrapper.CatalogOption
+
+
Action constant; indicates no action for the option.
+
+
NONE - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates an unknown data type.
+
+
+ + + +

O

+
+
ONE_PHASE_KIND - Static variable in class com.ibm.db2.wrapper.RemoteConnection
+
+
Constant to indicate that one-phase commit transactions are supported.
+
+
open() - Method in class com.ibm.db2.wrapper.RemotePassthru
+
+
Open a cursor for a pass-through operation and enable the data source + to return the first result row for the query.
+
+
OPEN - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object is in open state.
+
+
open() - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Allow the wrapper to prepare the remote data source to return the first result row for + the query.
+
+
OPEN_LOB_INIT - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB input status constant: indicate the start of processing for the input LOB values.
+
+
OPEN_LOB_LAST - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB input status constant: indicate that this is the last fragment for the current input LOB value.
+
+
OPEN_LOB_MORE - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB input status constant: indicate that more fragments are available for the current input LOB value.
+
+
OPEN_LOB_NEW - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB input status constant: indicate that the wrapper expects data fragments for a new input LOB value.
+
+
OPEN_NON_LOB_NEXT - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB input status constant: indicate that only input non-LOB values are to be processed.
+
+
OPEN_ROW_DONE - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
LOB input status constant: indicate that all the input values have been processed.
+
+
openInputLob(int, int, int, Object) - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Allow the wrapper to prepare the remote data source to return the first result row for + the query that contains input large object (LOB) parameters.
+
+
OPERATOR - Static variable in class com.ibm.db2.wrapper.RequestExp
+
+
Constant to indicate that the expression is an operator.
+
+
+ + + +

P

+
+
ParsedQueryFragment - Class in com.ibm.db2.wrapper
+
+
The ParsedQueryFragment class represents the base class of both the + Request class and Reply class.
+
+
planRequest(Request) - Method in class com.ibm.db2.wrapper.UnfencedGenericServer
+
+
Analyze a proposed plan and determine what part of the plan (if any) + can be pushed down to the remote data source.
+
+
PredicateList - Class in com.ibm.db2.wrapper
+
+
The PredicateList describes two lists of predicates to + estimate the selectivity factor.
+
+
prepare(RuntimeDataDescList) - Method in class com.ibm.db2.wrapper.RemotePassthru
+
+
Prepare a pass-through operation.
+
+
+ + + +

Q

+
+
Quantifier - Class in com.ibm.db2.wrapper
+
+
The Quantifier class encapsulates information for a quantifier of a Request.
+
+
+ + + +

R

+
+
READY - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object is ready to fetch the next row.
+
+
reExecCost() - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve the cost needed to rerun the query fragment + that is represented by the reply.
+
+
REMOTE_AUTHID_OPTION - Static variable in class com.ibm.db2.wrapper.RemoteUser
+
+
Constant that represents the name of the remote authorization ID option.
+
+
REMOTE_PASSWORD_OPTION - Static variable in class com.ibm.db2.wrapper.RemoteUser
+
+
Constant that represents the name of the remote authorization password option.
+
+
RemoteConnection - Class in com.ibm.db2.wrapper
+
+
The RemoteConnection class represents a connection (session) with a data source server.
+
+
RemoteConnection(FencedServer, FencedRemoteUser, int, long) - Constructor for class com.ibm.db2.wrapper.RemoteConnection
+
+
Construct a connection for the specified server with the user authorization and transaction type as specified.
+
+
RemoteFunctionInfo - Class in com.ibm.db2.wrapper
+
+
The RemoteFunctionInfo class represents the catalog information + and describes the function mapping with a remote source.
+
+
RemoteFunctionInfo() - Constructor for class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Class constructor.
+
+
RemoteFunctionInfo(int, String, String, String, int, String, String, Timestamp) - Constructor for class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Construct an instance with the specified values.
+
+
RemoteFunctionInfo(int, String, String, String, int, String, String, byte, Timestamp) - Constructor for class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Construct an instance with the specified values.
+
+
RemoteOperation - Class in com.ibm.db2.wrapper
+
+
The RemoteOperation class serves as the base class for classes that represent + various remote operations.
+
+
RemotePassthru - Class in com.ibm.db2.wrapper
+
+
The RemotePassthru class represents a pass-through session on a remote data source.
+
+
RemotePassthru(RemoteConnection, long) - Constructor for class com.ibm.db2.wrapper.RemotePassthru
+
+
Construct a new pass-through object for the specified connection.
+
+
RemoteQuery - Class in com.ibm.db2.wrapper
+
+
The RemoteQuery class represents SELECT statement operations on a remote data source.
+
+
RemoteQuery(RemoteConnection, long) - Constructor for class com.ibm.db2.wrapper.RemoteQuery
+
+
Construct a new query object for the specified connection.
+
+
RemoteUser - Class in com.ibm.db2.wrapper
+
+
The RemoteUser class represents the authorizations to use on a data source server.
+
+
reopen(short) - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Reset a previously opened result stream and prepares the data source to return more result sets, + possibly based on different parameter bindings.
+
+
reopenInputLob(short, int, int, int, Object) - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Reset a previously opened result stream and prepares the data source to return more result sets, + possibly based on different parameter bindings for queries with input large object (LOB) parameters.
+
+
Reply - Class in com.ibm.db2.wrapper
+
+
The Reply class represents the portion of a request that the wrapper processes.
+
+
Reply(Request, UnfencedGenericServer) - Constructor for class com.ibm.db2.wrapper.Reply
+
+
Instantiate a Reply for the specified data source (Server) and Request.
+
+
reportEof() - Method in class com.ibm.db2.wrapper.RemoteOperation
+
+
Report an end-of-file condition during a fetch operation.
+
+
reportEof() - Method in class com.ibm.db2.wrapper.RemotePassthru
+
+
Report an end-of-file condition during a fetch operation.
+
+
reportEof() - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Report an end-of-file condition during a fetch operation.
+
+
reportWarning(int, String, String[]) - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Report a warning to the DB2 Information Integrator user.
+
+
Request - Class in com.ibm.db2.wrapper
+
+
The Request class encapsulates a query fragment that is analyzed and processed by the wrapper.
+
+
RequestConstant - Class in com.ibm.db2.wrapper
+
+
The RequestConstant class describes a constant that is used in a query + expression during query planning.
+
+
RequestExp - Class in com.ibm.db2.wrapper
+
+
The RequestExp class represents a node in an expression tree.
+
+
RequestExpType - Class in com.ibm.db2.wrapper
+
+
The RequestExpType class describes the type of node in an expression tree.
+
+
RFuncParmInfo - Class in com.ibm.db2.wrapper
+
+
The RFuncParmInfo class represents the information that describes a function parameter + in a function mapping.
+
+
RFuncParmInfo() - Constructor for class com.ibm.db2.wrapper.RFuncParmInfo
+
+
Default constructor.
+
+
RFuncParmInfo(short) - Constructor for class com.ibm.db2.wrapper.RFuncParmInfo
+
+
Construct a function parameter with the specified ordinal.
+
+
rollback() - Method in class com.ibm.db2.wrapper.RemoteConnection
+
+
Indicate the unsuccessful completion of a + transaction and that the remote data + source then rolls back the transaction.
+
+
RuntimeData - Class in com.ibm.db2.wrapper
+
+
The RuntimeData class represents each column value that is transferred between the + federated server and a wrapper.
+
+
RuntimeDataDesc - Class in com.ibm.db2.wrapper
+
+
The RuntimeDataDesc class is created by the federated server to describe each column + value that is transferred between the federated server and a wrapper.
+
+
RuntimeDataDesc(short, int, short, short) - Constructor for class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Construct a new RuntimeDataDesc object with the specified attributes + to describe a column of a result set.
+
+
RuntimeDataDesc(short, int, short, short, byte) - Constructor for class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
+
+
RuntimeDataDesc(short, int, short, short, byte, byte) - Constructor for class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
+
+
RuntimeDataDesc(short, int, short, short, byte, byte, String) - Constructor for class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
+
+
RuntimeDataDesc(short, int, short, short, byte, byte, String, short) - Constructor for class com.ibm.db2.wrapper.RuntimeDataDesc
+
+
Construct a new RuntimeDataDesc object with the specified attributes to + describe a column of a result set.
+
+
RuntimeDataDescList - Class in com.ibm.db2.wrapper
+
+
The RuntimeDataDescList class encapsulates a list of RuntimeDataDesc + objects that describe a row in a result set or a list of input parameters.
+
+
RuntimeDataList - Class in com.ibm.db2.wrapper
+
+
The RuntimeDataList class encapsulates a list of RuntimeData objects + that represent either a row in a result set or a list of input parameters.
+
+
+ + + +

S

+
+
Server - Class in com.ibm.db2.wrapper
+
+
The Server class is the abstract base class for all server functionality.
+
+
ServerInfo - Class in com.ibm.db2.wrapper
+
+
The ServerInfo class encapsulates the catalog information for a server object + from the CREATE SERVER and ALTER SERVER statements.
+
+
ServerInfo() - Constructor for class com.ibm.db2.wrapper.ServerInfo
+
+
Construct a default (empty) server information object.
+
+
ServerInfo(String, String, String, String) - Constructor for class com.ibm.db2.wrapper.ServerInfo
+
+
Construct a fully initialized server information object.
+
+
SET - Static variable in class com.ibm.db2.wrapper.CatalogOption
+
+
Action constant; indicates that the option is set to a new value.
+
+
setAction(int) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the action value.
+
+
setActualLength(int) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the actual length for the data value.
+
+
setAuthID(String) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Set the authorization ID for the server.
+
+
setAuthID(String) - Method in class com.ibm.db2.wrapper.UserInfo
+
+
Set the authorization ID for this user mapping.
+
+
setAvgLength(int) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the average length of the column.
+
+
setBigDecimal(BigDecimal) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a BigDecimal instance.
+
+
setBinary(byte[]) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a binary value.
+
+
setByte(byte) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a byte.
+
+
setCachingAllowed(boolean) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Set the isCachingAllowed flag for the nickname determining if it is allowed to use the Nickname in local caches like MQTs
+
+
setCard(long) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Set the cardinality value.
+
+
setClusterRatio(short) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the cluster ratio.
+
+
setCodepage1(short) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the single-byte character set (SBCS) code page for the column.
+
+
setCodepage2(short) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the double-byte character set (DBCS) code page for the column.
+
+
setColCard(long) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the cardinality of the column.
+
+
setColNames(ArrayList) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the names of the indexed columns.
+
+
setColumnID(short) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the column ID, which represents the position of he column.
+
+
setColumnName(String) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the name of the column.
+
+
setColumnType(String) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the type of the column.
+
+
setDataNull() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Mark the data value as null.
+
+
setDate(Date) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a Date instance.
+
+
setDefault(String) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the default value for the column.
+
+
setDefiner(String) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the definer.
+
+
setDefinerType(byte) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the definer type.
+
+
setDistinct(boolean) - Method in class com.ibm.db2.wrapper.Reply
+
+
Set the DISTINCT indicator that is specified in the SELECT DISTINCT statement.
+
+
setDouble(double) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a double.
+
+
setErrorCode(int) - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Set the SQL error code for reporting a DB2 Information Integrator error.
+
+
setExecDesc(Serializable) - Method in class com.ibm.db2.wrapper.Reply
+
+
Set the execution descriptor object.
+
+
setFencedWrapperClass(WrapperInfo, String) - Method in class com.ibm.db2.wrapper.UnfencedWrapper
+
+
Add the wrapper-specific FencedWrapper subclass name to the WrapperInfo object.
+
+
setFirstKeycard(long) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the first key cardinality.
+
+
setFloat(float) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a float.
+
+
setForBitData(boolean) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the FOR BIT DATA flag for the column.
+
+
setFPages(long) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Set the fpages statistics for the nickname.
+
+
setFriendlyDivBy0() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Indicate that a value is null because a divide by zero error occurred.
+
+
setFriendlyException() - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Indicate that a value is null because of a numeric exception.
+
+
setFullKeycard(long) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the full key cardinality.
+
+
setFuncID(int) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the local function ID.
+
+
setFunctionName(String) - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Set the caller function name for reporting a DB2 Information Integrator error.
+
+
setHigh2Key(String) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the second-highest value for the column.
+
+
setIndexName(String) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the name of the index.
+
+
setInitialInsts(double) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the number of machine instructions executed the first time the function is executed
+
+
setInitialIos(double) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the number of I/O operations the first time the function is executed
+
+
setInstsPerArgByte(double) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the number of machine instructions per byte of argument for one invocation of the function.
+
+
setInstsPerInvoke(double) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the number of machine instructions per invocation of the function.
+
+
setInt(int) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as an int.
+
+
setIosPerArgByte(double) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the number of I/O operations per byte of argument for one invocation of the function.
+
+
setIosPerInvoke(double) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the number of I/O operations per invocation of the function.
+
+
setLobNext() - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Notify the federated server when a current fetched row contains large object (LOB) values and + that the fetchLob method is to be invoked.
+
+
setLocalSchema(String) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the local schema name.
+
+
setLocalSignature(String) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the local signature.
+
+
setLocalSignature(String) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the signature.
+
+
setLong(long) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a long.
+
+
setLow2Key(String) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the second-lowest value for the column.
+
+
setMappingName(String) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the mapping name.
+
+
setMyDefaultRemoteFunctionMappings() - Method in class com.ibm.db2.wrapper.UnfencedServer
+
+
Allows the wrapper to add temporary function mappings to the current server via the + UnfencedServer.insertRemoteFunction(RemoteFunctionInfo) and UnfencedServer.insertRemoteFunction(DefaultRemoteFunction) method.
+
+
setNewColumnName(String) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the new name for the column.
+
+
setNextFunction(RemoteFunctionInfo) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the next function in the chain.
+
+
setNextIndex(IndexInfo) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the next index in the chain.
+
+
setNextReply(Reply) - Method in class com.ibm.db2.wrapper.Reply
+
+
Specify the next reply in the chain.
+
+
setNextRFuncParm(RFuncParmInfo) - Method in class com.ibm.db2.wrapper.RFuncParmInfo
+
+
Set the next function parameter in the chain.
+
+
setNickname(String) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Set the name of the nickname.
+
+
setNLeaf(int) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the number of leafs.
+
+
setNLevels(short) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the number of levels.
+
+
setNPages(long) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Set the npages statistics for the nickname.
+
+
setNullIndicator(short) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the null indicator for the data value.
+
+
setNulls(boolean) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the nulls-allowed flag.
+
+
setNumberOfValues(int) - Method in class com.ibm.db2.wrapper.RuntimeDataDescList
+
+
Set the number of data descriptors in the list.
+
+
setNumNulls(long) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the number of null values in the column, -1 if statistics are not collected.
+
+
setObject(Object) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as an Object instance.
+
+
setOrdinal(short) - Method in class com.ibm.db2.wrapper.RFuncParmInfo
+
+
Set the ordinal value.
+
+
setOrgLength(int) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the maximum length (in bytes) for the column.
+
+
setOrgScale(short) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the numeric scale of the column.
+
+
setOverflow(long) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Set the overflow statistics for the nickname.
+
+
setPassword(String) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Set the password for the server.
+
+
setPercentArgByte(short) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the percentage of arguments bytes
+
+
setPrecision(byte) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the precision for numeric data type values.
+
+
setPrevFunction(RemoteFunctionInfo) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the previous function in the chain.
+
+
setPrevIndex(IndexInfo) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the previous index in the chain.
+
+
setRemoteFunctionName(String) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the remote function name.
+
+
setRemoteResultType(short) - Method in class com.ibm.db2.wrapper.DefaultRemoteFunction
+
+
Set the value for the result type.
+
+
setRowStatus(int) - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Set the current row status.
+
+
setScale(byte) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the scale for numeric data type values.
+
+
setSchema(String) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Set the local schema name of the nickname.
+
+
setServerName(String) - Method in class com.ibm.db2.wrapper.NicknameInfo
+
+
Set the server name of the nickname.
+
+
setServerName(String) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Set the server name.
+
+
setServerName(String) - Method in class com.ibm.db2.wrapper.UserInfo
+
+
Set the data source server name for this user mapping.
+
+
setShort(short) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a short.
+
+
setSpecificName(String) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the specific name.
+
+
setStatus(byte) - Method in class com.ibm.db2.wrapper.RemoteQuery
+
+
Set the query status.
+
+
setString(String) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a string.
+
+
setTime(Time) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a Time instance.
+
+
setTimestamp(Timestamp) - Method in class com.ibm.db2.wrapper.RemoteFunctionInfo
+
+
Set the timestamp value.
+
+
setTimestamp(Timestamp) - Method in class com.ibm.db2.wrapper.RuntimeData
+
+
Set the data value as a Timestamp instance.
+
+
setTokens(String[]) - Method in exception com.ibm.db2.wrapper.WrapperException
+
+
Set the substitution tokens that are used for reporting a DB2 Information Integrator error.
+
+
setType(String) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Set the type of the server.
+
+
setType(char) - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Set the wrapper type.
+
+
setTypeName(String) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the name of the local column type.
+
+
setTypeSchema(String) - Method in class com.ibm.db2.wrapper.ColumnInfo
+
+
Set the schema of the local column type.
+
+
setUniqueColCount(short) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the number of unique columns in the index.
+
+
setUniqueRule(byte) - Method in class com.ibm.db2.wrapper.IndexInfo
+
+
Set the flag to indicate whether or not the index has a unique rule.
+
+
setValue(RuntimeDataDesc, int) - Method in class com.ibm.db2.wrapper.RuntimeDataDescList
+
+
Set the data descriptor at the specified position in the list.
+
+
setVersion(String) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Set the version string for the server.
+
+
setVersion(int) - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Set the wrapper version.
+
+
setWrapperName(String) - Method in class com.ibm.db2.wrapper.ServerInfo
+
+
Set the name of the wrapper that contains the server.
+
+
setWrapperName(String) - Method in class com.ibm.db2.wrapper.WrapperInfo
+
+
Set the wrapper name.
+
+
SHORT - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a SHORT data type.
+
+
SQL_NO_NULLS - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates the column NULL status as NO NULLS.
+
+
SQL_NULLABLE - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates the column NULL status as NULLABLE.
+
+
SQL_NULLABLE_UNKNOWN - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates the column NULL status as UNKNOWN.
+
+
+ + + +

T

+
+
TIME - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a TIME data type.
+
+
TIMESTAMP - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a TIMESTAMP data type.
+
+
totalCost() - Method in class com.ibm.db2.wrapper.Reply
+
+
Retrieve the total execution cost that is needed + to run the query fragment that is represented by the reply.
+
+
traceEnabled() - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Verify whether the DB2 Information Integrator tracing is enabled.
+
+
traceError(int, String, int, String) - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Trace an error message.
+
+
traceException(int, String, int, Throwable) - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Trace an exception and its call stack.
+
+
traceFunctionData(int, String, int, String) - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Trace function data using a single data trace parameter.
+
+
traceFunctionData(int, String, int, String, String) - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Trace function data using two data trace parameters.
+
+
traceFunctionData(int, String, int, String, String, String) - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Trace function data using three data trace parameters.
+
+
traceFunctionEntry(int, String) - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Trace a function entry.
+
+
traceFunctionReturnCode(int, String, int) - Static method in class com.ibm.db2.wrapper.WrapperUtilities
+
+
Trace a function return code.
+
+
+ + + +

U

+
+
UNBOUND - Static variable in class com.ibm.db2.wrapper.RequestExp
+
+
Constant to indicate that the expression is an unbound parameter.
+
+
UnfencedGenericNickname - Class in com.ibm.db2.wrapper
+
+
The UnfencedGenericNickname class represents a nonrelational nickname + in the unfenced (trusted) process space.
+
+
UnfencedGenericNickname(String, String, UnfencedGenericServer) - Constructor for class com.ibm.db2.wrapper.UnfencedGenericNickname
+
+
Construct a nickname with the specified schema and name for the specified data source server.
+
+
UnfencedGenericRemoteUser - Class in com.ibm.db2.wrapper
+
+
The UnfencedGenericRemoteUser class represents a user mapping + for a nonrelational data source in the unfenced (trusted) process space.
+
+
UnfencedGenericRemoteUser(String, UnfencedGenericServer) - Constructor for class com.ibm.db2.wrapper.UnfencedGenericRemoteUser
+
+
Construct a user mapping with a specified name for the specified server.
+
+
UnfencedGenericServer - Class in com.ibm.db2.wrapper
+
+
The UnfencedGenericServer class is a subclass of the Server class and is the + abstract base class for all nonrelational data source server functionality that operates + in the unfenced (trusted) process space.
+
+
UnfencedGenericServer(String, UnfencedGenericWrapper) - Constructor for class com.ibm.db2.wrapper.UnfencedGenericServer
+
+
Construct a UnfencedGenericServer object for the specified wrapper with the specified name.
+
+
UnfencedGenericWrapper - Class in com.ibm.db2.wrapper
+
+
The UnfencedGenericWrapper class represents a nonrelational wrapper on + the unfenced (trusted) process space.
+
+
UnfencedGenericWrapper() - Constructor for class com.ibm.db2.wrapper.UnfencedGenericWrapper
+
+
Construct a new UnfencedGenericWrapper object.
+
+
UnfencedNickname - Class in com.ibm.db2.wrapper
+
+
The UnfencedNickname class represents a nickname + in the unfenced (trusted) process space.
+
+
UnfencedRemoteUser - Class in com.ibm.db2.wrapper
+
+
The UnfencedRemoteUser class represents a user mapping in the unfenced (trusted) process space.
+
+
UnfencedServer - Class in com.ibm.db2.wrapper
+
+
The UnfencedServer class is a subclass of the Server class and is the + abstract base class for all data source server functionality that operates in the unfenced + (trusted) process space.
+
+
UnfencedServer(String, int, UnfencedWrapper) - Constructor for class com.ibm.db2.wrapper.UnfencedServer
+
 
+
UnfencedWrapper - Class in com.ibm.db2.wrapper
+
+
The UnfencedWrapper class that represents the wrapper on the unfenced (trusted) process space.
+
+
UNREADY - Static variable in class com.ibm.db2.wrapper.RemoteQuery
+
+
Status constant to be used with getStatus and + setStatus methods to indicate that the + RemoteQuery object is not yet ready to fetch the next row.
+
+
UserInfo - Class in com.ibm.db2.wrapper
+
+
The UserInfo class encapsulates the catalog information for a user mapping + from the CREATE USER MAPPING and ALTER USER MAPPING statements.
+
+
UserInfo() - Constructor for class com.ibm.db2.wrapper.UserInfo
+
+
Construct a default (empty) user information object.
+
+
+ + + +

V

+
+
VARCHAR - Static variable in class com.ibm.db2.wrapper.Data
+
+
Constant that indicates a VARCHAR data type.
+
+
verifyMyAlterNicknameInfo(NicknameInfo) - Method in class com.ibm.db2.wrapper.UnfencedNickname
+
+
Validate the nickname information that is specified in ALTER NICKNAME statements.
+
+
verifyMyAlterServerInfo(ServerInfo) - Method in class com.ibm.db2.wrapper.UnfencedServer
+
+
Validate the data source server information that is specified in ALTER SERVER statements.
+
+
verifyMyAlterUserInfo(UserInfo) - Method in class com.ibm.db2.wrapper.UnfencedRemoteUser
+
+
Validate the user mapping information that is specified in the ALTER USER MAPPING statements.
+
+
verifyMyAlterWrapperInfo(WrapperInfo) - Method in class com.ibm.db2.wrapper.UnfencedWrapper
+
+
Validate the information that is specified on an ALTER WRAPPER statement.
+
+
verifyMyFunctionMappingInfo(RemoteFunctionInfo) - Method in class com.ibm.db2.wrapper.UnfencedServer
+
+
Validates function mapping information that is specified in CREATE FUNCTION MAPPING statements.
+
+
verifyMyRegisterNicknameInfo(NicknameInfo) - Method in class com.ibm.db2.wrapper.Nickname
+
+
Validate the nickname information that is specified in CREATE NICKNAME statements.
+
+
verifyMyRegisterServerInfo(ServerInfo) - Method in class com.ibm.db2.wrapper.UnfencedServer
+
+
Validate the data source server information that is specified in CREATE SERVER statements.
+
+
verifyMyRegisterUserInfo(UserInfo) - Method in class com.ibm.db2.wrapper.UnfencedRemoteUser
+
+
Validate the user mapping information that is specified in the CREATE USER MAPPING statements.
+
+
verifyMyRegisterWrapperInfo(WrapperInfo) - Method in class com.ibm.db2.wrapper.UnfencedWrapper
+
+
Validate the information that is specified on a CREATE WRAPPER statement.
+
+
+ + + +

W

+
+
Wrapper - Class in com.ibm.db2.wrapper
+
+
The Wrapper class represents the base class for a set of data sources.
+
+
WrapperException - Exception in com.ibm.db2.wrapper
+
+
The WrapperException class is the Exception subclass + that is used by the Java API to report exceptions.
+
+
WrapperException(String) - Constructor for exception com.ibm.db2.wrapper.WrapperException
+
+
Construct a new exception object with the specified message.
+
+
WrapperException(int, String, String[]) - Constructor for exception com.ibm.db2.wrapper.WrapperException
+
+
Construct an exception object that reports a DB2 Information Integrator error by its SQL + code, caller function name, and tokens.
+
+
WrapperInfo - Class in com.ibm.db2.wrapper
+
+
The WrapperInfo class encapsulates the catalog information for a wrapper object + from the CREATE WRAPPER and ALTER WRAPPER statements.
+
+
WrapperInfo() - Constructor for class com.ibm.db2.wrapper.WrapperInfo
+
+
Construct a new default (empty) wrapper information object.
+
+
WrapperUtilities - Class in com.ibm.db2.wrapper
+
+
The WrapperUtilities class is a container for several static utility functions.
+
+
+A B C D E F G I L M N O P Q R S T U V W 
+ +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/index.html b/wrappers/wrapper_sdk_java/javadoc/index.html new file mode 100644 index 0000000..a9bf2fe --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/index.html @@ -0,0 +1,71 @@ + + + + + +IBM DB2 Information Integrator - Java API Reference for Developing Wrappers + + + + + + +<noscript> +<div>JavaScript is disabled on your browser.</div> +</noscript> +<h2>Frame Alert</h2> +<p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="com/ibm/db2/wrapper/package-summary.html">Non-frame version</a>.</p> + + + diff --git a/wrappers/wrapper_sdk_java/javadoc/overview-tree.html b/wrappers/wrapper_sdk_java/javadoc/overview-tree.html new file mode 100644 index 0000000..521ecb1 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/overview-tree.html @@ -0,0 +1,238 @@ + + + + + +Class Hierarchy (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +
+

Hierarchy For All Packages

+Package Hierarchies: + +
+
+

Class Hierarchy

+ +
+ +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/package-list b/wrappers/wrapper_sdk_java/javadoc/package-list new file mode 100644 index 0000000..b3d3ea0 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/package-list @@ -0,0 +1 @@ +com.ibm.db2.wrapper diff --git a/wrappers/wrapper_sdk_java/javadoc/resources/background.gif b/wrappers/wrapper_sdk_java/javadoc/resources/background.gif new file mode 100644 index 0000000000000000000000000000000000000000..f471940fde2f39ef8943a6af9569bcf986b1579b GIT binary patch literal 2313 zcmV+k3HJ6!Nk%w1VKM-40OkMy00030|NlK(aXwsfKV5S}VtGJbbVOr%L0@%CZH88Q zl{{NzcR^uxNo<2iYk@pjY)*5FJz8x~bc{)B zfk z+1T6M-s9WdW8dcJ-wO*3@9+W*5AY543-j^$^!EPz_4eHZ2#>)41`h@dc!2OAgN6$a zCS2I?;lqgx6IR4nkpTe;1RN0f=zxMq2O=q`94V5d$&e>Unta)^<;;^G3>e7yp=ZvW z6DIW3xpSvaogXF?_4%`@(V;s}NR^5J!3hrtJV@1QRV&r5S*L!zYE|rss${iFkg&!? zTN5V#)~=bmMorwgZsEpdOE)iExo+FO-8;8Kga{=HbSQCnF=E6W3?o*|ID%uwi5**> zJXy127Y9m+=HQ|PhXWi+xNwoWv}n_%Pq%(e+H~mGqhq5kv4Mo|-n~g|7!F*xZ{xv< zCpXS~dGg^IGK?4@J-T%b(XnUHFul6n<@2&4)zzyO2) z3Q8`i0+UKY*`$}e9mmp;tg*))`|PsK1|hAo%u0K$vDwm4gaSkm0j{`26k#qAKmbuhxZ#cquDR>B zD{s8+&TH-uNg$C#68QG}1HMBHfrP&L@@w$F_!itRzXdCN@V|LDAu%3!IDtq1#1UV7 z#1RxvT=B(DWbCoU5l=ia$Pp`Hgb_?Mp@hmtxZDI2N-)v#$}PXVvdm1d>@v(v`0TUJ zF)Pu89(q`zv=w^nVTIF3@3BYIPA}c`(@ZCAwbNBEt@PDUKe5CTR8aB66IE1!w%Amt zy+jpcn~k>GZpVFg+H6x{_uOksvBlq0OyT$6TyQZ37k(cOxZr|JEx1sGm<(M9gH z-~PMqyn|tT=))UN`|-FFFUA#KToK0fUOaz=7}Z~KeHhVC&%O27cTfHQ^WBU8z4p&T zp#>D|V}XShTD;Hx745Iz{`>K-Z$A|7!*Boo{mY;G21vjH8t{M!OrQc6$iN0V@PQDF zpadsK!3tXNf*8!81~qnXWuHZ)kytd=_y+ADWvw31ouV;CdZ#ya*(l7-A-C-Y^+iit8O zBy3*`Ls$|5Hn4m_^I^|C7{m7EFn|5vTk;|oywIgCc9Bb*=L+Y$)M>9GC<|HGs@6NB zHLY%03!dDf=eDRt2O6lVSFRcsuWZEwU?=z$CZ0W?#VJfdN>HG(l%oKpyiftJc|Y)xkjSJYCrQal-0PC~()T9xwF!Jf zVi1UA#3BBbh(i8r5&v#Pz!cF41KjbCc?4u2@@Q~oKLirt2TM30;y6b+zyX2`Yl9u; z`0$3;v0-YUp&7NdPT#q`cZlbij$jvbRk6R>8g*>}*b9E+WDwmpHAAxYzyT aU_pX{M6b8i>#Dq3onfZy}_nli%!Q$ZV%e&!tN2 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 YpWXKgmku8Vj|K)Vje`mzEKCg608Q#dYybcN literal 0 HcmV?d00001 diff --git a/wrappers/wrapper_sdk_java/javadoc/serialized-form.html b/wrappers/wrapper_sdk_java/javadoc/serialized-form.html new file mode 100644 index 0000000..fc665e7 --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/serialized-form.html @@ -0,0 +1,158 @@ + + + + + +Serialized Form (IBM DB2 Information Integrator - Java API Reference for Developing Wrappers) + + + + + + + +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +
+

Serialized Form

+
+
+
    +
  • +

    Package com.ibm.db2.wrapper

    +
      +
    • + + +

      Class com.ibm.db2.wrapper.WrapperException extends java.lang.Exception implements Serializable

      +
        +
      • + + +

        Serialized Fields

        +
          +
        • +

          _errorCode

          +
          int _errorCode
          +
        • +
        • +

          _tokens

          +
          java.lang.String[] _tokens
          +
        • +
        • +

          _functionName

          +
          java.lang.String _functionName
          +
        • +
        • +

          _functionID

          +
          int _functionID
          +
        • +
        • +

          _internalReturnCode

          +
          boolean _internalReturnCode
          +
        • +
        +
      • +
      +
    • +
    +
  • +
+
+ +
+ + + + + + + +
IBM DB2 Information Integrator
Java API Reference
for Developing Wrappers
+
+ + +

(C)Copyright IBM Corp. 2002. All rights reserved.

Links on this page are made available for your convenience and may take you to non-IBM sites. IBM does not warrant any sample code provided on these sites.

+ + diff --git a/wrappers/wrapper_sdk_java/javadoc/stylesheet.css b/wrappers/wrapper_sdk_java/javadoc/stylesheet.css new file mode 100644 index 0000000..2f75e7f --- /dev/null +++ b/wrappers/wrapper_sdk_java/javadoc/stylesheet.css @@ -0,0 +1,481 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ +body { + background-color:#ffffff; + color:#353833; + font-family:Arial, Helvetica, sans-serif; + font-size:76%; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4c6b87; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4c6b87; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-size:1.3em; +} +h1 { + font-size:1.8em; +} +h2 { + font-size:1.5em; +} +h3 { + font-size:1.4em; +} +h4 { + font-size:1.3em; +} +h5 { + font-size:1.2em; +} +h6 { + font-size:1.1em; +} +ul { + list-style-type:disc; +} +code, tt { + font-size:1.2em; +} +dt code { + font-size:1.2em; +} +table tr td dt code { + font-size:1.2em; + vertical-align:top; +} +sup { + font-size:.6em; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:.8em; + z-index:200; + margin-top:-7px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + background-image:url(resources/titlebar.gif); + background-position:left top; + background-repeat:no-repeat; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-image:url(resources/background.gif); + background-repeat:repeat-x; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:1em; + margin:0; +} +.topNav { + background-image:url(resources/background.gif); + background-repeat:repeat-x; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; +} +.bottomNav { + margin-top:10px; + background-image:url(resources/background.gif); + background-repeat:repeat-x; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; +} +.subNav { + background-color:#dee3e9; + border-bottom:1px solid #9eadc0; + float:left; + width:100%; + overflow:hidden; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding:3px 6px; +} +ul.subNavList li{ + list-style:none; + float:left; + font-size:90%; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; +} +.navBarCell1Rev { + background-image:url(resources/tab.gif); + background-color:#a88834; + color:#FFFFFF; + margin: auto 5px; + border:1px solid #c9aa44; +} +.skip { + position:absolute; + top:auto; + left:-9999px; + overflow:hidden; + } +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader h1 { + font-size:1.3em; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 25px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:1.2em; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border-top:1px solid #9eadc0; + border-bottom:1px solid #9eadc0; + margin:0 0 6px -8px; + padding:2px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border-top:1px solid #9eadc0; + border-bottom:1px solid #9eadc0; + margin:0 0 6px -8px; + padding:2px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:1.0em; +} +.indexContainer h2 { + font-size:1.1em; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:1.1em; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:10px 0 10px 20px; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:25px; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #9eadc0; + background-color:#f9f9f9; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:1px solid #9eadc0; + border-top:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; + border-bottom:1px solid #9eadc0; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.contentContainer table, .classUseContainer table, .constantValuesContainer table { + border-bottom:1px solid #9eadc0; + width:100%; +} +.contentContainer ul li table, .classUseContainer ul li table, .constantValuesContainer ul li table { + width:100%; +} +.contentContainer .description table, .contentContainer .details table { + border-bottom:none; +} +.contentContainer ul li table th.colOne, .contentContainer ul li table th.colFirst, .contentContainer ul li table th.colLast, .classUseContainer ul li table th, .constantValuesContainer ul li table th, .contentContainer ul li table td.colOne, .contentContainer ul li table td.colFirst, .contentContainer ul li table td.colLast, .classUseContainer ul li table td, .constantValuesContainer ul li table td{ + vertical-align:top; + padding-right:20px; +} +.contentContainer ul li table th.colLast, .classUseContainer ul li table th.colLast,.constantValuesContainer ul li table th.colLast, +.contentContainer ul li table td.colLast, .classUseContainer ul li table td.colLast,.constantValuesContainer ul li table td.colLast, +.contentContainer ul li table th.colOne, .classUseContainer ul li table th.colOne, +.contentContainer ul li table td.colOne, .classUseContainer ul li table td.colOne { + padding-right:3px; +} +.overviewSummary caption, .packageSummary caption, .contentContainer ul.blockList li.blockList caption, .summary caption, .classUseContainer caption, .constantValuesContainer caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#FFFFFF; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + margin:0px; +} +caption a:link, caption a:hover, caption a:active, caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .packageSummary caption span, .contentContainer ul.blockList li.blockList caption span, .summary caption span, .classUseContainer caption span, .constantValuesContainer caption span { + white-space:nowrap; + padding-top:8px; + padding-left:8px; + display:block; + float:left; + background-image:url(resources/titlebar.gif); + height:18px; +} +.overviewSummary .tabEnd, .packageSummary .tabEnd, .contentContainer ul.blockList li.blockList .tabEnd, .summary .tabEnd, .classUseContainer .tabEnd, .constantValuesContainer .tabEnd { + width:10px; + background-image:url(resources/titlebar_end.gif); + background-repeat:no-repeat; + background-position:top right; + position:relative; + float:left; +} +ul.blockList ul.blockList li.blockList table { + margin:0 0 12px 0px; + width:100%; +} +.tableSubHeadingColor { + background-color: #EEEEFF; +} +.altColor { + background-color:#eeeeef; +} +.rowColor { + background-color:#ffffff; +} +.overviewSummary td, .packageSummary td, .contentContainer ul.blockList li.blockList td, .summary td, .classUseContainer td, .constantValuesContainer td { + text-align:left; + padding:3px 3px 3px 7px; +} +th.colFirst, th.colLast, th.colOne, .constantValuesContainer th { + background:#dee3e9; + border-top:1px solid #9eadc0; + border-bottom:1px solid #9eadc0; + text-align:left; + padding:3px 3px 3px 7px; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +td.colFirst, th.colFirst { + border-left:1px solid #9eadc0; + white-space:nowrap; +} +td.colLast, th.colLast { + border-right:1px solid #9eadc0; +} +td.colOne, th.colOne { + border-right:1px solid #9eadc0; + border-left:1px solid #9eadc0; +} +table.overviewSummary { + padding:0px; + margin-left:0px; +} +table.overviewSummary td.colFirst, table.overviewSummary th.colFirst, +table.overviewSummary td.colOne, table.overviewSummary th.colOne { + width:25%; + vertical-align:middle; +} +table.packageSummary td.colFirst, table.overviewSummary th.colFirst { + width:25%; + vertical-align:middle; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; + font-style:italic; +} +.docSummary { + padding:0; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:.9em; +} +.block { + display:block; + margin:3px 0 0 0; +} +.strong { + font-weight:bold; +} diff --git a/xml/README b/xml/README new file mode 100644 index 0000000..f4245cd --- /dev/null +++ b/xml/README @@ -0,0 +1,294 @@ +******************************************************************************* +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +******************************************************************************* +* +* README for XML Samples +* +* The /sqllib/samples/xml directory on UNIX and +* \sqllib\samples\xml directory on Windows contain this README file +* where is the location of DB2 9.7 on your hard drive. +* The default location for is $HOME for UNIX +* and C:\Program Files\IBM for windows. +* +* The DB2 9.7 sample code for XML is located in the following directory : +* /sqllib/samples/xml directory on Unix and +* \sqllib\samples\xml directory on Windows. +* +* This README is organized into DIRECTORY ROADMAP, GETTING XML SAMPLES UP +* AND RUNNING, XML SAMPLES DESIGN OVERVIEW and DETAILS OF SAMPLES sections. +* +******************************************************************************* +* +* DIRECTORY ROADMAP +* +* 1.xml/xquery : This directory contains samples for demonstrating the XQuery +* features. +* xquery/c contains C samples for XQuery. +* xquery/cli contains CLI samples for XQuery. + xquery/clp contains command line processor samples for XQuery. +* xquery/java/jdbc contains JDBC API samples for XQuery. +* xquery/java/sqlj contains SQLj samples for XQuery. +* +* 2. xml/c : contains the files for embedded SQL samples. +* 3. xml/cli : contains the files for CLI samples. +* 4. xml/clp : contains the files for CLP samples. +* 5. xml/java: contains the files for JAVA samples. +* java/jdbc contains the files for JDBC API samples +* java/sqlj contains the files for SQLj samples. +* 6. xml/data: directory contains the data required for running these samples. +* This directory contains the setup and clean up scripts for some of +* the samples. +* +* For more details on the content of these directories, please refer to the +* the README file in the respective directories. +* +******************************************************************************** +* +* GETTING XML SAMPLES UP AND RUNNING +* +* WARNINGS +* 1. These steps gives an overview of building and running the samples. Please +* read the README in corresponding directory for any specific considerations. +* +* SETUP: +* +* 1) Copy the files from corresponding directory to a working +* directory and ensure that directory has write permission. +* +* 2) On Windows platform, all samples should be run and built in DB2 +* Command Window. +* The DB2 command window is needed to execute the db2 specific commands. +* You can follow the step below to open DB2 command window. +* From the Start Menu click Start --> Programs --> IBM DB2 --> +* --> Command Line Tools --> Command Window. +* +* 3) Start the database manager with the following command: +* db2start +* +* 4) Create the sample database with the following command: +* db2sampl -xml +* +* 5) Connect to the sample database with the following command: +* db2 connect to sample +* +* 6) To build stored procedures and User defined functions, +* ensure that you have write permission on the +* /sqllib/function directory on UNIX and +* \sqlib\function directory on WINDOWS. +* +* 7) Change directory (CD) to the directory containing the files +* copied in step 1. +* +* BUILD AND RUN: +* 1. Some of the samples might need one or more of the data files at runtime. +* The data files can be found in the xml/data directory. Please copy the +* data files to your working directory before running the particular sample. +* For more details on the data files required for a particular sample, +* please refer the header section of the sample. +* +* To compile these samples, build scripts are provided. +* The README file in each directory containing the actual samples provides the +* details about how to compile the samples using the build script. +* +* Here is the brief overview : +* +* C and CLI: +* +* To create the executable for the sample: +* +* bldapp +* +* where is the name of the sample without any extension. +* +* e.g. bldapp xmlschema +* +* To run the sample: +* +* xmlschema +* +* JDBC: +* +* To create the class file: +* +* javac .java +* +* where is the name of the sample without any extension. +* +* To run the sample file: +* +* java .class +* +* where is the name of the sample without any extension. +* +* SQLj: +* +* To create the class file: +* +* bldsqlj userid password [server name] [port name] +* +* where is the name of the sample without any extension. +* +* To run the sample: +* +* java .class +* +* where is the name of the sample without any extension. +* +* +******************************************************************************* +* +* XML SAMPLES DESIGN OVERVIEW +* +* The XML samples can be functionally categorized into the following areas: +* +* Administration Samples +* +* XML Schema Support +* Schema registration and validation of XML document as per the schema +* +* XML Values Index Support +* Indexes on different node types of XML value +* +* Utility Support for XML +* Import/export/runstats/db2look/db2batch support for XML data type +* +* Application Development Samples +* +* XML Insert/Update/Delete +* Inserting the new XML value in XML type column, Updating and Deleting the +* existing values. +* +* XML Parse/Validate/Serialize Support +* Implicit/explicit parsing of compatible data types. +* +* Hybrid Use of SQL and XQuery +* SQL/XML functions like XMLTable, XMLQuery and XMLExists. +* +* XML in Stored Procedures +* Stored procedure with XML data type parameter +* +* XML Decomposition Support +* Decomposition of XML document as per annnotated schema +* +* XQuery Samples +* +* Axises, FLWOR expression. SQL/XML with XQuery and nested XQueries +* +******************************************************************************** +* +* DETAILS OF SAMPLES +* +* In order to help provide valid, usable and comprehensive XML samples, the +* samples are based on specific usage scenarios, or they demonstrate a +* particular feature or API. These samples are derived from a purchase order +* scenario. Besides the purchase order scenario, a bookstore scenario is used +* to demonstrate the decomposition functionality. +* +* A. Usage Scenarios +* +* 1. Consider a user who needs to insert an XML type value into the table. +* The user would like to ensure that the XML value conforms to a +* deterministic XML schema. To do so, the user can register the XML +* schema to the database and use that to validate the XML document +* prior to inserting it into the table. +* +* Samples: xmlschema.* +* +* 2. Purchase order XML document contains detailed information about all +* the orders. It will also have the detail of the customer with each +* order. To avoid infomation, such as address, repeating for each +* purchase order from the same customer, user can store this data into +* the relational table having XML column. +* +* Samples: xmltotable.* +* +* 3. A bookstore owner has some XML documents which contains descriptive +* information about a book which he has for sale. The owner needs to +* store these details in a relational table for easy retrival of +* information. He/She can easily do it using the Decomposition function. +* +* Samples: xmldecomposition.* +* +* 4. User's purchase order database uses relational tables to store the +* orders of different customers. To get all the purchase order data +* filtered by date or status, a lot of joins on relational tables are +* required. These joins create a massive amount of redundant data as the +* intermediate results. The same data can be returned as an XML object +* to the application. The XML object can be created using the XML +* constructor functions on the server side. +* +* Samples: reltoxmltype.* +* reltoxmldoc.* +* +* B. Features +* +* 1. XML Document Insert/Update/Delete: +* These samples demonstrate different ways of inserting/updating/deleting +* an XML document in a table having XML column. +* +* Samples: xmlinsert.* +* xmlupdel.* +* xmlread.* +* +* 2. Stored Procedure parameter of XML type: +* These samples demonstrate the XML parameter type for stored procedure. +* +* Samples: simple_xmlproc.* +* +* 3. XML Value Index: +* These samples demonstrate the new index features on XML document, +* the different kinds of indexes for XML columns, and how to put the +* constraints on XML document using an index. +* +* Samples: xmlindex.* +* xmlconst.* +* +* 4. Import/Export: +* These samples demonstrate the new import/export command for XML data, +* and the API changes for import/export commands. +* +* Samples: impexpxml.* +* +* 5. XML Runstats: +* These samples demonstrate how to perform RUNSTATS on a TABLE containing +* one or more XML columns. In DB2 Viper, RUNSTATS collects statistics for +* XML columns and associated XML indexes along with relational columns. +* Using these statistics the optimizers perform cost estimation for +* different execution plans. +* +* Samples: xmlrunstats.* +* +* 6. db2look support for XML: +* These samples demonstrate how db2look generates the DDL statements for +* the tables having XML columns. +* +* Samples: xmldb2look.* +* +* 7. db2batch support for XML: +* These samples demonstrate the db2batch functionality when the +* query statements in the batch has XML related queries. +* +* Samples: xmldb2batch.* +* +* 8. XQuery Support: +* These sample demonstrate the XQuery support of DB2. For more details, +* please refer to the README in xquery directory. +* +******************************************************************************** diff --git a/xml/addr.xsd b/xml/addr.xsd new file mode 100644 index 0000000..c386b56 --- /dev/null +++ b/xml/addr.xsd @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/xml/c/README b/xml/c/README new file mode 100644 index 0000000..e05cf89 --- /dev/null +++ b/xml/c/README @@ -0,0 +1,397 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for C XML Samples +* +* The "/sqllib/samples/xml/c" directory on Unix and +* "\sqllib\samples\xml\c" directory on Windows +* contain this README file where is the location of DB2 9.7 +* on your hard drive. +* The default location for is +* C:\Program Files\IBM on Windows. +* The default location for is +* $HOME on Unix. +* +* This README describes how to build and run C XML sample code for DB2 9.7. +* DB2 9.7 sample code and build files for C XML are located in the following +* directory: +* \sqllib\samples\xml\c on Windows and +* /sqllib/samples/xml/c on Unix +* +* It is recommended that you copy the sample files from this directory +* to a working directory prior to building the sample programs. +* The sample program directories are typically read-only on most +* platforms and some samples produce output files that require write +* perimssions on the directory. +* +* WARNING: Some of these samples may change your database or database manager +* configuration. Execute the samples against a test database +* only, such as the DB2 SAMPLE database. +* +****************************************************************************** +* +* Prepare your DB2 sample development environment for Windows/Unix +* +* 1) Copy the files in \sqllib\samples\xm\c\* for Windows and +* $HOME/sqllib/samples/xml/c/* for Unix to a working directory and +* ensure that directory has write permission. +* +* 2) On Windows platform, all samples should be run and built in DB2 +* Command Window. +* The DB2 command window is needed to execute the db2 specific commands. +* You can follow the step below to open DB2 command window. +* From the Start Menu click Start --> Programs --> IBM DB2 --> +* --> Command Line Tools --> Command Window. +* +* 3) Start the database manager with the following command: +* db2start +* +* 4) Create the sample database with the following command: +* db2sampl -xml +* +* 5) Connect to the sample database with the following command: +* db2 connect to sample +* +* 6) To build stored procedures and User defined functions, +* ensure that you have write permission on the +* \sqllib\function directory on Windows and +* /sqllib/function directory on Unix. +* +* 7) Change directory (CD) to the directory containing the files +* copied in step 1. +* +****************************************************************************** +* +* Building DB2 samples +* +* There are two ways to build DB2 samples: using a nmake utility for +* windows (make utility for Unix) or using build scripts that +* are included with DB2 sample programs. +* +* o To build samples using the nmake utility for windows see +* 'BUILDING SAMPLES USING nmake UTILITY on Windows'. +* o To build samples using the make utility for unix see +* 'BUILDING SAMPLES USING make UTILITY on Unix'. +* o To build samples using the build scripts or when you +* don't have a compatible make/namke utility, +* see 'BUILDING SAMPLES USING BUILD SCRIPTS'. +* +* NOTE : +* +* 1. Some of the samples might need one or more data files at runtime. +* some of the samples may also need setup script to be run before +* running the sample.See the specific sample descriptions in +* "File Descriptions" section for more details. +* +* 2. There are utility files available in this directory that are used +* by these samples for error checking. Please make sure that these +* files are present in you working directory. The information +* about these files can be found in "File Descriptions" section of +* this README. +* +* 3. Refer to the "File Descriptions" section in this README for +* information on specific samples and any special considerations +* relevant for each. The HEADER sections of these samples also +* provide further details on each sample. +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING nmake UTILITY ON Windows *** +* +* If you have a compatible nmake utility on your system, you can use +* the makefile provided. Such a nmake utility may be provided by +* another language compiler.If Windows, modify the PATH variable +* to include the directory containing the nmake utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'nmake' command in your working +* directory: +* +* nmake - Builds the program designated by . +* +* nmake all - Builds all supplied sample programs +* +* nmake srv - Builds sample that can only be run on the server +* (stored procedure) +* +* nmake all_client - Builds all client samples (all programs in the +* 'call_rtn' and 'client_run' categories). +* +* nmake call_rtn - Builds client programs that call stored +* procedure +* +* nmake client_run - Builds all programs that run completely on the +* client (not ones that call stored procedure) +* +* nmake clean - Erases all intermediate files produced in the +* build process. +* +* nmake cleanall - Erases all files produced in the build process +* (all files except the original source files). +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING make UTILITY ON Unix *** +* +* If you have a compatible make utility on your system, you +* can use the makefile provided. Modify the PATH +* variable to include the directory containing the make +* utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'make' command in your working directory: +* make - Builds the program designated by . +* +* make all - Builds all supplied sample programs +* +* make srv - Builds sample that can only be run on the server +* (stored procedure) +* +* make all_client - Builds all client samples (all programs in the +* 'call_rtn' and 'client_run' categories). +* +* make call_rtn - Builds client programs that call stored procedure +* +* make client_run - Builds all programs that run completely on the +* client (not ones that call stored procedure) +* +* make clean - Erases all intermediate files produced in the +* build process. +* +* make cleanall - Erases all files produced in the build process +* (all files except the original source files). +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING BUILD SCRIPTS *** +* +* As an alternative to the makefile , the build scripts included +* with the DB2 samples can be used to build the C XML sample programs. +* +* Building Standalone Samples: +* o bldapp +* - the name of the sample program without any +* extension. +* For any additional dependencies refer to the individual sample. +* +* Building and Executing Stored Procedures: +* o Build stored procedure server and copy the resulting binary file to +* the sqllib/function directory with the following command: +* bldrtn +* - Name of the sample program without any +* extension. +* o Catalog stored procedures with the following command: +* spcat +* o Build stored procedure client with the following command: +* bldapp +* - Name of the sample program without any +* extension. +* +* For any additional dependencies refer to individual samples. +* +****************************************************************************** +* +* Common file Descriptions +* +* The following are the common files for C XML samples. For more +* information on these files, refer to the program source files. +* +******************************************************************************* +* +* Common files +* +* README - this file +* makefile - makefile for all files. +* +****************************************************************************** +* +* Common Utility Function files +* +* utilapi.c - Error-checking utility file for DB2 API programs. +* utilapi.h - Header file for utilapi.c. +* utilemb.sqc - Error-checking utility file for embedded SQL programs. +* utilemb.h - Header file for utilemb.sqc. +* +***************************************************************************** +* +* Batch files(for Windows) and Shell Scripts(for Unix) +* +* bldapp - Builds an application program. +* bldrtn - Builds a routine (stored procedure and UDF) program. +* embprep - Precompiles and binds embedded SQL programs. +* +* +****************************************************************************** +* +* C XML sample descriptions +* +* The following are the C XML sample files included with DB2.For more +* information on these files, refer to program source files. +* +* +****************************************************************************** +* +* C XML samples description +* +* Sample Files +* +* xmlschema.sqc - How to register an XML schema to a database using +* stored procedures. How to use this registered schema +* to validate an XML value before inserting into +* a table. +* PREREQUISITE: copy product.xsd, order.xsd, +* customer.xsd, header.xsd Schema files, order.xml XML +* document from xml/data directory to working +* directory. +* +* reltoxmltype.sqc - How to create XML object from data stored in +* relational tables using various SQL/XML Constructor +* functions. +* PREREQUISITE: Run the cleanup.db2 and setupscript.db2 +* scripts before running this simple. +* Run the cleanupscript.db2 script to cleanup the +* database objects after running the sample. +* These scripts can be found in xml/data directory. +* +* xmlread.sqc - How to read XML data stored in tables. +* +* xmlinsert.sqc - How to insert XML data into tables having an XML +* column. +* +* xmlupdel.sqc - How to update and delete XML documents in tables. +* +* xmldecomposition.sqc - How to decompose data stored in a XML file and +* insert those into relational tables with constraints. +* PREREQUISITE: run the script setupfordecomposition.db2 +* before running the sample. Run the script +* cleanupfordecomposition.db2 after running the sample +* to cleanup the object created for the samples. These +* scripts can be found in xml/data directory. This +* sample require bookdetails.xsd, booksreturned.xsd, bookdetails.xml, +* booksreturned.del, booksreturned1.xml, booksreturned2.xml, +* booksreturned3.xml files at run time. Copy these files to your +* working directory before running the sample. These files can +* be found in xml/data directory. +* +* recxmldecomp.sqc - How to register a recursive XML schema to the XSR and +* enable the same for decomposition. +* PREREQUISITE: The instance document and the annotated +* schema should exist in the same directory as the sample. +* Copy recemp.xml, recemp.xsd from directory +* /sqllib/samples/xml/data in UNIX and +* \sqllib\samples\xml\data in Windows to the +* working directory. +* +* xmlload.sqc - How to load XML data into an XML column using LOAD. +* PREREQUISITE: The data files and XML documents must exist +* in the DB2 install path. Copy loaddata1.del +* and loaddata2.del from directory xml/data in UNIX and +* xml\data in Windows to the DB2 install path. +* Create a new directory "xmldatadir" in the install path +* and copy loadfile1.xml and loadfile2.xml from directory +* xml/data in UNIX and xml\data in Windows to the newly +* created xmldatadir directory. +* +* lobstoxml.sqc - How to move XML data stored as LOB to XML column +* using IMPORT/EXPORT. +* PREREQUISITE: create a directory lobdatadir in db2 +* home directory to store the data files created during +* the execution of the sample. +* +* impexpxml.sqc - How to move table data of XML data type using IMPORT +* and EXPORT. +* PREREQUISITE: copy xmldata.del in db2 home directory. +* xmldata.del can be found in xml/data directory +* create a directory xmldatadir in db2 home +* directory and copy the file xmlfiles.001.xml to +* this directory. +* +* xmlrunstats.sqc - How to perform runstats on a table with XML type +* columns. +* +* xmlindex.sqc - How to create index on an XML column. +* +* xmlconst.sqc - How to put constraints on an XML column. +* NOTE : This sample demonstrate the how to enforce the +* constraints on an XML value. There are some statement +* in the samples which are expected to fail because of +* constraint violation so The sql error SQL803N, +* SQL20305N and SQL20306N are expected. +* +* xmltrig.sqc - How to automate validation for XML documents while +* insertion or updation using XML triggers. +* PREREQUISITE: boots.xsd schema must be copied +* from /xml/data to the current +* working directory from where the sample will +* be executed. +* +* xmlintegrate.sqc - How to use XMLROW and XMLGROUP functions to publish +* relational information as XML. +* To show XMLQuery default passing mechanism. +* To show default column specification for XMLTABLE. +* +* xmlxslt.sqc - How to convert XML document from one form to another +* using XSL stylesheets +* +* xmlcheckconstraint.sqc +* - How to create check constraint on XML column validating +* XML document against single or multiple schemas. +* PREREQUISITE: boots.xsd and musicplayer.xsd schemas +* must be copied from /xml/data to the +* current working directory from where the sample will +* be executed. +* +* xmludfs.sqc - How XML data type is supported in Scalar UDFs, Sourced +* UDFs and SQL bodied UDFs. +****************************************************************************** +* +* Stored Procedures (program files that demonstrate stored procedures) +* +* simple_xmlproc_client.db2 - Client application that calls the stored +* procedure in simple_xmlproc.sqc. +* PREREQUISITE: Build the server +* "simple_xmlproc.sqc" +* and register the procedure using spcat_xml. +* For more information, See the Samples header. +* +* simple_xmlproc.sqc - Stored procedure function built and run on +* the server +* +* spcat_xml - This file is a shell script on Unix and +* batch file on windows which first calls +* simple_xmlproc_drop.db2 +* and then calls simple_xmlproc_create.db2. +* +* simple_xmlproc_create.db2 - CLP script to issue CREATE PROCEDURE +* statement +* +* simple_xmlproc_drop.db2 - CLP script to drop stored procedure from +* the catalog +* +* simple_xmlproc.exp - export file for simple_xmlproc. +* +****************************************************************************** diff --git a/xml/c/bldapp b/xml/c/bldapp new file mode 100644 index 0000000..b82a5f0 --- /dev/null +++ b/xml/c/bldapp @@ -0,0 +1,111 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldapp +# Builds C applications for Linux +# Usage: bldapp [ [ ]] + +# Select a compiler to use +CC=gcc +#CC=xlc_r + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then +BITWIDTH=64 +else +# x86 is the only native 32-bit platform +BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] + then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +# Note: some .sqc files contain no SQL but link in +# utilemb.sqc, so if you get this warning, ignore it: +# SQL0053W No SQL statements were found in the program. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 $3 $4 + # Compile the utilemb.c error-checking utility. + $CC $EXTRA_C_FLAGS -I$DB2PATH/include -c utilemb.c +else + # Compile the utilapi.c error-checking utility. + $CC $EXTRA_C_FLAGS -I$DB2PATH/include -c utilapi.c +fi + +# Compile the program. +$CC $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c + +if [ -f $1".sqc" ] +then + # Link the program with utilemb.o. + $CC $EXTRA_C_FLAGS -o $1 $1.o utilemb.o $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 +else + # Link the program with utilapi.o. + $CC $EXTRA_C_FLAGS -o $1 $1.o utilapi.o $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 +fi diff --git a/xml/c/bldrtn b/xml/c/bldrtn new file mode 100644 index 0000000..663f958 --- /dev/null +++ b/xml/c/bldrtn @@ -0,0 +1,111 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldrtn +# Builds C routines (stored procedures or UDFs) for Linux +# Usage: bldrtn [ ] + +# Select the compiler to use +CC=gcc +#CC=xlc_r + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default compiler/linker settings +EXTRA_C_FLAGS="" +SHARED_LIB_FLAG="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then +BITWIDTH=64 +else +# x86 is the only native 32-bit platform +BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] + then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +if [ "$CC" = "xlc_r" ] +then + SHARED_LIB_FLAG="-qmkshrobj" +else + SHARED_LIB_FLAG="-shared" + EXTRA_C_FLAGS="$EXTRA_C_FLAGS -fpic" +fi + +LINK_FLAGS="$EXTRA_C_FLAGS $SHARED_LIB_FLAG" + +# Set the runtime path. +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 +fi + +# Compile the program. +$CC $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c -D_REENTRANT + +# Link the program and create a shared library +$CC $LINK_FLAGS -o $1 $1.o $EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2 -lpthread + +# Copy the shared library to the function subdirectory. +# The user must have write permission to this directory. +rm -f $DB2PATH/function/$1 +cp $1 $DB2PATH/function diff --git a/xml/c/embprep b/xml/c/embprep new file mode 100644 index 0000000..56dce72 --- /dev/null +++ b/xml/c/embprep @@ -0,0 +1,63 @@ + +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: embprep +# To prep and bind C/C++ and Micro Focus COBOL embedded SQL programs +# +# Usage: embprep [ [ ]] + +# Connect to a database. +if (test $# -lt 2) +then + db2 connect to sample +elif (test $# -lt 3) +then + db2 connect to $2 +else + db2 connect to $2 user $3 using $4 +fi + +# Precompile the program. +if [ -f $1".sqc" ] +then + db2 prep $1.sqc bindfile + if [ -f utilemb.sqc ] + then + db2 prep utilemb.sqc + fi +elif [ -f $1".sqC" ] +then + db2 prep $1.sqC bindfile + if [ -f utilemb.sqC ] + then + db2 prep utilemb.sqC + fi +elif [ -f $1".sqb" ] +then + db2 prep $1.sqb bindfile target mfcob CALL_RESOLUTION DEFERRED +fi + +# Bind the program to the database. +db2 bind $1.bnd + +# Disconnect from the database. +db2 connect reset +db2 terminate diff --git a/xml/c/impexpxml.sqc b/xml/c/impexpxml.sqc new file mode 100644 index 0000000..831355a --- /dev/null +++ b/xml/c/impexpxml.sqc @@ -0,0 +1,493 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: impexpxml.sqc +** +** SAMPLE: How to move XML data using IMPORT and EXPORT with new options +** +** PREREQUISITES: +** Note: All the data files are at sqllib/xml/data directory. +** 1. Copy xmldata.del to the DB2 home directory +** 2. Create a directory "xmldatadir" in DB2 home directory and copy +** "xmlfiles.001.xml" to the "xmldatadir" directory +** +** DB2 APIs USED: +** db2Export -- Export +** db2Import -- Import +** +** SQL STATEMENTS USED: +** PREPARE +** DECLARE CURSOR +** OPEN +** FETCH +** CLOSE +** CREATE TABLE +** INSERT INTO +** DROP +** +** OUTPUT FILE: impexpxml.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +int DataExport(char *); +int TbImport(char *); + +/* support functions */ +int ExportedDataDisplay(char *); +int ImportedDataDisplay(void); + +EXEC SQL BEGIN DECLARE SECTION; + char strStmt[256]; + short cid; + SQL TYPE IS XML AS CLOB(50K) info; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + char impDataFileName[256]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO MOVE XML DATA USING EXPORT & IMPORT.\n"); + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + #if(defined(DB2NT)) + sprintf(impDataFileName, "%s%sxmldata.del", getenv("DB2PATH"), PATH_SEP); + #else /* UNIX */ + sprintf(impDataFileName, "%s%sxmldata.del", getenv("HOME"), PATH_SEP); + #endif + + rc = TbImport(impDataFileName); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if (rc != 0) + { + return rc; + } + + return 0; +} /* main */ + +int ExportedDataDisplay(char *dataFileName) +{ + struct sqlca sqlca = {0}; + FILE *fp; + char buffer[100]; + int maxChars = 100; + int numChars; + int charNb; + + fp = fopen(dataFileName, "r"); + if (fp == NULL) + { + return 1; + } + + printf("\n The content of the file '%s' is:\n", dataFileName); + printf(" "); + numChars = fread(buffer, 1, maxChars, fp); + while (numChars > 0) + { + for (charNb = 0; charNb < numChars; charNb++) + { + if (buffer[charNb] == '\n') + { + printf("\n"); + if (charNb < numChars - 1) + { + printf(" "); + } + } + else + { + printf("%c", buffer[charNb]); + } + } + numChars = fread(buffer, 1, maxChars, fp); + } + + if (ferror(fp)) + { + fclose(fp); + return 1; + } + else + { + fclose(fp); + } + + return 0; +} /* ExportedDataDisplay */ + +int ImportedDataDisplay(void) +{ + struct sqlca sqlca = {0}; + + printf("\n SELECT * FROM customer_xml ORDER BY cid\n"); + printf(" CID INFO \n"); + printf(" -------- --------------\n"); + + strcpy(strStmt, "SELECT * FROM customer_xml ORDER BY cid"); + + EXEC SQL PREPARE stmt FROM :strStmt; + EMB_SQL_CHECK("statement -- prepare"); + + EXEC SQL DECLARE c0 CURSOR FOR stmt; + + EXEC SQL OPEN c0; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c0 INTO :cid, :info; + EMB_SQL_CHECK("cursor -- fetch"); + + while (sqlca.sqlcode != 100) + { + printf(" %8d %-s\n", cid, info.data); + + EXEC SQL FETCH c0 INTO :cid, :info; + EMB_SQL_CHECK("cursor -- fetch"); + } + + EXEC SQL CLOSE c0; + + return 0; +} /* ImportedDataDisplay */ + +int DataExport(char *dataFileName) +{ + int rc = 0; + unsigned short saveschema = 1; + struct sqlca sqlca = {0}; + struct sqldcol dataDescriptor = {0}; + char actionString[256]; + struct sqllob *pAction = {0}; + char msgFileName[128]; + struct db2ExportOut outputInfo = {0}; + struct db2ExportIn inputInfo = {0}; + struct db2ExportStruct exportParmStruct = {0}; + struct sqlchar *fileTypeMod = NULL; + struct sqlu_media_entry *pPathList = {0}; + struct sqlu_location_entry *psLocationEntry = {0}; + union sqlu_media_list_targets listTargetsXmlPath = {0}, listTargetsXmlFile = {0}; + struct sqlu_media_list mediaListXmlPath = {0}, mediaListXmlFile = {0}; + char temp[256]; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" db2Export -- Export\n"); + printf("TO EXPORT DATA TO A FILE.\n"); + + printf("\n Be sure to complete all table operations and release\n"); + printf(" all locks before starting an export operation. This\n"); + printf(" can be done by issuing a COMMIT after closing all\n"); + printf(" cursors opened WITH HOLD, or by issuing a ROLLBACK.\n"); + printf(" Please refer to the 'Administrative API Reference'\n"); + printf(" for the details.\n"); + + /* export data */ + dataDescriptor.dcolmeth = SQL_METH_D; + strcpy(actionString, "SELECT Cid,Info FROM customer_xml ORDER BY Cid"); + pAction = (struct sqllob *)malloc(sizeof(sqluint32) + + sizeof(actionString) + 1); + pAction->length = strlen(actionString); + strcpy(pAction->data, actionString); + strcpy(msgFileName, "tbexport.MSG"); + + /* XML Path Specification */ + pPathList=(struct sqlu_media_entry *)malloc(sizeof(struct sqlu_media_entry)); + #if(defined(DB2NT)) + sprintf(pPathList->media_entry, "%s%sxmldatadir", getenv("DB2PATH"), PATH_SEP); + #else /* UNIX */ + sprintf(pPathList->media_entry, "%s%sxmldatadir", getenv("HOME"), PATH_SEP); + #endif + + listTargetsXmlPath.media = pPathList; + mediaListXmlPath.media_type = 'L'; + mediaListXmlPath.sessions = 1; + mediaListXmlPath.target = listTargetsXmlPath; + + /* XMLFILE base name specification */ + psLocationEntry=(struct sqlu_location_entry *)malloc(sizeof(struct sqlu_location_entry)); + strcpy(psLocationEntry->location_entry,"expxmlfile"); + listTargetsXmlFile.location = psLocationEntry; + mediaListXmlFile.media_type = 'C'; + mediaListXmlFile.sessions = 1; + mediaListXmlFile.target = listTargetsXmlFile; + + /* File Type Modifier for Export Utility */ + strcpy(temp,"XMLINSEPFILES"); + fileTypeMod = (struct sqlchar *) malloc(sizeof(short) + sizeof (temp) + 1); + fileTypeMod->length = strlen(temp); + strcpy(fileTypeMod->data,temp); + + /* XML Save Schema Option */ + inputInfo.piXmlSaveSchema = &saveschema; + + /* Export Data */ + exportParmStruct.piDataFileName = dataFileName; + exportParmStruct.piLobPathList = NULL; + exportParmStruct.piLobFileList = NULL; + exportParmStruct.piDataDescriptor = &dataDescriptor; + exportParmStruct.piActionString = pAction; + exportParmStruct.piFileType = SQL_DEL; + exportParmStruct.piFileTypeMod = fileTypeMod; + exportParmStruct.piMsgFileName = msgFileName; + exportParmStruct.iCallerAction = SQLU_INITIAL; + exportParmStruct.poExportInfoOut = &outputInfo; + exportParmStruct.piExportInfoIn = &inputInfo; + exportParmStruct.piXmlPathList = &mediaListXmlPath; + exportParmStruct.piXmlFileList = &mediaListXmlFile; + + printf("\n Export data.\n"); + printf(" client destination file name: %s\n", dataFileName); + printf(" action : %s\n", actionString); + printf(" client message file name : %s\n", msgFileName); + + /*Performing Export data */ + printf(" \n EXPORT TO expxmldata.del OF DEL XML TO xmldatadir XMLFILE expxmlfile\n"); + printf(" MODIFIED BY XMLCHAR XMLINSEPFILES XMLSAVESCHEMA \n"); + printf(" SELECT CID, INFO FROM customer_xml ORDER BY Cid\n "); + db2Export(db2Version970, + &exportParmStruct, + &sqlca); + + DB2_API_CHECK("data -- export"); + + /* free memory allocated */ + free(pAction); + free(pPathList); + free(fileTypeMod); + free(psLocationEntry); + + /* display exported data */ + rc = ExportedDataDisplay(dataFileName); + + return 0; +} /* DataExport */ + +int TbImport(char *dataFileName) +{ + int rc = 0; + int totalLength = 0; + struct sqlca sqlca = {0}; + struct sqldcol dataDescriptor = {0}; + char actionString[256]; + struct sqlchar *pAction = {0}; + char msgFileName[128]; + struct db2ImportIn inputInfo = {0}; + struct db2ImportOut outputInfo = {0}; + struct db2ImportStruct importParmStruct = {0}; + int commitcount = 10; + int whiteSpace = 1; + unsigned short xmlParse = whiteSpace; + struct sqlchar *fileTypeMod = NULL; + struct sqlu_media_entry *pPathList = {0}; + union sqlu_media_list_targets listTargetsXmlPath; + struct sqlu_media_list mediaListXmlPath = {0}; + struct db2DMUXmlValidate xmlValidate = {0}; + struct db2DMUXmlValidateXds xdsArgs = {0}; + struct db2Char defaultSchema = {0}, ignoreSchemas = {0}; + struct db2DMUXmlMapSchema mapSchemas = {0}; + struct db2Char mapFromSchema = {0}; + struct db2Char mapToSchema = {0}; + char expDataFileName[256]; + char temp[256]; + + printf("\n CREATE TABLE customer_xml(Cid INT,"); + printf("\n Info XML))\n"); + + EXEC SQL CREATE TABLE customer_xml(Cid INT, Info XML); + EMB_SQL_CHECK("customer_xml -- create"); + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" db2Import -- Import\n"); + printf("TO IMPORT DATA TO A TABLE.\n"); + + /* import table */ + dataDescriptor.dcolmeth = SQL_METH_D; + strcpy(actionString, "INSERT INTO customer_xml"); + pAction = (struct sqlchar *)malloc(sizeof(short) + sizeof(actionString) + 1); + pAction->length = strlen(actionString); + strcpy(pAction->data, actionString); + strcpy(msgFileName, "tbimport.MSG"); + + /* Setup db2ImportIn structure */ + + /* XML Path setup */ + pPathList=(struct sqlu_media_entry *)malloc(sizeof(struct sqlu_media_entry)); + #if(defined(DB2NT)) + sprintf(pPathList->media_entry, "%s%sxmldatadir", getenv("DB2PATH"), PATH_SEP); + #else /* UNIX */ + sprintf(pPathList->media_entry, "%s%sxmldatadir", getenv("HOME"), PATH_SEP); + #endif + + listTargetsXmlPath.media = pPathList; + mediaListXmlPath.media_type = 'L'; + mediaListXmlPath.sessions = 1; + mediaListXmlPath.target = listTargetsXmlPath; + + /* File Type Modifier for Import Utility */ + strcpy(temp,"XMLCHAR"); + fileTypeMod = (struct sqlchar *) malloc(sizeof(short) + sizeof (temp) + 1); + fileTypeMod->length = strlen(temp); + strcpy(fileTypeMod->data,temp); + + /* XML validate using XDS set up */ + defaultSchema.iLength = 8; + defaultSchema.pioData=malloc(9); + strcpy(defaultSchema.pioData,"customer"); + ignoreSchemas.iLength = 8; + ignoreSchemas.pioData=malloc(9); + strcpy(ignoreSchemas.pioData,"supplier"); + mapFromSchema.iLength = 7; + mapFromSchema.pioData=malloc(8); + strcpy(mapFromSchema.pioData,"product"); + mapToSchema.iLength = 8; + mapToSchema.pioData=malloc(9); + strcpy(mapToSchema.pioData,"customer"); + mapSchemas.iMapFromSchema = mapFromSchema; + mapSchemas.iMapToSchema = mapToSchema; + xdsArgs.piDefaultSchema = &defaultSchema; + xdsArgs.iNumIgnoreSchemas = 1; + xdsArgs.piIgnoreSchemas =&ignoreSchemas; + xdsArgs.iNumMapSchemas = 1; + xdsArgs.piMapSchemas = &mapSchemas; + xmlValidate.iUsing = DB2DMU_XMLVAL_XDS; + xmlValidate.piXdsArgs =&xdsArgs; + + inputInfo.iRowcount = inputInfo.iRestartcount = 0; + inputInfo.iSkipcount = inputInfo.iWarningcount = 0; + inputInfo.iNoTimeout = 0; + inputInfo.iAccessLevel = SQLU_ALLOW_NO_ACCESS; + inputInfo.piCommitcount = &commitcount; + inputInfo.piXmlParse = &xmlParse; + inputInfo.piXmlValidate = &xmlValidate; + + printf("\n Import table.\n"); + printf(" client source file name: %s\n", dataFileName); + printf(" action : %s\n", actionString); + printf(" client message file name: %s\n", msgFileName); + + importParmStruct.piFileType = SQL_DEL; + importParmStruct.piFileTypeMod = fileTypeMod; + importParmStruct.piDataFileName = dataFileName; + importParmStruct.piLobPathList = NULL; + importParmStruct.piDataDescriptor = &dataDescriptor; + importParmStruct.piActionString = pAction; + importParmStruct.piMsgFileName = msgFileName; + importParmStruct.piImportInfoIn = &inputInfo; + importParmStruct.poImportInfoOut = &outputInfo; + importParmStruct.piNullIndicators = NULL; + importParmStruct.iCallerAction = SQLU_INITIAL; + importParmStruct.piXmlPathList = &mediaListXmlPath; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" db2Import -- Import\n"); + printf("TO IMPORT DATA TO A FILE.\n"); + + /* import table */ + printf("\n IMPORT FROM xmldata.del OF DEL XML FROM xmldatadir\n"); + printf(" MODIFIED BY XMLCHAR XMLVALIDATE using XDS DEFAULT customer \n"); + printf(" IGNORE (supplier) MAP((product,customer))\n"); + printf(" INSERT INTO customer_xml \n"); + + db2Import(db2Version970, + &importParmStruct, + &sqlca); + + EXEC SQL COMMIT; + + /* free memory allocated */ + free(pAction); + free(pPathList); + free(fileTypeMod); + free(defaultSchema.pioData); + free(ignoreSchemas.pioData); + free(mapFromSchema.pioData); + free(mapToSchema.pioData); + + /* display import info */ + printf("\n Import info.\n"); + printf(" rows read : %ld\n", (int)outputInfo.oRowsRead); + printf(" rows skipped : %ld\n", (int)outputInfo.oRowsSkipped); + printf(" rows inserted : %ld\n", (int)outputInfo.oRowsInserted); + printf(" rows updated : %ld\n", (int)outputInfo.oRowsUpdated); + printf(" rows rejected : %ld\n", (int)outputInfo.oRowsRejected); + printf(" rows committed: %ld\n", (int)outputInfo.oRowsCommitted); + + /* display content of the new table */ + rc = ImportedDataDisplay(); + + #if(defined(DB2NT)) + sprintf(expDataFileName, "%s%sexpxmldata.DEL", getenv("DB2PATH"), PATH_SEP); + #else /* UNIX */ + sprintf(expDataFileName, "%s%sexpxmldata.DEL", getenv("HOME"), PATH_SEP); + #endif + + rc = DataExport(expDataFileName); + + /* drop new table */ + printf("\n DROP TABLE customer_xml\n"); + + EXEC SQL DROP TABLE customer_xml; + EMB_SQL_CHECK("customer_xml -- drop"); + + return 0; +} /* TbImport */ + diff --git a/xml/c/lobstoxml.sqc b/xml/c/lobstoxml.sqc new file mode 100644 index 0000000..2420d0d --- /dev/null +++ b/xml/c/lobstoxml.sqc @@ -0,0 +1,482 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: lobstoxml.sqc +** +** SAMPLE: How to move LOB data into an XML column using IMPORT and EXPORT +** +** PREREQUISITE: Create a directory "lobdatadir" in the DB2 home directory +** +** DB2 APIs USED: +** db2Export -- Export +** db2Import -- Import +** +** SQL STATEMENTS USED: +** PREPARE +** DECLARE CURSOR +** OPEN +** FETCH +** CLOSE +** CREATE TABLE +** INSERT INTO +** DROP +** +** OUTPUT FILE: lobstoxml.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +int DataExport(char *); +int TbImport(char *); + +/* support functions */ +int ExportedDataDisplay(char *); +int ImportedDataDisplay(void); + +EXEC SQL BEGIN DECLARE SECTION; + char strStmt[256]; + short cid; + SQL TYPE IS XML AS CLOB(50K) info; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + char dataFileName[256]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\n HOW TO MOVE LOB DATA INTO AN XML COLUMN USING IMPORT AND EXPORT.\n"); + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + #if(defined(DB2NT)) + sprintf(dataFileName, "%s%slobdata.del", getenv("DB2PATH"), PATH_SEP); + #else /* UNIX */ + sprintf(dataFileName, "%s%slobdata.del", getenv("HOME"), PATH_SEP); + #endif + + rc = DataExport(dataFileName); + rc = TbImport(dataFileName); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if (rc != 0) + { + return rc; + } + + return 0; +} /* main */ + +int ExportedDataDisplay(char *dataFileName) +{ + struct sqlca sqlca = {0}; + FILE *fp; + char buffer[100]; + int maxChars = 100; + int numChars; + int charNb; + + fp = fopen(dataFileName, "r"); + if (fp == NULL) + { + return 1; + } + + printf("\n The content of the file '%s' is:\n", dataFileName); + printf(" "); + numChars = fread(buffer, 1, maxChars, fp); + while (numChars > 0) + { + for (charNb = 0; charNb < numChars; charNb++) + { + if (buffer[charNb] == '\n') + { + printf("\n"); + if (charNb < numChars - 1) + { + printf(" "); + } + } + else + { + printf("%c", buffer[charNb]); + } + } + numChars = fread(buffer, 1, maxChars, fp); + } + + if (ferror(fp)) + { + fclose(fp); + return 1; + } + else + { + fclose(fp); + } + + return 0; +} /* ExportedDataDisplay */ + +int ImportedDataDisplay(void) +{ + struct sqlca sqlca = {0}; + + printf("\n SELECT * FROM customer_xml ORDER BY cid\n"); + printf(" CID INFO \n"); + printf(" -------- --------------\n"); + + strcpy(strStmt, "SELECT * FROM customer_xml ORDER BY cid"); + + EXEC SQL PREPARE stmt FROM :strStmt; + EMB_SQL_CHECK("statement -- prepare"); + + EXEC SQL DECLARE c0 CURSOR FOR stmt; + + EXEC SQL OPEN c0; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c0 INTO :cid, :info; + EMB_SQL_CHECK("cursor -- fetch"); + + while(sqlca.sqlcode != 100) + { + printf(" %8d %-s\n", cid, info.data); + EXEC SQL FETCH c0 INTO :cid, :info; + EMB_SQL_CHECK("cursor -- fetch"); + } + + EXEC SQL CLOSE c0; + + return 0; +} /* ImportedDataDisplay */ + +int DataExport(char *dataFileName) +{ + int rc = 0; + struct sqlca sqlca = {0}; + struct sqldcol dataDescriptor = {0}; + char actionString[256],sqlstmt[1000]; + struct sqllob *pAction = {0}; + char msgFileName[128],temp[256]; + struct db2ExportOut outputInfo = {0}; + struct db2ExportIn inputinfo = {0}; + struct db2ExportStruct exportParmStruct = {0}; + struct sqlchar *fileTypeMod = NULL; + struct sqlu_media_entry *pPathList={0}; + struct sqlu_location_entry *psLocationEntry={0}; + union sqlu_media_list_targets listTargetsLobPath={0},listTargetsLobFile={0}; + struct sqlu_media_list mediaListLobPath={0},mediaListLobFile={0}; + + /* create a table CUSTOMER_LOB with LOB column */ + printf("\n CREATE TABLE customer_lob(Cid SMALLINT,"); + printf("\n Info CLOB(50K))\n"); + + EXEC SQL CREATE TABLE customer_lob(Cid SMALLINT, Info CLOB(500)); + EMB_SQL_CHECK("customer_lob -- create"); + + /* Insert LOB data into the table */ + printf("\n Inserting multiple rows of LOB data...\n"); + + strcpy(sqlstmt,"INSERT INTO customer_lob VALUES(1001,'Kathy Smith25 EastCreekTorontoOntarioM8X-3T6416-555-1358')"); + EXEC SQL EXECUTE IMMEDIATE :sqlstmt; + +strcpy(sqlstmt,"INSERT INTO customer_lob VALUES(1002,'Jim Noodle 25 EastCreekMarkhamOntarioN9C-3T6905-555-7258')"); + EXEC SQL EXECUTE IMMEDIATE :sqlstmt; + +strcpy(sqlstmt,"INSERT INTO customer_lob VALUES(1003,'Robert Shoemaker1596 BaselineAuroraOntarioN8X-7F8905-555-7258416-555-2937905-555-8743613-555-3278')"); + EXEC SQL EXECUTE IMMEDIATE :sqlstmt; + +strcpy(sqlstmt,"INSERT INTO customer_lob VALUES(1004,'Matt Foreman1596 BaselineTorontoOntarioM3Z-5H9905-555-4789416-555-3376')"); + EXEC SQL EXECUTE IMMEDIATE :sqlstmt; + + printf("\n Multiple rows Inserted "); + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" db2Export -- Export\n"); + printf("TO EXPORT DATA TO A FILE.\n"); + + printf("\n Be sure to complete all table operations and release\n"); + printf(" all locks before starting an export operation. This\n"); + printf(" can be done by issuing a COMMIT after closing all\n"); + printf(" cursors opened WITH HOLD, or by issuing a ROLLBACK.\n"); + printf(" Please refer to the 'Administrative API Reference'\n"); + printf(" for the details.\n"); + + /* export data */ + dataDescriptor.dcolmeth = SQL_METH_D; + strcpy(actionString, "SELECT Cid, Info FROM customer_lob ORDER BY Cid"); + pAction = (struct sqllob *)malloc(sizeof(sqluint32) + + sizeof(actionString) + 1); + pAction->length = strlen(actionString); + strcpy(pAction->data, actionString); + strcpy(msgFileName, "tbexport.MSG"); + + /* LOB Path Specification */ + pPathList=(struct sqlu_media_entry *)malloc(sizeof(struct sqlu_media_entry)); + #if(defined(DB2NT)) + sprintf(pPathList->media_entry, "%s%slobdatadir", getenv("DB2PATH"), PATH_SEP); + #else /* UNIX */ + sprintf(pPathList->media_entry, "%s%slobdatadir", getenv("HOME"), PATH_SEP); + #endif + + listTargetsLobPath.media = pPathList; + mediaListLobPath.media_type = 'L'; + mediaListLobPath.sessions = 1; + mediaListLobPath.target = listTargetsLobPath; + + /* LOBFILE base name specification */ + psLocationEntry=(struct sqlu_location_entry *)malloc(sizeof(struct sqlu_location_entry)); + strcpy(psLocationEntry->location_entry,"lobfiles"); + listTargetsLobFile.location = psLocationEntry; + mediaListLobFile.media_type = 'C'; + mediaListLobFile.sessions = 1; + mediaListLobFile.target = listTargetsLobFile; + + /* File Type Modifier for Export Utility */ + strcpy(temp,"LOBSINSEPFILES"); + fileTypeMod = (struct sqlchar *) malloc(sizeof(short) + sizeof (temp) + 1); + fileTypeMod->length = strlen(temp); + strcpy(fileTypeMod->data,temp); + + /* Export Data */ + exportParmStruct.piDataFileName = dataFileName; + exportParmStruct.piLobPathList = &mediaListLobPath; + exportParmStruct.piLobFileList = &mediaListLobFile; + exportParmStruct.piDataDescriptor = &dataDescriptor; + exportParmStruct.piActionString = pAction; + exportParmStruct.piFileType = SQL_DEL; + exportParmStruct.piFileTypeMod = fileTypeMod; + exportParmStruct.piMsgFileName = msgFileName; + exportParmStruct.iCallerAction = SQLU_INITIAL; + exportParmStruct.poExportInfoOut = &outputInfo; + exportParmStruct.piExportInfoIn = NULL; + exportParmStruct.piXmlPathList = NULL; + exportParmStruct.piXmlFileList = NULL; + + printf("\n Export data.\n"); + printf(" client destination file name: %s\n", dataFileName); + printf(" action : %s\n", actionString); + printf(" client message file name : %s\n", msgFileName); + + /*Performing Export data */ + printf("\n EXPORT TO lobdata.del OF DEL LOBS TO lobdatadir LOBFILE lobfiles \n"); + printf(" MODIFIED BY LOBSINSEPFILES SELECT * FROM customer_lob \n"); + db2Export(db2Version970, + &exportParmStruct, + &sqlca); + + DB2_API_CHECK("data -- export"); + + /* free memory allocated */ + free(pAction); + free(pPathList); + free(fileTypeMod); + free(psLocationEntry); + + /* drop the table CUSTOMER_LOB */ + printf("\n DROP TABLE customer_lob"); + + EXEC SQL DROP TABLE customer_lob; + EMB_SQL_CHECK("customer_lob -- drop"); + + /* display exported data */ + rc = ExportedDataDisplay(dataFileName); + + return 0; +} /* DataExport */ + +int TbImport(char *dataFileName) +{ + int rc = 0; + int totalLength = 0; + struct sqlca sqlca = {0}; + struct sqldcol dataDescriptor = {0}; + char actionString[256]; + struct sqlchar *pAction = {0}; + char msgFileName[128]; + struct db2ImportIn inputInfo = {0}; + struct db2ImportOut outputInfo = {0}; + struct db2ImportStruct importParmStruct = {0}; + int commitcount = 10; + int whiteSpace = 1; + unsigned short xmlParse = whiteSpace; + struct sqlchar *fileTypeMod = NULL; + struct sqlu_media_entry *pPathList = {0}; + union sqlu_media_list_targets listTargetsLobPath = {0}; + struct sqlu_media_list mediaListLobPath = {0}; + struct db2DMUXmlValidate xmlValidate = {0}; + struct db2DMUXmlValidateSchema schemaArgs = {0}; + struct db2Char schemaName = {0}; + char temp[256]; + + printf("\n CREATE TABLE customer_xml(Cid INT,"); + printf("\n Info XML))\n"); + + EXEC SQL CREATE TABLE customer_xml(Cid INT, Info XML); + EMB_SQL_CHECK("customer_xml -- create"); + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" db2Import -- Import\n"); + printf("TO IMPORT DATA TO A TABLE.\n"); + + /* import table */ + dataDescriptor.dcolmeth = SQL_METH_D; + strcpy(actionString, "INSERT INTO customer_xml"); + pAction = (struct sqlchar *)malloc(sizeof(short) + sizeof(actionString) + 1); + pAction->length = strlen(actionString); + strcpy(pAction->data, actionString); + strcpy(msgFileName, "tbimport.MSG"); + + /* Setup db2ImportIn structure */ + + /* Lob Path Specification */ + pPathList=(struct sqlu_media_entry *)malloc(sizeof(struct sqlu_media_entry)); + #if(defined(DB2NT)) + sprintf(pPathList->media_entry, "%s%slobdatadir", getenv("DB2PATH"), PATH_SEP); + #else /* UNIX */ + sprintf(pPathList->media_entry, "%s%slobdatadir", getenv("HOME"), PATH_SEP); + #endif + + listTargetsLobPath.media = pPathList; + mediaListLobPath.media_type = 'L'; + mediaListLobPath.sessions = 1; + mediaListLobPath.target = listTargetsLobPath; + + /* File Type Modifier for Import Utility */ + strcpy(temp,"XMLCHAR"); + fileTypeMod = (struct sqlchar *) malloc(sizeof(short) + sizeof (temp) + 1); + fileTypeMod->length = strlen(temp); + strcpy(fileTypeMod->data,temp); + + /* Schema Specification */ + schemaName.iLength = 8; + schemaName.pioData=malloc(9); + strcpy(schemaName.pioData,"customer"); + schemaArgs.piSchema = &schemaName; + xmlValidate.iUsing = DB2DMU_XMLVAL_SCHEMA; + xmlValidate.piSchemaArgs =&schemaArgs; + + /* Import input Structure */ + inputInfo.iRowcount = inputInfo.iRestartcount = 0; + inputInfo.iSkipcount = inputInfo.iWarningcount = 0; + inputInfo.iNoTimeout = 0; + inputInfo.iAccessLevel = SQLU_ALLOW_NO_ACCESS; + inputInfo.piCommitcount = &commitcount; + inputInfo.piXmlParse = &xmlParse; + inputInfo.piXmlValidate = &xmlValidate; + + printf("\n Import table.\n"); + printf(" client source file name: %s\n", dataFileName); + printf(" action : %s\n", actionString); + printf(" client message file name: %s\n", msgFileName); + + importParmStruct.piFileType = SQL_DEL; + importParmStruct.piFileTypeMod = fileTypeMod; + importParmStruct.piDataFileName = dataFileName; + importParmStruct.piLobPathList = &mediaListLobPath; + importParmStruct.piDataDescriptor = &dataDescriptor; + importParmStruct.piActionString = pAction; + importParmStruct.piMsgFileName = msgFileName; + importParmStruct.piImportInfoIn = &inputInfo; + importParmStruct.poImportInfoOut = &outputInfo; + importParmStruct.piNullIndicators = NULL; + importParmStruct.iCallerAction = SQLU_INITIAL; + importParmStruct.piXmlPathList = NULL; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" db2Import -- Import\n"); + printf("TO IMPORT DATA TO A FILE.\n"); + + /* import table */ + printf("\n IMPORT FROM lobdata.del OF DEL LOBS FROM lobdatadir MODIFIED BY XMLCHAR \n"); + printf(" XMLVALIDATE USING SCHEMA customer INSERT INTO customer_xml \n"); + db2Import(db2Version970, + &importParmStruct, + &sqlca); + + EXEC SQL COMMIT; + + /* free memory allocated */ + free(pAction); + free(pPathList); + free(fileTypeMod); + free(schemaName.pioData); + + /* display import info */ + printf("\n Import info.\n"); + printf(" rows read : %ld\n", (int)outputInfo.oRowsRead); + printf(" rows skipped : %ld\n", (int)outputInfo.oRowsSkipped); + printf(" rows inserted : %ld\n", (int)outputInfo.oRowsInserted); + printf(" rows updated : %ld\n", (int)outputInfo.oRowsUpdated); + printf(" rows rejected : %ld\n", (int)outputInfo.oRowsRejected); + printf(" rows committed: %ld\n", (int)outputInfo.oRowsCommitted); + + + /* display content of the new table */ + rc = ImportedDataDisplay(); + + /* drop new table */ + printf("\n DROP TABLE customer_xml\n"); + + EXEC SQL DROP TABLE customer_xml; + EMB_SQL_CHECK("customer_xml -- drop"); + + return 0; +} /* TbImport */ + diff --git a/xml/c/makefile b/xml/c/makefile new file mode 100644 index 0000000..c5f39ae --- /dev/null +++ b/xml/c/makefile @@ -0,0 +1,204 @@ +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# +# MAKEFILE for XML C samples on Unix +# +# Enter one of the following commands +# +# make - Builds the program designated by +# make all - Builds all supplied sample programs +# make all_client - Builds all client samples (all programs in the +# call_rtn and client_run categories) +# make srv - Builds sample that run on the server +# (stored procedure) +# make call_rtn - Builds client programs that call stored procedure +# make client_run - Builds all programs that run completely on the +# client (not ones that call stored procedure) +# make clean - Erases intermediate files +# make cleanall - Erases all files produced in the build process +# except the original source files +# +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +############################################################################## +# 1 -- VARIABLES +############################################################################## + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + + +BLDAPP=bldapp +BLDRTN=bldrtn + + +# To connect to a remote SAMPLE database cataloged on the client machine +# with another name, update the ALIAS variable. +ALIAS=sample +# Set UID and PWD if neccesary +UID= +PWD= + +# To connect to a remote SAMPLE2 database cataloged on the client machine +# with another name, update the ALIAS2 variable. +ALIAS2=sample2 +# Set UID2 and PWD2 if neccesary +UID2=$(UID) +PWD2=$(PWD) + + +COPY=cp +ERASE=rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all (rtn + all_client) +# 2b - make all_client (call_rtn + client_run) +# 2c - make srv +# 2d - make call_rtn +# 2e - make client_run +# 2f - make clean +# 2g - make cleanall +############################################################################# + + +#**************************************************************************** +# 2a - make all +#**************************************************************************** + +all : \ + all_client + +#**************************************************************************** +# 2b - make all_client (call_rtn + client_run) +#**************************************************************************** + +all_client : \ + client_run \ + call_rtn + +#**************************************************************************** +# 2c - make srv +#**************************************************************************** + +srv : \ + simple_xmlproc + +#**************************************************************************** +# 2d - make call_rtn +#**************************************************************************** + +call_rtn : + +#**************************************************************************** +# 2e - make client_run +# +# xmldecomposition and reltoxmltype samples may fail to build if the setup +# for this sample is not run prior to make, to check setup script for sample +# please refer to README of header of the sample". +#**************************************************************************** + +client_run : \ + xmlconst xmlindex xmlinsert xmlread xmlupdel impexpxml \ + lobstoxml reltoxmltype xmlrunstats xmldecomposition \ + xmltrig xmlintegrate xmlcheckconstraint xmlxslt recxmldecomp \ + xmlload xmludfs + +#**************************************************************************** +# 2f - make clean +#**************************************************************************** + +clean : + $(ERASE) *.o *.bnd + $(ERASE) xmlconst.c xmlindex.c xmlinsert.c xmlread.c xmlupdel.c + $(ERASE) impexpxml.c lobstoxml.c reltoxmltype.c xmlrunstats.c + $(ERASE) xmldecomposition.c xmltotable.c simple_xmlproc.c + $(ERASE) xmltrig.c xmlintegrate.c xmlcheckconstraint.c xmlxslt.c + $(ERASE) recxmldecomp.c xmlload.c xmludfs.c + +#**************************************************************************** +# 2g - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) xmlconst xmlindex xmlinsert xmlread xmlupdel + $(ERASE) impexpxml lobstoxml reltoxmltype xmlrunstats + $(ERASE) xmldecomposition xmltotable simple_xmlproc xmlload + $(ERASE) xmltrig xmlintegrate xmlcheckconstraint xmlxslt recxmldecomp + $(ERASE) $DB2PATH/function/simple_xmlproc.class + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - regular samples, non-embedded SQL +# 3b - client/server samples +############################################################################# + +xmlconst : + $(BLDAPP) xmlconst +xmlindex : + $(BLDAPP) xmlindex +xmlinsert : + $(BLDAPP) xmlinsert +xmlread : + $(BLDAPP) xmlread +xmltotable : + $(BLDAPP) xmltotable +xmlupdel : + $(BLDAPP) xmlupdel +impexpxml : + $(BLDAPP) impexpxml +lobstoxml : + $(BLDAPP) lobstoxml +reltoxmltype : + $(BLDAPP) reltoxmltype +xmlrunstats : + $(BLDAPP) xmlrunstats +xmldecomposition : + $(BLDAPP) xmldecomposition +xmltrig : + $(BLDAPP) xmltrig +xmlintegrate : + $(BLDAPP) xmlintegrate +xmlcheckconstraint : + $(BLDAPP) xmlcheckconstraint +xmlxslt : + $(BLDAPP) xmlxslt +xmlload : + $(BLDAPP) xmlload +recxmldecomp : + $(BLDAPP) recxmldecomp +xmludfs: + $(BLDAPP) xmludfs + +#**************************************************************************** +# 3b - client/server samples +#**************************************************************************** + +simple_xmlproc : + $(BLDRTN) simple_xmlproc + spcat_xml diff --git a/xml/c/recxmldecomp.sqc b/xml/c/recxmldecomp.sqc new file mode 100644 index 0000000..ed619b8 --- /dev/null +++ b/xml/c/recxmldecomp.sqc @@ -0,0 +1,350 @@ +/*************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +** ************************************************************************* +** +** SAMPLE FILE NAME: recxmldecomp.sqc +** +** PURPOSE: How to register a recursive XML schema to the XSR and +** enable the same for decomposition. +** +** USER SCENARIO: The existing PurchaseOrder schema in the Sample database is +** enhanced to have new Employee tables to process the purchase orders. +** We have Recursive Schema for Employee data management, an employee +** can be a manager and himself reporting to another employee. The XML document +** contains the employee information along with department details which needs +** to be stored in relational tables for easy retrieval of data. +** +** PREREQUISITE: +** The instance document and the annotated schema should exist in the same +** directory as the sample. Copy recemp.xml, recemp.xsd from directory +** /sqllib/samples/xml/data in UNIX and +** \sqllib\samples\xml\data in Windows to the working directory. +** +** EXECUTION: i) bldapp recxmldecomp ( Build the sample) +** ii) recxmldecomp ( Run the sample) +** +** INPUTS: NONE +** +** OUTPUTS: Decomposition of XML document according to the annotations +** in recursive schema. +** +** OUTPUT FILE: recxmldecomp.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** REGISTER XMLSCHEMA +** COMPLETE XMLSCHEMA +** DECOMPOSE XML DOCUMENT +** CREATE +** SELECT +** DROP +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +**************************************************************************** +** +** SAMPLE DESCRIPTION +** +** ************************************************************************* +** 1. Register the annotated recursive XML schema. +** 2. Decompose the XML document using the registered XML schema. +** 3. Select data from the relational tables to see the decomposed data. +** *************************************************************************/ + +/* ************************************************************************** +** SETUP +** **************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; +EXEC SQL BEGIN DECLARE SECTION; + char RelSchema[1024]; + char SchemaName[1024]; + char SchemaLocation[1024]; + char PrimaryDocument[1024]; + char xmlfilename[1024]; + char documentid[1024]; + short shred = 1; + short validation = 1; + short isRelSchemaNULL = 0; + short isXMLSchemaNULL = 0; + short isDocumentIDNULL = 0; + short isXMLFileNULL = 0; + short isValidationNULL = 0; + short isReserveBLOB1NULL = -1; + short isReserveBLOB2NULL = -1; + short isReserveIntNULL = -1; + SQL TYPE IS BLOB_FILE xsdfile; + SQL TYPE IS BLOB_FILE addfile; + SQL TYPE IS BLOB_FILE xmlfile; + short in_ind = 0; + short null_ind = -1; + SQL TYPE is BLOB(1M) *xsdobjp = NULL; + SQL TYPE is BLOB(1M) *addobjp = NULL; + SQL TYPE is BLOB(2M) *xmlobjp = NULL; + char empid[20]; + char deptid[20]; + SQL TYPE IS XML AS CLOB(50K) members; + char status[1]; + char decomposition[1]; + char decomposition_version[5]; +EXEC SQL END DECLARE SECTION; + +int selectfromtable(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + FILE *testfile; + char strStmt[100]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENT\n"); + printf(" CREATE TABLE\n"); + printf("TO CREATE TABLE xdb.poemployee\n"); + + strcpy(strStmt,"CREATE TABLE xdb.poemployee (empid VARCHAR(20), deptid VARCHAR(20), members XML)"); + + EXEC SQL EXECUTE IMMEDIATE :strStmt; + EMB_SQL_CHECK("Table -- Create"); + + /* ************************************************************************** + ** 1. Register the recursive XML schema. + ** **************************************************************************/ + strcpy((char *)RelSchema, "xdb"); + strcpy((char *)SchemaName,"employee"); + strcpy((char *)SchemaLocation, "http://porder.com/employee.xsd"); + strcpy((char *)documentid, "employee001"); + strcpy((char *)PrimaryDocument,"recemp.xsd"); + strcpy((char *)xmlfilename, "recemp.xml"); + + printf("\nTHIS SAMPLE SHOWS: How to register a recursive XML schema to the XSR "); + printf("\nand enable the same for decomposition.\n\n"); + + /* Register the schema documents.*/ + strcpy(xsdfile.name, PrimaryDocument); + xsdfile.name_length = strlen(xsdfile.name); + xsdfile.file_options = SQL_FILE_READ; + if (xsdfile.name_length > 0) + { + testfile = fopen( xsdfile.name, "r" ); + if ( testfile != NULL ) + { + fclose( testfile ); + if ((xsdobjp = (struct xsdobjp_t *) + malloc (sizeof (*xsdobjp))) != NULL ) + { + memset(xsdobjp, 0, sizeof(*xsdobjp)); + EXEC SQL VALUES (:xsdfile) INTO :*xsdobjp; + } + } + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xsdfile.name); + exit(0); + } + } + /* Call the stored procedure. */ + printf("CALLING SYSPROC.XSR_REGISTER TO REGISTER THE SCHEMA\n"); + + EXEC SQL CALL SYSPROC.XSR_REGISTER (:RelSchema:in_ind, + :SchemaName:in_ind, + :SchemaLocation:in_ind, + :*xsdobjp:in_ind, + :*xsdobjp:null_ind ); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_REGISTER"); + + /* Complete schema registration with Decomposition enabled.*/ + /* COMPLETE XMLSCHEMA xdb.bookdetail ENABLE DECOMPOSITION;*/ + + EXEC SQL CALL SYSPROC.XSR_COMPLETE (:RelSchema:in_ind, + :SchemaName:in_ind, + :*xsdobjp:null_ind, + :shred); + + EMB_SQL_CHECK("CALLING SYSPROC.XSR_COMPLETE"); + + /* Perform Commit to save changes */ + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + /*Check catalog tables for information regarding registered schema. */ + EXEC SQL DECLARE c2 cursor FOR SELECT status, decomposition, decomposition_version FROM SYSIBM.SYSXSROBJECTS WHERE XSROBJECTNAME = 'EMPLOYEE'; + /* open cursor */ + EXEC SQL OPEN c2; + EMB_SQL_CHECK("cursor -- open"); + + /* fetch cursor */ + EXEC SQL FETCH c2 INTO :status, :decomposition, :decomposition_version; + EMB_SQL_CHECK("cursor -- fetch"); + while (sqlca.sqlcode != 100) + { + printf("STATUS : %.*s\n",1,status); + printf("DECOMPOSITION ENABLED : %.*s\n",1,decomposition); + printf("DECOMPOSITION VERSION : %.*s\n",5, decomposition_version); + + EXEC SQL FETCH c2 INTO :status, :decomposition, :decomposition_version; + EMB_SQL_CHECK("cursor -- fetch"); + + } + + /* close cursor */ + EXEC SQL CLOSE c2; + EMB_SQL_CHECK("cursor -- close"); + + /* ************************************************************************* + ** 2. Decompose the XML document using the registered XML schema. + ** *************************************************************************/ + + /* Decompose the XML document */ + if (strcmp(xmlfilename, "NULL") == 0) + { + isXMLFileNULL = -1; + } + else + { + strcpy(xmlfile.name, xmlfilename); + xmlfile.name_length = strlen(xmlfile.name); + xmlfile.file_options = SQL_FILE_READ; + if (xmlfile.name_length > 0) + { + testfile = fopen( xmlfile.name, "r" ); + if ( testfile != NULL ) + { + fclose( testfile ); + if ((xmlobjp = (struct xmlobjp_t *) + malloc (sizeof (*xmlobjp))) != NULL ) + { + memset(xmlobjp, 0, sizeof(*xmlobjp)); + EXEC SQL VALUES (:xmlfile) INTO :*xmlobjp; + } + }/* file opened*/ + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xmlfile.name); + exit(0); + } + } /* xmlfile.name_length>0 */ + } + + EXEC SQL CALL SYSPROC.XDBDECOMPXML (:RelSchema, + :SchemaName, + :*xmlobjp, + :documentid, + :validation:isValidationNULL, + :*xmlobjp:isReserveBLOB1NULL, + :*xmlobjp:isReserveBLOB2NULL, + :validation:isReserveIntNULL); + + EMB_SQL_CHECK("CALL SYSPROC.XDBDECOMPXML"); + + /* ************************************************************************* + ** 3. Select data from the relational tables to see the decomposed data. + ** *************************************************************************/ + + /* Select from tables to check if decomposition was successfull */ + rc = selectfromtable(); + + EXEC SQL DROP TABLE xdb.poemployee; + EMB_SQL_CHECK("XDB.POEMPLOYEE-- DROP"); + + EXEC SQL DROP XSROBJECT xdb.employee; + EMB_SQL_CHECK("XDB.EMPLOYEE-- DROP"); + + /* Reset connection to DB */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("Connect Reset"); + + return 0; +} + +int selectfromtable(void) +{ + int rc = 0; + struct sqlca sqlca; + char strStmt[100]; + + printf("\n Executing:\n"); + printf(" SELECT empid, deptid, members FROM XDB.POEMPLOYEE ORDER BY empid\n"); + printf("\n Results:\n"); + printf("-------------------------------------------------------------------------------\n"); + + /* declare cursor */ + strcpy(strStmt, "SELECT empid, deptid, members FROM xdb.poemployee ORDER BY empid"); + EXEC SQL PREPARE stmt FROM :strStmt; + EXEC SQL DECLARE c0 CURSOR FOR stmt; + + /* open cursor */ + EXEC SQL OPEN c0; + EMB_SQL_CHECK("cursor -- open"); + + /* fetch cursor */ + EXEC SQL FETCH c0 INTO :empid, :deptid, :members; + EMB_SQL_CHECK("cursor -- fetch"); + + while (sqlca.sqlcode != 100) + { + printf("EMPID : %s\n", empid); + printf("DEPTID : %s\n", deptid); + printf("MEMBERS : %s\n\n", members.data); + + EXEC SQL FETCH c0 INTO :empid, :deptid, :members; + EMB_SQL_CHECK("cursor -- fetch"); + } + + /* close cursor */ + EXEC SQL CLOSE c0; + EMB_SQL_CHECK("cursor -- close"); + + return 0; +} /* selectfromtable */ diff --git a/xml/c/reltoxmltype.sqc b/xml/c/reltoxmltype.sqc new file mode 100644 index 0000000..6675e4e --- /dev/null +++ b/xml/c/reltoxmltype.sqc @@ -0,0 +1,202 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: reltoxmltype.sqc +** +** SAMPLE: Purchase order database uses relational tables to store the orders of +** different customers. This data can be returned as an XML object to the +** application. The XML object can be created using the XML constructor +** functions on the server side. +** To achieve this, the user can +** 1. Create new tables having XML columns. (Done in set up script). +** 2. Change the relational data to XML type using constructor functions. +** 3. Insert the data in new tables +** 4. Use the query to select all PO data. +** +** PREREQUISITE: +** The relational tables that store the purchase order data will have to +** be created before this sample is executed. For this the file +** setupscript.db2 will have to be run using the command +** db2 -tvf setupscript.db2 +** +** Please make sure that you run the cleanup script after running the +** sample using following command +** db2 -tvf cleanupscript.db2 +** +** SQL STATEMENT USED: +** CREATE +** SELECT +** INSERT +** +** OUTPUT FILE: reltoxmltype.out (available in the online documentation) +** +** For more information about the sample programs, see the README file. +** +** For more information about SQL, see the "SQL Reference". +** +** For more information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, compiling, and running DB2 +** applications, refer to the DB2 application development website at +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +EXEC SQL BEGIN DECLARE SECTION; + short custid; + short ponum; + char orderdate[11]; + SQL TYPE IS XML AS CLOB(1K) purchaseorder; + SQL TYPE IS XML AS CLOB(1K) address; + SQL TYPE IS XML AS CLOB(1K) lineitem; + short purchaseorder_ind; + short address_ind; + short lineitem_ind; + +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + int charNb; + int lineNb; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* Insert data from the relational table into the XML tables. */ + EXEC SQL INSERT INTO Customerinfo_New (Custid, Address) + (SELECT Custid, + XMLDOCUMENT( + XMLELEMENT(NAME "Address", + XMLELEMENT(NAME "Name", c.Name), + XMLELEMENT(NAME "Street", c.Street), + XMLELEMENT(NAME "City", c.City), + XMLELEMENT(NAME "Province", c.Province), + XMLELEMENT(NAME "PostalCode", c.PostalCode))) + FROM CustomerInfo_relational AS C); + EMB_SQL_CHECK("Insert into -- Customerinfo_New"); + + /* Insert data from the relational table into the XML tables. */ + EXEC SQL INSERT INTO purchaseorder_new(PoNum, OrderDate, CustID, Status, LineItems) + (SELECT Po.PoNum, OrderDate, CustID, Status, + XMLDOCUMENT( + XMLELEMENT(NAME "itemlist", + XMLELEMENT(NAME "PartID", l.ProdID), + XMLELEMENT(NAME "Description", p.Description ), + XMLELEMENT(NAME "Quantity", l.Quantity), + XMLELEMENT(NAME "Price", p.Price))) + FROM purchaseorder_relational AS po, lineitem_relational AS l, + products_relational AS P + WHERE l.PoNum=po.PoNum AND l.ProdID=P.ProdID); + EMB_SQL_CHECK("Insert into -- PurchaseOrder_new"); + + /* Select the Purchase order. Declare a cursor*/ + EXEC SQL DECLARE c1 CURSOR FOR SELECT po.PoNum, po.CustId, po.OrderDate, + XMLELEMENT(NAME "PurchaseOrder", + XMLATTRIBUTES(po.CustID AS "CustID", po.PoNum AS "PoNum", + po.OrderDate AS "OrderDate", po.Status AS "Status")), + XMLELEMENT(NAME "Address", c.Address), + XMLELEMENT(NAME "lineitems", po.LineItems) + FROM PurchaseOrder_new AS po, CustomerInfo_new AS c + WHERE po.custid = c.custid + ORDER BY po.custID; + + /* open cursor */ + EXEC SQL OPEN c1; + EMB_SQL_CHECK("cursor -- open"); + + /* fetch cursor */ + EXEC SQL FETCH c1 INTO :custid, :ponum, :orderdate, :purchaseorder:purchaseorder_ind, + :address:address_ind, + :lineitem:lineitem_ind; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Print the result */ + while (sqlca.sqlcode != 100) + { + printf("\n\ncustId = %d, Purchase Order Number = %d, Order Date = %s",custid, ponum, orderdate); + printf("\n\n******Purchase Order Document :******\n"); + if(purchaseorder_ind >= 0) + { + for (charNb = 0; charNb < purchaseorder.length; charNb++) + { + printf("%c", purchaseorder.data[charNb]); + } + } + if(address_ind >= 0) + { + printf("\n\n******Address in XML format is :******\n"); + for (charNb = 0; charNb < address.length; charNb++) + { + printf("%c", address.data[charNb]); + } + } + if(lineitem_ind >= 0) + { + printf("\n\n******Line Item details in XML format is :******\n"); + for (charNb = 0; charNb < lineitem.length; charNb++) + { + printf("%c", lineitem.data[charNb]); + } + } + /* Fetch next row */ + EXEC SQL FETCH c1 INTO :custid, :ponum, :orderdate, :purchaseorder:purchaseorder_ind, + :address:address_ind, + :lineitem:lineitem_ind; + EMB_SQL_CHECK("cursor -- fetch"); + } + + /* close cursor */ + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("cursor -- close"); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if (rc != 0) + { + return rc; + } + + return 0; +} /* main */ + diff --git a/xml/c/simple_xmlproc.exp b/xml/c/simple_xmlproc.exp new file mode 100644 index 0000000..7865d3b --- /dev/null +++ b/xml/c/simple_xmlproc.exp @@ -0,0 +1 @@ +simple_proc diff --git a/xml/c/simple_xmlproc.sqc b/xml/c/simple_xmlproc.sqc new file mode 100644 index 0000000..5191cc0 --- /dev/null +++ b/xml/c/simple_xmlproc.sqc @@ -0,0 +1,213 @@ +/************************************************************************* +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +*************************************************************************** +** +** SOURCE FILE NAME: simple_xmlproc.sqc +** +** SAMPLE: Code implementation of a stored procedure Simple_XML_Proc_C +** +** The stored procedures defined in this program is called by the +** client application simple_xmlproc_client.db2. Before running +** simple_xmlproc_client.db2, build the shared library by completing +** the following steps: +** +** BUILDING THE SHARED LIBRARY: +** 1. Ensure the Database Manager Configuration file has the keyword +** KEEPFENCED set to "no". This allows shared libraries to be unloaded +** while you are developing stored procedures. You can view the file's +** settings by issuing the command: "db2 get dbm cfg". You can set +** KEEPFENCED to "no" with this command: "db2 update dbm cfg using +** KEEPFENCED no". NOTE: Setting KEEPFENCED to "no" reduces performance +** the performance of accessing stored procedures, because they have +** to be reloaded into memory each time they are called. If this is a +** concern, set KEEPFENCED to "yes", stop and then restart DB2 before +** building the shared library, by entering "db2stop" followed by +** "db2start". This forces DB2 to unload shared libraries and enables +** the build file or the makefile to delete a previous version of the +** shared library from the "sqllib/function" directory. +** 2. To build the shared library, enter "bldrtn simple_xmlproc", or use the +** makefile: "make simple_xmlproc"(UNIX) or "nmake simple_xmlproc"(Windows) +** +** CATALOGING THE STORED PROCEDURES +** 1. The stored procedures are cataloged or recataloged using "spcat_xml". +** The spcat_xml script (UNIX) or spcat_xml.bat batch file (Windows) +** connects to the database, runs simple_xmlproc_drop.db2 to uncatalog +** the stored procedures if they were previously cataloged, then runs +** simple_xmlproc_create.db2 which catalogs the stored procedures, then +** disconnects from the database. +** +** CALLING THE STORED PROCEDURES IN THE SHARED LIBRARY: +** 1. Run simple_xmlproc_client.db2: "db2 -td@ -vf simple_xmlproc_client.db2" +** +** DESCRIPTION OF FUNCTION SIMPLE_PROC: +** This function will take Customer Information ( of type XML) as input , +** finds whether the customer with cid in Customer Information exists in the +** customer table , if not this will insert the customer info with that cid +** into the customer table, and find out all the customers from the same city +** of this customer and returns the result in XML format. +** +** SQL STATEMENTS USED: +** CLOSE +** DECLARE +** FETCH +** OPEN +** SELECT +** SELECT INTO +** CREATE +** +** STRUCTURES USED: +** sqlca +** sqlda +** +** EXTERNAL DEPENDENCIES: +** This program must be built on a DB2 server. +** Ensure existence of the sample database. +** Precompile with the SQL precompiler (PREP in DB2) +** Bind to a database (BIND in DB2) +** Compile and link loop with the compiler supported on your +** platform. +** +** OUTPUT FILE: simple_xmlproc_client.out (available in the online documentation) +*************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +SQL_API_RC SQL_API_FN simple_proc ( SQLUDF_CLOB* inXML, + SQLUDF_CLOB* outXML, + sqlint32 *outReturnCode, + SQLUDF_NULLIND *inXML_ind, + SQLUDF_NULLIND *outXML_ind, + SQLUDF_NULLIND *outReturnCode_ind, + SQLUDF_TRAIL_ARGS) +{ + + EXEC SQL INCLUDE SQLCA; + + EXEC SQL BEGIN DECLARE SECTION; + sqlint64 count,custid; + SQL TYPE IS XML AS CLOB(5000) ipdata,tempXML; + char city[100]; + char insstmt1[1024],stmt1[1024],stmt2[1024],stmt3[1024],stmt4[1024],stmt5[200]; + EXEC SQL END DECLARE SECTION; + + /* Initialize the input data */ + ipdata.length = 0; + strcpy(ipdata.data," "); + tempXML.length = 0; + strcpy(tempXML.data," "); + + /* Initialize output parameters .. */ + outXML->length = 0; + strcpy(outXML->data," "); + *outXML_ind = -1; + *outReturnCode = -1; + *outReturnCode_ind = 0; + + /* Copy input parameters to host variables */ + ipdata.length = inXML->length; + strncpy(ipdata.data, inXML->data, inXML->length); + + /* find whether the customer with that Info exists in the customer table */ + sprintf(stmt1, "SELECT COUNT(*) FROM customer WHERE " + "XMLEXISTS('$info/customerinfo[@Cid=$id]' " + "PASSING by ref cast(? as XML) AS \"info\", cid as \"id\")"); + EXEC SQL PREPARE s1 FROM :stmt1 ; + EXEC SQL DECLARE cur1 CURSOR FOR s1; + EXEC SQL OPEN cur1 using :ipdata; + EXEC SQL FETCH cur1 INTO :count; + EXEC SQL CLOSE cur1; + + /* if customer doesn't exist ...... insert into the table */ + if( count < 1 ) + { + /* get the custid from the customer information */ + sprintf(stmt2,"SELECT XMLCAST( XMLQUERY('$info/customerinfo/@Cid' passing by " + "ref cast(? as XML) as \"info\") as BIGINT) FROM SYSIBM.SYSDUMMY1"); + EXEC SQL PREPARE s2 FROM :stmt2; + EXEC SQL DECLARE cur2 CURSOR FOR s2; + EXEC SQL OPEN cur2 USING :ipdata; + EXEC SQL FETCH cur2 INTO :custid; + EXEC SQL CLOSE cur2; + + /* insert into customer table with that custid */ + sprintf(insstmt1,"INSERT INTO customer(Cid, Info) VALUES(?,?)"); + EXEC SQL PREPARE insertStmt FROM :insstmt1; + EXEC SQL EXECUTE insertStmt using :custid, :ipdata; + } + + /* find the city of the customer and assign it to an application variable */ + sprintf( stmt3, "SELECT XMLCAST( XMLQUERY('$info/customerinfo//city' " + "passing by ref cast(? as XML) as \"info\") as " + "VARCHAR(100)) FROM SYSIBM.SYSDUMMY1"); + EXEC SQL PREPARE s3 FROM :stmt3; + EXEC SQL DECLARE cur3 CURSOR FOR s3; + EXEC SQL OPEN cur3 using :ipdata; + EXEC SQL FETCH cur3 INTO :city; + EXEC SQL CLOSE cur3; + + /* findout the location of customer and return as an XML document */ + sprintf(stmt4, "SELECT XMLQUERY('let $city:=$info/customerinfo//city " + "let $prov:=$info/customerinfo//prov-state return " + "{$city}{$prov} ' passing by ref cast(? as XML) as " + "\"info\") FROM SYSIBM.SYSDUMMY1"); + EXEC SQL PREPARE s4 FROM :stmt4; + EXEC SQL DECLARE cur4 CURSOR FOR s4; + EXEC SQL OPEN cur4 using :ipdata; + EXEC SQL FETCH cur4 INTO :tempXML; + EXEC SQL CLOSE cur4; + + /* assign the values to output parameters */ + outXML->length = tempXML.length; + strncpy(outXML->data, tempXML.data, tempXML.length); + *outXML_ind = 0; + + /* findout all the customers from that city and return as an XML document to caller */ + strcpy(stmt5, "XQUERY for $cust in db2-fn:xmlcolumn(\"CUSTOMER.INFO\") " + "/customerinfo/addr[city=\""); + strcat(stmt5, city); + strcat(stmt5, "\"] order by $cust/../@Cid return {$cust/../@Cid}{$cust/../name}"); + + EXEC SQL PREPARE s5 FROM :stmt5; + EXEC SQL DECLARE cur5 CURSOR FOR s5; + EXEC SQL OPEN cur5; + + *outReturnCode = sqlca.sqlcode; + *outReturnCode_ind = 0; + + return 0; +} diff --git a/xml/c/simple_xmlproc_client.db2 b/xml/c/simple_xmlproc_client.db2 new file mode 100644 index 0000000..1fb17b9 --- /dev/null +++ b/xml/c/simple_xmlproc_client.db2 @@ -0,0 +1,63 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: simple_xmlproc_client.db2 +-- +-- SAMPLE: How to call the DB2 C stored procedure contained in +-- simple_xmlproc.sqc +-- +-- To run this script from the CLP: +-- 1. EXTERNAL DEPENDENCIES: +-- Ensure existence of database for precompile purposes. +-- Ensure that the stored procedures called from this program have +-- been built and cataloged with the database (see the instructions in +-- xquery_xmlproc.sqc). +-- +-- issue the command "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- +-- For more information on the sample programs, see the README file. +-- +-- For information on developing C applications, see the C Guide +-- and Reference. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- creating procedure +CALL Simple_XML_Proc_C ( XMLPARSE(DOCUMENT ' + + Kathy Smith + + 25 EastCreek + Markham + Ontario + N9C-3T6 + + 905-566-7258 + ' PRESERVE WHITESPACE),?,?)@ +CONNECT RESET@ diff --git a/xml/c/simple_xmlproc_create.db2 b/xml/c/simple_xmlproc_create.db2 new file mode 100644 index 0000000..4fafd74 --- /dev/null +++ b/xml/c/simple_xmlproc_create.db2 @@ -0,0 +1,58 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: simple_xmlproc_create.db2 +-- +-- SAMPLE: How to catalog the DB2 C stored procedure contained in +-- simple_xmlproc.sqc +-- +-- To run this script from the CLP +-- issue the command "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- +-- For more information on the sample programs, see the README file. +-- +-- For information on developing C applications, see the C Guide +-- and Reference. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- creating procedure +CREATE PROCEDURE Simple_XML_Proc_C( IN inXML XML as CLOB(5000), + OUT outXML XML as CLOB(5000), + OUT outReturnCode INTEGER) +LANGUAGE C +PARAMETER STYLE SQL +FENCED +DYNAMIC RESULT SETS 1 +PARAMETER CCSID UNICODE +EXTERNAL NAME 'simple_xmlproc!simple_proc'@ + +CONNECT RESET@ + + diff --git a/xml/c/simple_xmlproc_drop.db2 b/xml/c/simple_xmlproc_drop.db2 new file mode 100644 index 0000000..f5a2b82 --- /dev/null +++ b/xml/c/simple_xmlproc_drop.db2 @@ -0,0 +1,50 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: simple_xmlproc_drop.db2 +-- +-- SAMPLE: How to uncatalog the DB2 C stored procedure contained in +-- simple_xmlproc.sqc +-- +-- To run this script from the CLP +-- issue the command "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- +-- For more information on the sample programs, see the README file. +-- +-- For information on developing C applications, see the C Guide +-- and Reference. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- drop the pocedure +DROP PROCEDURE Simple_XML_Proc_C ( XML as CLOB(5000), + XML as CLOB(5000), + INTEGER)@ +CONNECT RESET@ + diff --git a/xml/c/spcat_xml b/xml/c/spcat_xml new file mode 100644 index 0000000..bc6c495 --- /dev/null +++ b/xml/c/spcat_xml @@ -0,0 +1,31 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: spcat_xml +# To catalog SQC stored procedures on UNIX +# Catalogs the stored procedures in the simple_xmlproc library +# simple_xmlproc_drop.db2 uncatalogs the stored procedures if previously cataloged +# simple_xmlproc_create.db2 catologs the stored procedures +# Both CLP scripts can be run on their own +# Usage: spcat_xml + +db2 -td@ -vf simple_xmlproc_drop.db2 +db2 -td@ -vf simple_xmlproc_create.db2 + diff --git a/xml/c/utilapi.c b/xml/c/utilapi.c new file mode 100644 index 0000000..eed6364 --- /dev/null +++ b/xml/c/utilapi.c @@ -0,0 +1,359 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilapi.c +** +** SAMPLE: Error-checking utility for non-embedded SQL samples in C +** +** This utility file is compiled and linked in as an object module +** with non-embedded SQL sample programs by the supplied makefile +** and build files. It checks for and prints to the screen SQL +** warnings and errors. +** +** DB2 APIs USED: +** sqlaintp -- Get Error Message +** sqlogstt -- Get SQLSTATE Message +** sqleatin -- Attach to an Instance +** sqledtin -- Detach from an Instance +** +** Included functions: +** SqlInfoPrint - prints to the screen SQL warnings and errors +** CmdLineArgsCheck1 - checks the command line arguments, version 1 +** CmdLineArgsCheck2 - checks the command line arguments, version 2 +** CmdLineArgsCheck3 - checks the command line arguments, version 3 +** CmdLineArgsCheck4 - checks the command line arguments, version 4 +** InstanceAttach - attach to instance +** InstanceDetach - detach from instance +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "utilapi.h" + +void SqlInfoPrint(char *appMsg, struct sqlca *pSqlca, int line, char *file) +{ + int rc = 0; + char sqlInfo[1024]; + char sqlInfoToken[1024]; + char sqlstateMsg[1024]; + char errorMsg[1024]; + + if (pSqlca->sqlcode != 0 && pSqlca->sqlcode != 100) + { + strcpy(sqlInfo, ""); + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "\n---- error report -----------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } + else + { + sprintf(sqlInfoToken, + "\n---- warning report ---------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } /* endif */ + + sprintf(sqlInfoToken, "\napplication message = %s\n", appMsg); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "line = %d\n", line); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "file = %s\n", file); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "SQLCODE = %d\n\n", pSqlca->sqlcode); + strcat(sqlInfo, sqlInfoToken); + + /* get error message */ + rc = sqlaintp(errorMsg, 1024, 80, pSqlca); + if (rc > 0) /* return code is the length of the errorMsg string */ + { + sprintf(sqlInfoToken, "%s\n", errorMsg); + strcat(sqlInfo, sqlInfoToken); + } + + /* get SQLSTATE message */ + rc = sqlogstt(sqlstateMsg, 1024, 80, pSqlca->sqlstate); + if (rc > 0) + { + sprintf(sqlInfoToken, "%s\n", sqlstateMsg); + strcat(sqlInfo, sqlInfoToken); + } + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "---- end error report ------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } + else + { + sprintf(sqlInfoToken, + "---- end warning report ----------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } /* endif */ + } /* endif */ +} /* SqlInfoPrint */ + + +int CmdLineArgsCheck1(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck1 */ + +int CmdLineArgsCheck2(int argc, + char *argv[], + char nodeName[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(nodeName, ""); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(nodeName, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(nodeName, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [nodeName [userid passwd]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck2 */ + +int CmdLineArgsCheck3(int argc, + char *argv[], + char dbAlias[], + char nodeName[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(nodeName, ""); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(nodeName, ""); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 3: + strcpy(dbAlias, argv[1]); + strcpy(nodeName, argv[2]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 5: + strcpy(dbAlias, argv[1]); + strcpy(nodeName, argv[2]); + strcpy(user, argv[3]); + strcpy(pswd, argv[4]); + break; + default: + printf("\nUSAGE: %s [dbAlias [nodeName [userid passwd]]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck3 */ + +int CmdLineArgsCheck4(int argc, + char * argv[], + char dbAlias1[], + char dbAlias2[], + char user1[], + char pswd1[], + char user2[], + char pswd2[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias1, "sample"); + strcpy(dbAlias2, "sample2"); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 2: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, "sample2"); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 3: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 4: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, "sample2"); + strcpy(user1, argv[2]); + strcpy(pswd1, argv[3]); + strcpy(user2, argv[2]); + strcpy(pswd2, argv[3]); + break; + case 5: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[3]); + strcpy(pswd2, argv[4]); + break; + case 7: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[5]); + strcpy(pswd2, argv[6]); + break; + default: + printf("\nUSAGE: %s " + "[dbAlias1 [dbAlias2] [user1 pswd1 [user2 pswd2]]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck4 */ + + +int InstanceAttach(char nodeName[], + char user[], + char pswd[]) +{ + struct sqlca sqlca; + + if (strlen(nodeName) > 0) + { + printf("\n\n############## ATTACH TO THE INSTANCE: %s #######\n\n", + nodeName); + + /* attach to an instance */ + sqleatin(nodeName, user, pswd, &sqlca); + DB2_API_CHECK("instance -- attach"); + } + + return 0; +} /* CmdLineArgsCheck4 */ + + +int InstanceDetach(char * nodeName) +{ + struct sqlca sqlca; + + if (strlen(nodeName) > 0) + { + printf("\n\n############## DETACH FROM THE INSTANCE: %s #####\n\n", + nodeName); + + /* detach from an instance */ + sqledtin(&sqlca); + DB2_API_CHECK("instance -- detach"); + } + + return 0; +} /* InstanceDetach */ + + diff --git a/xml/c/utilapi.h b/xml/c/utilapi.h new file mode 100644 index 0000000..7ca1167 --- /dev/null +++ b/xml/c/utilapi.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilapi.h +** +** SAMPLE: Error-checking utility header file for utilapi.c +** +** This is the header file for the utilapi.c error-checking utility +** file. The utilapi.c file is compiled and linked in as an object +** module with non-embedded SQL sample programs by the supplied +** makefile and build files. +** +** Macros defined: +** DB2_API_CHECK(MSG_STR) +** EXPECTED_ERR_CHECK(MSG_STR) +** EXPECTED_WARN_CHECK(MSG_STR) +** +** Functions declared: +** SqlInfoPrint - prints to the screen SQL warnings and errors +** CmdLineArgsCheck1 - checks the command line arguments, version 1 +** CmdLineArgsCheck2 - checks the command line arguments, version 2 +** CmdLineArgsCheck3 - checks the command line arguments, version 3 +** CmdLineArgsCheck4 - checks the command line arguments, version 4 +** InstanceAttach - attach to instance +** InstanceDetach - detach from instance +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILAPI_H +#define UTILAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef max +#define max(A, B) ((A) > (B) ? (A) : (B)) +#endif +#ifndef min +#define min(A, B) ((A) > (B) ? (B) : (A)) +#endif + +#define USERID_SZ 128 +#define PSWD_SZ 14 + +#if (defined(DB2NT)) +#define PATH_SEP "\\" +#else /* UNIX */ +#define PATH_SEP "/" +#endif + +/* macro for DB2_API checking */ +#define DB2_API_CHECK(MSG_STR) \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ +if (sqlca.sqlcode < 0) \ +{ \ + return 1; \ +} + +/* macro for expected error checking and message */ +#define EXPECTED_ERR_CHECK(MSG_STR) \ +printf("\n-- The following error report is expected! --"); \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ + +/* macro for expected warning */ +#define EXPECTED_WARN_CHECK(MSG_STR) \ +printf("\n-- The following warning report is expected! --"); \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ + +/* functions used in ..._CHECK macros */ +void SqlInfoPrint(char *, struct sqlca *, int, char *); + +/* other functions */ +int CmdLineArgsCheck1(int, char * argv[], char *, char *, char *); +int CmdLineArgsCheck2(int, char * argv[], char *, char *, char *); +int CmdLineArgsCheck3(int, char * argv[], char *, char *, char *, char *); +int CmdLineArgsCheck4(int, char * argv[], char *, char *, + char *, char *, char *, char *); +int InstanceAttach(char * , char *, char *); +int InstanceDetach(char *); + +#ifdef __cplusplus +} +#endif + +#endif /* UTILAPI_H */ + diff --git a/xml/c/utilemb.h b/xml/c/utilemb.h new file mode 100644 index 0000000..602595f --- /dev/null +++ b/xml/c/utilemb.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilemb.h +** +** SAMPLE: Error-checking utility header file for utilemb.sqc +** +** This is the header file for the utilemb.sqc error-checking utility +** file. The utilemb.sqc file is compiled and linked in as an object +** module with embedded SQL sample programs by the supplied makefile +** and build files. +** +** Macro defined: +** EMB_SQL_CHECK(MSG_STR) +** +** Functions declared: +** TransRollback - rolls back the transaction +** DbConn - connects to the database +** DbDisconn - disconnects from the database +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILEMB_H +#define UTILEMB_H + +#include "utilapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_UID_LENGTH 18 +#define MAX_PWD_LENGTH 30 + +#ifndef max +#define max(A, B) ((A) > (B) ? (A) : (B)) +#endif +#ifndef min +#define min(A, B) ((A) > (B) ? (B) : (A)) +#endif + +#define LOBLENGTH 29 + +/* macro for embedded SQL checking */ +#define EMB_SQL_CHECK(MSG_STR) \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ +if (sqlca.sqlcode < 0) \ +{ \ + TransRollback(); \ + return 1; \ +} + +/* function used in EMB_SQL_CHECK macro */ +void TransRollback(void); + +/* other useful functions with self-explanatory names */ +int DbConn(char * , char *, char *); +int DbDisconn(char *); + +#ifdef __cplusplus +} +#endif + +#endif /* UTILEMB_H */ + diff --git a/xml/c/utilemb.sqc b/xml/c/utilemb.sqc new file mode 100644 index 0000000..7ab2196 --- /dev/null +++ b/xml/c/utilemb.sqc @@ -0,0 +1,130 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilemb.sqc +** +** SAMPLE: Error-checking utility for embedded SQL samples in C +** +** This utility file is compiled and linked in as an object module +** with embedded SQL sample programs by the supplied makefile and +** build files. It checks for and prints to the screen SQL warnings +** and errors. +** +** SQL STATEMENTS USED: +** BEGIN DECLARE SECTION +** END DECLARE SECTION +** ROLLBACK +** CONNECT +** +** Included functions: +** TransRollback - rolls back the transaction +** DbConn - connects to the database +** DbDisconn - disconnects from the database +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "utilapi.c" +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char dbAlias[15]; + char user[129]; + char pswd[15]; +EXEC SQL END DECLARE SECTION; + +void TransRollback() +{ + struct sqlca sqlca; + + /* rollback the transaction */ + printf("\n Rolling back the transaction...\n"); + + EXEC SQL ROLLBACK; + SqlInfoPrint("ROLLBACK", &sqlca, __LINE__, __FILE__); + if (sqlca.sqlcode == 0) + { + printf(" The transaction was rolled back.\n"); + } +} /* TransRollback */ + +int DbConn(char paramDbAlias[], char paramUser[], char paramPswd[]) +{ + struct sqlca sqlca; + int rc = 0; + + strcpy(dbAlias, paramDbAlias); + strcpy(user, paramUser); + strcpy(pswd, paramPswd); + + printf("\n Connecting to '%s' database...\n", dbAlias); + if (strlen(user) == 0) + { + EXEC SQL CONNECT TO :dbAlias; + EMB_SQL_CHECK("CONNECT"); + } + else + { + EXEC SQL CONNECT TO :dbAlias USER :user USING :pswd; + EMB_SQL_CHECK("CONNECT"); + } + printf(" Connected to '%s' database.\n", dbAlias); + + return 0; +} /* DbConn */ + +int DbDisconn(char *dbAlias) +{ + struct sqlca sqlca; + int rc = 0; + + printf("\n Disconnecting from '%s' database...\n", dbAlias); + + /* Commit all non-committed transactions to release database locks */ + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + + printf(" Disconnected from '%s' database.\n", dbAlias); + + return 0; +} /* DbDisconn */ + diff --git a/xml/c/xmlcheckconstraint.sqc b/xml/c/xmlcheckconstraint.sqc new file mode 100644 index 0000000..5711d86 --- /dev/null +++ b/xml/c/xmlcheckconstraint.sqc @@ -0,0 +1,797 @@ +/*************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SAMPLE FILE NAME: xmlcheckconstraint.sqc +** +** PURPOSE: The purpose of this sample is to show how to create check +** constraints on XML column. +** +** USAGE SCENARIO: Super market maintains different stores for different +** products like music players, boots, headphones. Each store sells one +** type of product, as they would want to have separate accounting or +** billing for their products. Super market application maintains a +** separate table data for each product to make his work easy.Whenever +** a customer purchases some product an entry is made in the corresponding +** table restricting the table to a particular product entry. +** Because there are multiple tables and if the manager wants to frequently +** view data from multiple tables, he creates a view on top of these product +** tables with required columns. Also, when a customer purchases 2 or +** more products, inserting data from view has made his job easy. +** Some times when he wants to get the customer address details, he uses +** "customer" table from sample database to get only valid data using +** IS VALIDATED predicate. In XML case, users can insert data into tables +** through views. But if the user wants to select data, as indexes are +** created on XML documents on base tables and not on views, it would be +** best to make use of indexes on base tables rather than using +** select on views. +** +** PREREQUISITE: +** On Unix: copy boots.xsd file from /sqllib +** /samples/xml/data directory to current directory. +** copy musicplayer.xsd file from /sqllib +** /samples/xml/data directory to current directory. +** On Windows: copy boots.xsd file from \sqllib\samples\ +** xml\data directory to current directory +** copy musicplayer.xsd file from \sqllib\ +** samples\xml\data directory to current directory +** +** EXECUTION: bldapp xmlcheckconstraint +** xmlcheckconstraint +** +** INPUTS: NONE +** +** OUTPUTS: One of the insert statements will fail because of check constraint +** violation. All other statements will succeed. +** +** OUTPUT FILE: xmlcheckconstraint.out (available in online documentation) +** +** SQL STATEMENTS USED: +** CREATE TABLE +** INSERT +** DROP +** SELECT +** SYSPROC.XSR_REGISTER +** SYSPROC.XSR_COMPLETE +** +** SQL/XML FUNCTIONS USED: +** XMLVALIDDATE +** XMLPARSE +** XMLDOCUMENT +** +***************************************************************************** +** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +***************************************************************************** +** +** SAMPLE DESCRIPTION +** +***************************************************************************** +** +** 1. Register XML schemas +** +** 2. Create tables with check constraint on XML column and insert data into +** tables. +** +** 3. Show partitioning of tables by schema. +** +** 4. Show usage of IS VALIDATED and IS NOT VALIDATED predicates. +** +** 5. Shows insert statement failure when check constraint is violated. +** +** 6. Show check constraint and view dependency on schema. +** +**************************************************************************** +** +** INCLUDE ALL HEADER FILES +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +/**************************************************************************** +** +** DECLARE HOST VARIABLES +** +*****************************************************************************/ + +EXEC SQL BEGIN DECLARE SECTION; /* Start of declare section */ + char dbAlias[700]; + char user[700]; + char pswd[700]; + sqlint32 cid; + short custid; + SQL TYPE IS XML AS CLOB( 10K ) history; + short null_ind = -1; + char RelSchema[1024]; + char SchemaName[1024]; + char SchemaLocation[1024]; + char PrimaryDocument[1024]; + short isshred=0; + SQL TYPE IS BLOB_FILE xsdfile; + SQL TYPE is BLOB(1M) *xsdobjp; + char stmt[16384]; + SQL TYPE IS XML AS BLOB( 10K ) info; +EXEC SQL END DECLARE SECTION; /* End of declare section */ + + +int main(int argc, char *argv[]) +{ + int rc = 0; + struct sqlca sqlca; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* Register boots XML schema */ + rc = registerbootsxmlschema(); + if (rc != 0) + { + return rc; + } + + /* Register musicplayer XML schema */ + rc = registermusicplayerschema(); + if (rc != 0) + { + return rc; + } + + /* Create tables with check constraints on XML column */ + checkconstraintonxmlcolumn(); + + /* Partitioning of tables by schemas */ + partitiontablesbyschema(); + + /* Shows usage of IS VALIDATED and IS NOT VALIDATED predicates */ + usageofvalidatedpredicate(); + + /* Shows insert statement failure because of schema violation */ + schemavoilation(); + + /* Shows check constraint and view dependency on schema */ + dependencyonschema(); + + /* Drop all the tables and views created */ + cleanup(); +} + +/******************************************************************** +** 1. Register XML schemas +********************************************************************/ + +int registerbootsxmlschema() +{ + struct sqlca sqlca; + FILE *testfile; + + /* Initialize host variables for schema registration */ + sprintf((char *)RelSchema,"POSAMPLE1"); + sprintf((char *)SchemaName,"boots"); + sprintf((char *)SchemaLocation, "http://posample1.org"); + sprintf((char *)PrimaryDocument,"boots.xsd"); + sprintf(xsdfile.name, PrimaryDocument); + + xsdfile.name_length = strlen(xsdfile.name); + xsdfile.file_options = SQL_FILE_READ; + + + /* read the BLOB file into a BLOB variable */ + if (xsdfile.name_length > 0) + { + testfile = fopen( xsdfile.name, "r" ); + if ( testfile != NULL ) + { + fclose( testfile ); + if ((xsdobjp = (struct xsdobjp_t *) + malloc (sizeof (*xsdobjp))) != NULL ) + { + memset(xsdobjp, 0, sizeof(*xsdobjp)); + EXEC SQL VALUES (:xsdfile) INTO :*xsdobjp; + } + } + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xsdfile.name); + exit(0); + } + } + + + printf("----------------------------------------------------------------\n"); + printf("\nFilename : %s\n",xsdfile.name); + printf("XSD Data : %s\n",xsdobjp->data); + printf("CALLING SYSPROC.XSR_REGISTER TO REGISTER THE SCHEMA %s......\n\n",SchemaName); + + /* call SYSPROC.XSR_REGISTER to register the primary schema */ + EXEC SQL CALL SYSPROC.XSR_REGISTER(:RelSchema, + :SchemaName, + :SchemaLocation, + :*xsdobjp, + :*xsdobjp:null_ind ); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_REGISTER"); + + /* call SYSPROC.XSR_COMPLETE the complete the registeration of the schema */ + printf("----------------------------------------------------------------\n"); + printf("CALLING SYSPROC.XSR_COMPLETE TO COMPLETE THE SCHEMA REGISTERATION.....\n\n"); + EXEC SQL CALL SYSPROC.XSR_COMPLETE(:RelSchema, + :SchemaName, + :*xsdobjp:null_ind, + :isshred); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_COMPLETE"); + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + printf("\nSCHEMA REGISTRATION COMPLETED SUCCESSFULLY\n"); + + free(xsdobjp); + return 0; +} /* registerxmlschema */ + +int registermusicplayerschema() +{ + struct sqlca sqlca; + FILE *testfile; + + /* Initialize host variables for schema registration */ + sprintf((char *)RelSchema,"POSAMPLE1"); + sprintf((char *)SchemaName,"musicplayer"); + sprintf((char *)SchemaLocation, "http://posample1.org"); + sprintf((char *)PrimaryDocument,"musicplayer.xsd"); + sprintf(xsdfile.name, PrimaryDocument); + + xsdfile.name_length = strlen(xsdfile.name); + xsdfile.file_options = SQL_FILE_READ; + + + /* read the BLOB file into a BLOB variable */ + if (xsdfile.name_length > 0) + { + testfile = fopen( xsdfile.name, "r" ); + if ( testfile != NULL ) + { + fclose( testfile ); + if ((xsdobjp = (struct xsdobjp_t *) + malloc (sizeof (*xsdobjp))) != NULL ) + { + memset(xsdobjp, 0, sizeof(*xsdobjp)); + EXEC SQL VALUES (:xsdfile) INTO :*xsdobjp; + } + } + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xsdfile.name); + exit(0); + } + } + printf("----------------------------------------------------------------\n"); + printf("\nFilename : %s\n",xsdfile.name); + printf("XSD Data : %s\n",xsdobjp->data); + printf("CALLING SYSPROC.XSR_REGISTER TO REGISTER THE SCHEMA %s......\n\n",SchemaName); + + /* call SYSPROC.XSR_REGISTER to register the primary schema */ + EXEC SQL CALL SYSPROC.XSR_REGISTER(:RelSchema, + :SchemaName, + :SchemaLocation, + :*xsdobjp, + :*xsdobjp:null_ind ); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_REGISTER"); + + /* call SYSPROC.XSR_COMPLETE the complete the registeration of the schema */ + printf("----------------------------------------------------------------\n"); + printf("CALLING SYSPROC.XSR_COMPLETE TO COMPLETE THE SCHEMA REGISTERATION.....\n\n"); + EXEC SQL CALL SYSPROC.XSR_COMPLETE(:RelSchema, + :SchemaName, + :*xsdobjp:null_ind, + :isshred); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_COMPLETE"); + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + printf("\nSCHEMA REGISTRATION COMPLETED SUCCESSFULLY\n"); + free(xsdobjp); + return 0; +} /* registerxmlschema */ + +/*************************************************************************** +** 2. Create table with check constraints on XML column and insert data +** into tables +****************************************************************************/ + +int checkconstraintonxmlcolumn() +{ + struct sqlca sqlca; + + printf("\nCreate table with check constraints on XML column and "); + printf(" insert data into tables\n"); + printf("\n-------------------------------------------------------\n"); + + sprintf(stmt," CREATE TABLE item (custid int, " + "xmldoc XML constraint valid_check1 " + "CHECK(xmldoc IS VALIDATED ACCORDING TO XMLSCHEMA " + "IN (ID POSAMPLE1.MUSICPLAYER, ID POSAMPLE1.BOOTS)))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE item"); + + sprintf(stmt, "INSERT INTO item " + "VALUES(100, xmlvalidate(xmlparse(document " + "'" + "" + "samsung" + " 100 watts " + "5" + "7" + "4" + "300.00" + "" + "') ACCORDING TO XMLSCHEMA ID posample1.musicplayer))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO item"); + + sprintf(stmt, "INSERT INTO item " + "VALUES (100, XMLVALIDATE(XMLPARSE(document " + "'" + "" + "adidas" + "7" + "10" + "499.9" + "" + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO item"); + + sprintf(stmt, "CREATE TABLE musicplayer (custid int, " + "xmldoc XML constraint valid_check1 " + "CHECK(xmldoc IS VALIDATED ACCORDING TO XMLSCHEMA " + "ID POSAMPLE1.MUSICPLAYER))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE musicplayer"); + + + sprintf(stmt, "INSERT INTO musicplayer " + "VALUES(100, xmlvalidate(xmlparse(document " + "'" + "" + "sony" + " 100 watts " + "5" + "3" + "4" + "200.00" + "" + "') ACCORDING TO XMLSCHEMA ID posample1.musicplayer))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO musicplayer"); + + sprintf(stmt, "CREATE TABLE boots (custid int," + "xmldoc XML constraint valid_check2 " + "CHECK(xmldoc IS VALIDATED ACCORDING TO XMLSCHEMA " + " ID posample1.boots))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE boots"); + + sprintf(stmt, "INSERT INTO boots " + "VALUES (100, XMLVALIDATE(XMLPARSE(document " + "'" + "" + "nike" + "7" + "10" + "99.9" + "" + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO boots"); + printf("\n-------------------------------------------------------\n"); + + return 0; +} /* checkconstraintonxmlcolumn */ + +/***************************************************************************** +** 3. Shows partitioning of tables by schema. +*****************************************************************************/ + +int partitiontablesbyschema() +{ + printf("\n Shows partitioning of tables by schema.\n"); + printf("\n-------------------------------------------------------\n"); + + sprintf(stmt, "CREATE VIEW view_purchases(custid, xmldoc)" + "AS (SELECT * FROM musicplayer " + "UNION ALL " + "SELECT * FROM boots)"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE VIEW view_purchases"); + + sprintf(stmt, "INSERT INTO view_purchases " + "VALUES (1001,xmlvalidate(xmlparse(document " + "'" + "" + "philips" + " 1000 watts" + "2" + "5" + "4" + "1200.00" + "" + "') ACCORDING TO XMLSCHEMA ID posample1.musicplayer))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO view_purchases"); + + sprintf(stmt, "INSERT INTO view_purchases " + "VALUES (1002, XMLVALIDATE(XMLPARSE(document " + "'" + "" + "adidas" + "10" + "2" + "199.9" + "" + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO view_purchases"); + + sprintf(stmt, "SELECT * FROM musicplayer"); + printf("\n%s\n", stmt); + + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("PREPARE s1"); + + EXEC SQL DECLARE c1 CURSOR FOR s1; + EMB_SQL_CHECK("DECLARE c1"); + + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN c1"); + + EXEC SQL FETCH c1 INTO :cid, :info; + EMB_SQL_CHECK("FETCH c1"); + + printf("\n------------------------------------------------------\n"); + printf(" cid info"); + printf("\n%d", cid); + printf(" %s\n", info.data); + printf("\n------------------------------------------------------\n"); + + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("CLOSE c1"); + + sprintf(stmt, "SELECT * FROM boots"); + printf("\nSELECT * FROM boots\n"); + + EXEC SQL PREPARE s2 FROM :stmt; + EMB_SQL_CHECK("PREPARE s2"); + + EXEC SQL DECLARE c2 CURSOR FOR s2; + EMB_SQL_CHECK("DECLARE c2 "); + + EXEC SQL OPEN c2; + EMB_SQL_CHECK("OPEN c2"); + + EXEC SQL FETCH c2 INTO :cid, :info; + EMB_SQL_CHECK("FETCH c2"); + + printf("\n------------------------------------------------------\n"); + printf(" cid info"); + printf("\n%d", cid); + printf(" %s\n", info.data); + printf("\n------------------------------------------------------\n"); + + EXEC SQL CLOSE c2; + EMB_SQL_CHECK("CLOSE c2"); + + return 0; + +} /* partitiontablesbyschema */ + +/****************************************************************** +** 4. Show usage of IS VALIDATED and IS NOT VALIDATED predicates. +******************************************************************/ + +int usageofvalidatedpredicate() +{ + struct sqlca sqlca; + + printf("\nShow usage of IS VALIDATED and IS NOT VALIDATED predicates.\n"); + printf("\n-------------------------------------------------------\n"); + + printf("\n Get customer addressess from customer table for the"); + printf(" customers who purchased boots or music players\n"); + + sprintf(stmt, "SELECT V.custid, C.info " + "FROM customer C, view_purchases V " + "WHERE V.custid = C.Cid AND C.info IS VALIDATED"); + printf("\n%s\n", stmt); + + EXEC SQL PREPARE s3 FROM :stmt; + EMB_SQL_CHECK("PREPARE s1"); + + EXEC SQL DECLARE c3 CURSOR FOR s3; + EMB_SQL_CHECK("DECLARE c1"); + + EXEC SQL OPEN c3; + EMB_SQL_CHECK("OPEN c3"); + + printf("\n--------------------------------------------------\n"); + while (sqlca.sqlcode == SQL_RC_OK) + { + memset (info.data, '\0', sizeof(info.data)+1); + + EXEC SQL FETCH c3 INTO :cid, :info; + EMB_SQL_CHECK("FETCH c1"); + + printf("cid info"); + printf("\n%d %s\n", cid, info.data); + } + printf("\n--------------------------------------------------\n"); + + EXEC SQL CLOSE c3; + EMB_SQL_CHECK("CLOSE c3"); + + printf("\n Shows usage of IS NOT VALIDATED predicate\n"); + printf("\n--------------------------------------------------\n"); + + EXEC SQL CREATE TABLE temp_table (custid int, xmldoc XML); + EMB_SQL_CHECK("CREATE TABLE"); + printf("\nCREATE TABLE temp_table (custid int, xmldoc XML)\n"); + + sprintf(stmt, "INSERT INTO temp_table " + "VALUES(1003, " + "'" + "" + "Red Tape" + "6" + "2" + "1199.9" + "" + "')"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO temp_table"); + + sprintf(stmt, "INSERT INTO temp_table " + "VALUES(1004, XMLVALIDATE(XMLPARSE(document " + "'" + "" + "Liberty" + "6" + "2" + "900.90" + "" + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO temp_table"); + + sprintf(stmt, "CREATE VIEW temp_table_details AS " + "(SELECT * FROM temp_table WHERE xmldoc IS NOT VALIDATED)"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE VIEW"); + + sprintf(stmt, "SELECT * FROM temp_table_details"); + EXEC SQL PREPARE s4 FROM :stmt; + EMB_SQL_CHECK("PREPARE s4"); + + EXEC SQL DECLARE c4 CURSOR FOR s4; + EMB_SQL_CHECK("DECLARE c4"); + + EXEC SQL OPEN c4; + EMB_SQL_CHECK("OPEN c4"); + + printf("\n Display all XML documents which doesn't have a schema \n"); + printf("\n-------------------------------------------------------\n"); + while (sqlca.sqlcode == SQL_RC_OK) + { + EXEC SQL FETCH c4 INTO :cid, :info; + EMB_SQL_CHECK("FETCH c4"); + + printf("cid info"); + printf("\n%d %s\n", cid, info.data); + } + printf("\n-------------------------------------------------------\n"); + + EXEC SQL CLOSE c4; + EMB_SQL_CHECK("CLOSE c4"); + +return 0; +} /* usageofvalidatedpredicate */ + +/************************************************************************ +** 5. Shows insert statement failure when check constraint is violated. +*************************************************************************/ + +int schemavoilation() +{ + int rc = 0; + + printf("\nShows insert statement failure when check constraint is violated."); + printf("\n-------------------------------------------------------\n"); + sprintf(stmt, "INSERT INTO musicplayer " + "VALUES (1005, XMLVALIDATE(XMLPARSE(document " + "'" + "" + "Red Tape" + "6" + "2" + "1199.9" + "" + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + + printf("\n-----------------------------------------\n"); + printf("\n Insert will fail \n"); + printf("ERROR: SQL Code = %d\n", sqlca.sqlcode); + rc = sqlaintp(stmt, sizeof(stmt), 16384, &sqlca); + printf("%s", stmt); + printf("\n-----------------------------------------\n"); + +return 0; +} /* schemavoilation */ + +/************************************************************************** +** 6. Show check constraint and view dependency on schema. +***************************************************************************/ +int dependencyonschema() +{ + + struct sqlca sqlca; + + printf("\nShow check constraint and view dependency on schema.\n"); + printf("\n----------------------------------------------------\n"); + + EXEC SQL DROP XSROBJECT POSAMPLE1.BOOTS; + EMB_SQL_CHECK("DROP XSROBJECT boots"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT "); + + sprintf(stmt, "INSERT INTO boots " + "VALUES (1006, " + "'" + "" + "Red Tape" + "6" + "2" + "1199.9" + "" + "')"); + printf("\n%s\n", stmt); + printf("\n Insert statement will succeed without any validation\n"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO boots"); + + sprintf(stmt, "INSERT INTO view_purchases " + "VALUES (1007, " + "'" + "philips" + " 1000 watts" + "2" + "5" + "4" + "1200.00" + "')"); + printf("\n%s\n", stmt); + printf("\n Insert statement will succeed without any validation\n"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO view_purchases"); + + printf("\n----------------------------------------------------\n"); + +return 0; +} /* dependencyonschema */ + +/*********************************************************************** +** CLEANUP +***********************************************************************/ + +int cleanup() +{ + printf("\nDrop all tables and views\n"); + + EXEC SQL DROP TABLE item; + EMB_SQL_CHECK("DROP TABLE item"); + + EXEC SQL DROP TABLE musicplayer; + EMB_SQL_CHECK("DROP TABLE musicplayer"); + + EXEC SQL DROP TABLE boots; + EMB_SQL_CHECK("DROP TABLE boots"); + + EXEC SQL DROP XSROBJECT POSAMPLE1.MUSICPLAYER; + EMB_SQL_CHECK("DROP XSROBJECT MUSICPLAYER"); + + EXEC SQL DROP TABLE temp_table; + EMB_SQL_CHECK("DROP TABLE temp_table"); + + EXEC SQL DROP VIEW view_purchases; + EMB_SQL_CHECK("DROP VIEW view_purchases"); + + EXEC SQL DROP VIEW temp_table_details; + EMB_SQL_CHECK("DROP VIEW temp_table_details"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT "); + + return 0; +} /* cleanup */ diff --git a/xml/c/xmlconst.sqc b/xml/c/xmlconst.sqc new file mode 100644 index 0000000..4e278a9 --- /dev/null +++ b/xml/c/xmlconst.sqc @@ -0,0 +1,309 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlconst.sqc +** +** SAMPLE: How to create an index using UNIQUE constraint on an xml column +** +** This is a tutorial sample shows where and when indexing fails when +** unique constraint is applied. +** NOTE : 1) This sample demonstrate the how to enforce the +** constraints on an XML value. There are some statement +** in the samples which are expected to fail because of +** constraint violation so The sql error SQL803N and +** SQL20305N are expected. +** +** 2) Primary key, unique constraint, or unique index are not supported +** for XML column in the Database Partitioning Feature available with +** DB2 Enterprise Server Edition for Linux, UNIX, and Windows. +** +** SQL STATEMENTS USED: +** INSERT +** INDEX +** CREATE +** DROP +** +** OUTPUT FILE: xmconst.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char dbAlias[100]; + char user[100]; + char pswd[100]; + char stmt[700]; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + struct sqlca sqlca; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("THIS SAMPLE SHOWS HOW TO CREATE AN INDEX" \ + "USING UNIQUE CONSTRAINT ON AN XML COLUMN\n"); + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* indexing XML columns using UNIQUE constraint */ + rc = TbindexUniqueConstraint1(); + rc = TbindexUniqueConstraint2(); + rc = TbindexVarcharConstraint(); + rc = TbindexVarcharConstraint1(); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if(rc != 0) + { + return rc; + } + + return 0; +} + +int TbindexUniqueConstraint1() +{ + struct sqlca sqlca; + + /* create table */ + printf("create table called company to perform index operation\n"); + + EXEC SQL CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML); + EMB_SQL_CHECK("CREATE TABLE COMPANY"); + + /* create unique index */ + printf("CREATE UNIQUE INDEX \n"); + + EXEC SQL CREATE UNIQUE INDEX empindex on company(doc) GENERATE KEY + USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE; + EMB_SQL_CHECK("CREATE UNIQUE INDEX"); + + printf("insert row1 into table \n"); + + strcpy(stmt, "insert into company values (1, 'doc1', xmlparse " + "(document ' " + " " + "Laura Brown " + "Finance'))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + printf("This insert gives Unique voilation error because of id = \"31201\" \n"); + + strcpy(stmt, " Insert into company values (1, 'doc1', xmlparse " + " (document ' " + " " + " Laura Brown " + " Finance'))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + /* drop index */ + printf("Drop the index \n"); + EXEC SQL DROP INDEX "EMPINDEX1"; + EMB_SQL_CHECK("DROP INDEX"); + + /* drop the table */ + printf("drop the table \n"); + EXEC SQL DROP TABLE "COMPANY"; + EMB_SQL_CHECK("DROP TABLE"); + +return 0; +} + + +int TbindexUniqueConstraint2() +{ +struct sqlca sqlca; + + /* create table */ + printf("create table called company to perform index operation\n"); + + EXEC SQL CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML); + EMB_SQL_CHECK("CREATE TABLE COMPANY"); + + /* create index */ + printf("create unique index \n"); + EXEC SQL CREATE UNIQUE INDEX empindex on company(doc) GENERATE + KEY USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE; + EMB_SQL_CHECK("CREATE UNIQUE INDEX"); + + printf("No index entry is inserted because \"ABCDE\" "); + printf("cannot be cast to DOUBLE data type \n"); + + strcpy(stmt, "Insert into company values (1, 'doc1', xmlparse" + "(document '" + "" + " Laura Brown" + " Finance'))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + printf("insert succeeds because no index entry is inserted "); + printf(" since \"ABCDE\" cannot be cast to the DOUBLE data type. \n"); + + strcpy(stmt, "Insert into company values (1, 'doc1', xmlparse " + " (document ' " + "Laura" + " Brown " + "Finance '))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + /* drop index */ + printf("drop the index \n"); + EXEC SQL DROP INDEX "EMPINDEX"; + EMB_SQL_CHECK("DROP INDEX"); + + /* drop table */ + printf("drop the table \n"); + + EXEC SQL DROP TABLE "COMPANY"; + EMB_SQL_CHECK("DROP TABLE"); + return 0; +} + +int TbindexVarcharConstraint() +{ + struct sqlca sqlca; + + /* create table */ + printf("create table called company to perform index operation\n"); + + EXEC SQL CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML); + EMB_SQL_CHECK("CREATE TABLE COMPANY"); + + /* create index with varchar constraint */ + printf("create unique index with varchar constraint\n"); + + EXEC SQL CREATE UNIQUE INDEX empindex1 on company(doc) + GENERATE KEY USING XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(4); + EMB_SQL_CHECK("CREATE UNIQUE INDEX"); + + printf("insert statement succeeds because the length of \"312\" < 4.\n"); + + strcpy(stmt, "Insert into company values (1, 'doc1', xmlparse " + " (document 'Laura" + " Brown" + "Finance'))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + printf("insert statement fails because the length of \"31202\" > 4. \n"); + + strcpy(stmt, " Insert into company values (1, 'doc1', xmlparse " + "(document 'Laura " + "Brown" + "Finance'))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + /* drop index */ + printf("drop index \n"); + + EXEC SQL DROP INDEX "EMPINDEX1"; + EMB_SQL_CHECK("DROP INDEX"); + + /* drop table */ + printf("drop table \n"); + EXEC SQL DROP TABLE "COMPANY"; + EMB_SQL_CHECK("DROP TABLE"); + +} + +int TbindexVarcharConstraint1() +{ + struct sqlca sqlca; + + /* create table */ + EXEC SQL CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML); + + /* insert row into table. */ + strcpy(stmt, " INSERT INTO company values (1, 'doc1', xmlparse" + "(document 'Laura" + "Brown" + "Finance'))"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + printf("insert row2 into table \n"); + + strcpy(stmt, "INSERT INTO company values (1, 'doc1', xmlparse" + "(document 'Laura" + "Brown" + "Finance'))"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + printf("create index with Varchar constraint fails because "); + printf("the length of \"31202\" > 4"); + + EXEC SQL CREATE UNIQUE INDEX empindex1 on company(doc) + GENERATE KEY USING XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(4); + EMB_SQL_CHECK("CREATE UNIQUE INDEX"); + + + /* drop index */ + EXEC SQL DROP INDEX "EMPINDEX1"; + + /* drop table */ + EXEC SQL DROP TABLE "COMPANY"; + + + return 0; +} diff --git a/xml/c/xmldecomposition.sqc b/xml/c/xmldecomposition.sqc new file mode 100644 index 0000000..f357159 --- /dev/null +++ b/xml/c/xmldecomposition.sqc @@ -0,0 +1,580 @@ +/*************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +** ************************************************************************* +** +** SAMPLE FILE NAME: xmldecomposition.sqc +** +** PURPOSE: To demonstrate annotated XML schema decomposition +** +** USER SCENARIO: +** A bookstore has books for sale and the descriptive information about +** each book is stored as an XML document. The store owner needs to store +** these details in different relational tables with referential +** constraints for easy retreival of data. +** The Bookstore that has two types of customers, retail customers and +** corporate customers. Corporate customers do bulk purchases of books +** for their company libraries. The store has a DBA for maintaining +** the database, the store manager runs queries on different tables +** to view the book sales. The information about books returned by +** customers due to damage or due to exchange with some other book +** is stored as xml document in books_returned table. At the end of +** the day a batch process decomposes these XML documents to update +** the books available status with the latest information. The batch +** process uses the DECOMPOSE XML DOCUMENTS command to decompose +** binary or XML column data into relational tables. +** +** SOLUTION: +** The store manager must have an annotated schema based on which the XML data +** can be decomposed. Once a valid annotated schema for the instance document +** is ready, it needs to be registered with the XML schema repository with +** the decomposition option enabled. Also, the tables in which the data will be +** decomposed must exist before the schema is registered. The user can +** decompose the instance documents and store the data in the relational +** tables using annotated XML Decomposition. +** +** +** PREREQUISITE: +** The instance documents and the annotated schema must exist in the same +** directory as the sample. +** Copy bookdetails.xsd, booksreturned.xsd, bookdetails.xml, +** booksreturned.del, booksreturned1.xml, booksreturned2.xml, booksreturned3.xml, +** setupfordecomposition.db2 and cleanupfordecomposition.db2 from directory +** /sqllib/samples/xml/data in UNIX and +** \sqllib\samples\xml\data in Windows to the working directory. +** +** EXECUTION: i) db2 -tvf setupfordecomposition.db2 (setup script +** to create the required tables. +** ii) bldapp xmldecomposition (Build the sample) +** iii) xmldecomposition (Run the sample) +** iv) db2 -tvf cleanupfordecomposition.db2 (clean up +** script to drop all the objects created) +** +** INPUTS: NONE +** +** OUTPUTS: Decomposition of XML document according to the dependencies +** specified in the annotated XML schema. +** +** OUTPUT FILE: xmldecomposition.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** REGISTER XMLSCHEMA +** COMPLETE XMLSCHEMA +** DECOMPOSE XML DOCUMENT +** CREATE +** SELECT +** DROP +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +**************************************************************************** +** +** SAMPLE DESCRIPTION +** +** ************************************************************************* +** 1. Register the annotated XML schema. +** 2. Decompose the XML documents using the registered XML schema. +** 3. Select data from the relational tables to see decomposed data. +** *************************************************************************/ + +/* ************************************************************************** +** SETUP ** execute setupfordecomposition.db2 +** **************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; +EXEC SQL BEGIN DECLARE SECTION; + char RelSchema[1024]; + char SchemaName[1024]; + char SchemaLocation[1024]; + char PrimaryDocument[1024]; + char xmlfilename[1024]; + char documentid[1024]; + short shred = 1; + short validation = 1; + short isRelSchemaNULL = 0; + short isXMLSchemaNULL = 0; + short isDocumentIDNULL = 0; + short isXMLFileNULL = 0; + short isValidationNULL = 0; + short isReserveBLOB1NULL = -1; + short isReserveBLOB2NULL = -1; + short isReserveIntNULL = -1; + SQL TYPE IS BLOB_FILE xsdfile; + SQL TYPE IS BLOB_FILE addfile; + SQL TYPE IS BLOB_FILE xmlfile; + short in_ind = 0; + short null_ind = -1; + SQL TYPE is BLOB(1M) *xsdobjp = NULL; + SQL TYPE is BLOB(1M) *addobjp = NULL; + SQL TYPE is BLOB(2M) *xmlobjp = NULL; + char isbn[15]; + short chptnum; + char chpttittle[50]; + char chptcontent[1000]; + short authid; + char book_title[50]; + char authname[50]; + short no_of_copies=0; + float price=0; + char status[1]; + char decomposition[1]; + char decomposition_version[5]; + char query[2000]; + SQL TYPE is CLOB(2000) *hquery = NULL; + short hquery_ind = 0; + short validate_ind = 0; + short commitcount_ind = 0; + short allowaccess_ind = 0; + short continueonerror_ind = 0; + short totalDoc_ind=-1, totalDecomp_ind=-1, errorReport_ind=-1; + sqlint32 validate; + sqlint32 commitcount; + sqlint32 allowaccess; + sqlint32 totalDoc, totalDecomp; + short continueonerror; + SQL TYPE is BLOB(500K) *errorReport = NULL; + SQL TYPE is BLOB(64) reservedBLOB; +EXEC SQL END DECLARE SECTION; + +int selectfromalltables(void); +int selectfrombooksavail(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + FILE *testfile; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + errorReport = (struct errorReport_t *) malloc (5000); + + printf("\nTHIS SAMPLE SHOWS HOW TO DECOMPOSE XML DATA \n"); + + /* Register the schema bookdetailss*/ + printf("\n/*************************************************************************"); + printf("\n Register the XML schema bookdetails"); + printf("\n*************************************************************************/"); + strcpy((char *)RelSchema, "xdb"); + strcpy((char *)SchemaName,"bookdetails"); + strcpy((char *)SchemaLocation, "http://bookdetailsschema.com/bookdetails.xsd"); + strcpy((char *)PrimaryDocument,"bookdetails.xsd"); + strcpy((char *)xmlfilename, "bookdetails.xml"); + strcpy((char *)documentid, "bookdetails001"); + rc = registerxmlschema(); + + /* Decompose a single XML document */ + printf("\n/*************************************************************************"); + printf("\n Decompose a single XML document using the registered XML schema."); + printf("\n*************************************************************************/"); + rc = singlexmldecompose(); + + /* Register the schema booksreturned*/ + printf("\n/*************************************************************************"); + printf("\n Register the XML schema booksreturned"); + printf("\n*************************************************************************/"); + strcpy((char *)RelSchema, "xdb"); + strcpy((char *)SchemaName,"booksreturned"); + strcpy((char *)SchemaLocation, "http://bookdetailsschema.com/booksreturned.xsd"); + strcpy((char *)PrimaryDocument,"booksreturned.xsd"); + rc = registerxmlschema(); + + printf("\n/*************************************************************************"); + printf("\n Decompose XML documents from an XML column."); + printf("\n*************************************************************************/"); + strcpy(query,"SELECT customerID, booksreturned FROM xdb.books_returned"); + hquery = (struct hquery_t *) malloc (strlen(query)+100); + hquery->length = strlen (query); + strcpy (hquery->data, query); + rc = bulkxmldecompose(); + free(hquery); + + printf("\n/*************************************************************************"); + printf("\n Decompose XML documents from a BLOB column."); + printf("\n*************************************************************************/"); + strcpy(query,"SELECT supplierID, booksinfo from xdb.books_received_BLOB"); + hquery = (struct hquery_t *) malloc (strlen(query)+100); + hquery->length = strlen (query); + strcpy (hquery->data, query); + rc = bulkxmldecompose(); + free(hquery); + + printf("\n/*************************************************************************"); + printf("\n Decompose XML documents from an XML column resulted by Join operation."); + printf("\n*************************************************************************/"); + strcpy(query,"SELECT id, data FROM( SELECT br.customerID as id, br.booksreturned AS info FROM xdb.books_returned as br,xdb.books_received as bc WHERE XMLEXISTS('$bi/books/book[@isbn] = $bid/books/book[@isbn]' PASSING br.booksreturned as \"bi\", bc.booksinfo as \"bid\")) AS temp(id,data) "); + hquery = (struct hquery_t *) malloc (strlen(query)+100); + hquery->length = strlen (query); + strcpy (hquery->data, query); + rc = bulkxmldecompose(); + free(hquery); + + printf("\n/*************************************************************************"); + printf("\n Decompose XML documents from an XML column resulted by union operation."); + printf("\n*************************************************************************/"); + strcpy(query,"SELECT id, data FROM(SELECT customerID as cid, booksreturned AS info FROM xdb.books_returned WHERE XMLEXISTS('$bk/books/book[author=\"Carl\"]' PASSING booksreturned AS \"bk\") UNION ALL SELECT supplierID as sid, booksinfo AS books FROM xdb.books_received WHERE XMLEXISTS('$br/books/book[author=\"Carl\"]' PASSING booksinfo AS \"br\")) AS temp(id,data)"); + hquery = (struct hquery_t *) malloc (strlen(query)+100); + hquery->length = strlen (query); + strcpy (hquery->data, query); + rc = bulkxmldecompose(); + free(hquery); + + /* Reset connection to DB */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("Connect Reset"); + + free(errorReport); + return 0; +} + +int selectfromalltables(void) +{ + int rc = 0; + struct sqlca sqlca; + + printf("\n Executing:\n"); + printf("-------------------------------------------------------------------------------\n"); + printf(" SELECT ISBN, chptnum, chpttitle, chptcontent FROM XDB.BOOK_CONTENTS\n"); + printf("\n Results:\n"); + printf("-------------------------------------------------------------------------------\n"); + /* declare cursor */ + EXEC SQL DECLARE c0 CURSOR FOR SELECT isbn, chptnum, chpttitle, chptcontent + FROM XDB.BOOK_CONTENTS; + /* open cursor */ + EXEC SQL OPEN c0; + EMB_SQL_CHECK("cursor -- open"); + + /* fetch cursor */ + EXEC SQL FETCH c0 INTO :isbn, :chptnum, :chpttittle, :chptcontent; + EMB_SQL_CHECK("cursor -- fetch"); + + while (sqlca.sqlcode != 100) + { + printf("ISBN : %s\n", isbn); + printf("CHAPTER NUMBER : %d\n", chptnum); + printf("CHAPTER TITLE : %s\n", chpttittle); + printf("CHAPTER CONTENT : %s\n", chptcontent); + + EXEC SQL FETCH c0 INTO :isbn, :chptnum, :chpttittle, :chptcontent; + EMB_SQL_CHECK("cursor -- fetch"); + } + + /* close cursor */ + EXEC SQL CLOSE c0; + EMB_SQL_CHECK("cursor -- close"); + + printf("\n-------------------------------------------------------------------------------\n"); + + /* Select from Second table */ + printf("\n Executing:\n"); + printf("-------------------------------------------------------------------------------\n"); + printf(" SELECT authid, isbn, book_title FROM ADMIN.BOOK_AUTHOR WHERE authid=532\n"); + printf("\n Results:\n"); + printf("-------------------------------------------------------------------------------\n"); + /* declare cursor */ + EXEC SQL DECLARE c1 CURSOR FOR SELECT authid, isbn, book_title + FROM ADMIN.BOOK_AUTHOR WHERE authid=532; + /* open cursor */ + EXEC SQL OPEN c1; + EMB_SQL_CHECK("cursor -- open"); + + /* fetch cursor */ + EXEC SQL FETCH c1 INTO :authid, :isbn, :book_title; + EMB_SQL_CHECK("cursor -- fetch"); + + while (sqlca.sqlcode != 100) + { + printf("AUTHID : %d\n", authid); + printf("ISBN : %s\n", isbn); + printf("BOOK TITLE : %s\n", chpttittle); + + EXEC SQL FETCH c1 INTO :authid, :isbn, :book_title; + EMB_SQL_CHECK("cursor -- fetch"); + } + + /* close cursor */ + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("cursor -- close"); + + printf("\n-------------------------------------------------------------------------------\n"); + selectfrombooksavail(); + + return 0; +} /* selectfromalltables */ + + +int selectfrombooksavail(void) +{ + + int rc = 0; + struct sqlca sqlca; + + printf("\n Executing:\n"); + printf("-------------------------------------------------------------------------------\n"); + printf(" SELECT isbn, book_title, authid, authname, price, no_of_copies FROM XDB.BOOKS_AVAIL\n"); + printf("\n Results:\n"); + printf("-------------------------------------------------------------------------------\n"); + /* declare cursor */ + EXEC SQL DECLARE c11 CURSOR FOR SELECT isbn, book_title, authid, authname, price, no_of_copies FROM XDB.BOOKS_AVAIL; + /* open cursor */ + EXEC SQL OPEN c11; + EMB_SQL_CHECK("cursor -- open"); + + /* fetch cursor */ + EXEC SQL FETCH c11 INTO :isbn, :book_title, :authid, :authname, :price, :no_of_copies; + EMB_SQL_CHECK("cursor -- fetch"); + + while (sqlca.sqlcode != 100) + { + printf("\nISBN : %s\n", isbn); + printf("BOOK TITLE : %s\n", book_title); + printf("AUTHOR ID : %d\n", authid); + printf("AUTHOR NAME : %s\n", authname); + printf("PRICE : %f\n", price); + printf("NO OF COPIES : %d\n", no_of_copies); + + EXEC SQL FETCH c11 INTO :isbn, :book_title, :authid, :authname, :price, :no_of_copies; + EMB_SQL_CHECK("cursor -- fetch"); + } + + /* close cursor */ + EXEC SQL CLOSE c11; + EMB_SQL_CHECK("cursor -- close"); + + printf("\n-------------------------------------------------------------------------------\n"); + EXEC SQL DELETE FROM XDB.BOOKS_AVAIL; + EMB_SQL_CHECK("delete "); + +return 0; + +} /* selectfrombooksavail */ + +int registerxmlschema() +{ + struct sqlca sqlca; + FILE *testfile; + + short isshred=1; + strcpy(xsdfile.name, PrimaryDocument); + xsdfile.name_length = strlen(xsdfile.name); + xsdfile.file_options = SQL_FILE_READ; + + /* read the BLOB file into a BLOB variable */ + if (xsdfile.name_length > 0) + { + testfile = fopen( xsdfile.name, "r" ); + if ( testfile != NULL ) + { + fclose( testfile ); + if ((xsdobjp = (struct xsdobjp_t *) + malloc (sizeof (*xsdobjp))) != NULL ) + { + memset(xsdobjp, 0, sizeof(*xsdobjp)); + EXEC SQL VALUES (:xsdfile) INTO :*xsdobjp; + } + } + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xsdfile.name); + exit(0); + } + } + + + printf("\nCALLING SYSPROC.XSR_REGISTER TO REGISTER THE SCHEMA %s......\n\n",SchemaName); + + /* call SYSPROC.XSR_REGISTER to register the primary schema */ + EXEC SQL CALL SYSPROC.XSR_REGISTER (:RelSchema:in_ind, + :SchemaName:in_ind, + :SchemaLocation:in_ind, + :*xsdobjp:in_ind, + :*xsdobjp:null_ind ); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_REGISTER"); + + + /* call SYSPROC.XSR_COMPLETE the complete the registeration of the schema */ + printf("\n----------------------------------------------------------------\n"); + printf("CALLING SYSPROC.XSR_COMPLETE TO COMPLETE THE SCHEMA REGISTERATION.....\n\n"); + EXEC SQL CALL SYSPROC.XSR_COMPLETE (:RelSchema:in_ind, + :SchemaName:in_ind, + :*xsdobjp:null_ind, + :shred); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_COMPLETE"); + EXEC SQL COMMIT; + + /*Check catalog tables for information regarding registered schema. */ + EXEC SQL DECLARE c2 cursor FOR SELECT status, decomposition, decomposition_version FROM SYSIBM.SYSXSROBJECTS WHERE XSROBJECTNAME IN ('BOOKDETAILS', 'BOOKSRETURNED'); + + /* open cursor */ + EXEC SQL OPEN c2; + EMB_SQL_CHECK("cursor -- open"); + + /* fetch cursor */ + EXEC SQL FETCH c2 INTO :status, :decomposition, :decomposition_version; + EMB_SQL_CHECK("cursor -- fetch"); + + while (sqlca.sqlcode != 100) + { + printf("STATUS : %s\n", status); + printf("DECOMPOSITION ENABLED : %s\n", decomposition); + printf("DECOMPOSITION VERSION : %s\n", decomposition_version); + + EXEC SQL FETCH c2 INTO :status, :decomposition, :decomposition_version; + EMB_SQL_CHECK("cursor -- fetch"); + } + + /* close cursor */ + EXEC SQL CLOSE c2; + EMB_SQL_CHECK("cursor -- close"); + + /* Perform Commit to save changes */ + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + return 0; +} /* registerxmlschema */ + +int singlexmldecompose() +{ + +FILE *testfile; + + /* Decompose the XML document */ + if (strcmp(xmlfilename, "NULL") == 0) + { + isXMLFileNULL = -1; + } + else + { + strcpy(xmlfile.name, xmlfilename); + xmlfile.name_length = strlen(xmlfile.name); + xmlfile.file_options = SQL_FILE_READ; + if (xmlfile.name_length > 0) + { + testfile = fopen( xmlfile.name, "r" ); + if ( testfile != NULL ) + { + fclose( testfile ); + if ((xmlobjp = (struct xmlobjp_t *) + malloc (sizeof (*xmlobjp))) != NULL ) + { + memset(xmlobjp, 0, sizeof(*xmlobjp)); + EXEC SQL VALUES (:xmlfile) INTO :*xmlobjp; + } + }/* file opened*/ + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xmlfile.name); + exit(0); + } + } /* xmlfile.name_length>0 */ + } + + EXEC SQL CALL SYSPROC.XDBDECOMPXML (:RelSchema, + :SchemaName, + :*xmlobjp, + :documentid, + :validation:isValidationNULL, + :*xmlobjp:isReserveBLOB1NULL, + :*xmlobjp:isReserveBLOB2NULL, + :validation:isReserveIntNULL); + + EMB_SQL_CHECK("CALL SYSPROC.XDBDECOMPXML"); + + /* Select from tables to check if decomposition was successfull */ + selectfromalltables(); +} + + + +int bulkxmldecompose() +{ + + int rc = 0; + validate = 1; + commitcount = 0; + allowaccess = 0; + continueonerror = 0; + + printf("\n %s",hquery->data); + /* Call the stored procedure. */ + printf("\n Calling SYSPROC.XDB_DECOMP_XML_FROM_QUERY...\n"); + EXEC SQL CALL SYSPROC.XDB_DECOMP_XML_FROM_QUERY + (:RelSchema:in_ind, + :SchemaName:in_ind, + :*hquery:hquery_ind, + :validate:validate_ind, + :commitcount:commitcount_ind, + :allowaccess:allowaccess_ind, + :reservedBLOB:null_ind, + :reservedBLOB:null_ind, + :continueonerror:continueonerror_ind, + :totalDoc:totalDoc_ind, + :totalDecomp:totalDecomp_ind, + :*errorReport:errorReport_ind + ); + EMB_SQL_CHECK("CALL SYSPROC.SYSPROC.XDB_DECOMP_XML_FROM_QUERY"); + EXEC SQL COMMIT; + + if (totalDoc_ind != -1) + printf ("Total XML documents = %d\n", totalDoc); + if (totalDecomp_ind != -1) + printf ("Total XML documents decomposed = %d\n", totalDecomp); + if (errorReport_ind == -1) + { + printf ("error report length = %d\n", errorReport->length); + printf ("error report = %s\n", errorReport->data); + } + + /* Select from BOOKS_AVAIL table to check if decomposition was successfull */ + selectfrombooksavail(); + +} diff --git a/xml/c/xmlindex.sqc b/xml/c/xmlindex.sqc new file mode 100644 index 0000000..9e25657 --- /dev/null +++ b/xml/c/xmlindex.sqc @@ -0,0 +1,449 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlindex.sqc +** +** SAMPLE: How to create an index on an xml column +** +** This is a tutorial sample showing basic operation on creating an +** index on xml column +** +** SQL STATEMENTS USED: +** INSERT +** INDEX +** CREATE +** DROP +** +** OUTPUT FILE: xmlindex.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char dbAlias[700]; + char user[700]; + char pswd[700]; + char stmt[700]; + char stmt1[700]; + SQL TYPE IS XML AS CLOB( 10K ) salary; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob1; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + struct sqlca sqlca; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("THIS SAMPLE SHOWS HOW TO CREATE AN INDEX ON AN XML COLUMN\n"); + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* create table */ + printf("create table called company to perform index operation\n"); + EXEC SQL CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML); + EMB_SQL_CHECK("CREATE TABLE COMPANY"); + + + /* insert into row1 into table company */ + + printf("insert row1 into company \n"); + strcpy(stmt, "INSERT INTO COMPANY VALUES(1, 'doc1', xmlparse" + " (document ' " + " Laura Brown " + " Finance " + " '))"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + /* insert row2 into table company */ + + printf("insert row2 into table company \n"); + strcpy(stmt, "Insert into company values (2, 'doc2', xmlparse " + "(document ' " + "ChrisMurphy " + "Marketing " + "NicoleMurphy " + "Sales'))"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO COMPANY"); + + printf("\nXQUERY STATEMENT CANNOT BE EXECUTED STATICALLY."); + printf("\nTO EMBED AN XQUERY STATEMENT, APPLICATION SHOULD MAKE USE OF DYNAMIC SQL LIKE"); + printf("\n PREPARE, DECLARE CURSOR, OPEN AND FETCH STATEMENT"); + printf("OR XMLQUERY FUNCTION WHICH"); + printf("\nCAN BE EMBEDDED STATICALLY\n"); + + + /* create index on attribute */ + + printf("\n\ncreate index on attribute \n"); + printf("----------------------------\n"); + EXEC SQL CREATE INDEX empindex1 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@*' AS SQL VARCHAR(15) ; + EMB_SQL_CHECK("CREATE INDEX"); + + + /* example query using above index */ + sprintf(stmt, "XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + " /company/emp[@id='42366'] return $i/name"); + + EXEC SQL PREPARE s1 from :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c1 CURSOR FOR s1; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c1; + EMB_SQL_CHECK("cursor -- open"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + xmlblob.length = 0; + EXEC SQL FETCH c1 into :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + printf("\n\n\n%s\n",xmlblob.data); + /* Display results */ + } + + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("cursor -- close"); + + + /* create index with self or descendent forward axis */ + + printf("\n\ncreate index with self or descendent forward axis\n"); + printf("------------------------------------------------------\n"); + EXEC SQL CREATE INDEX empindex2 on company(doc) GENERATE KEY USING + XMLPATTERN '//@salary' AS SQL DOUBLE; + EMB_SQL_CHECK("CREATE INDEX"); + + sprintf(stmt, "XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + " /company/emp[@salary > 35000] return {$i/@salary} "); + + EXEC SQL PREPARE s2 from :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c2 CURSOR FOR s2; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c2; + EMB_SQL_CHECK("cursor -- open"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + EXEC SQL FETCH c2 into :salary; + EMB_SQL_CHECK("cursor -- fetch"); + printf("\n\n\n%s\n",salary.data); + /* Display results */ + } + + + EXEC SQL CLOSE c2; + EMB_SQL_CHECK("cursor -- close"); + + /* create index on a text node */ + + printf("\n\ncreate index on a text node \n"); + printf("----------------------------------\n"); + EXEC SQL CREATE INDEX empindex3 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/dept/text()' AS SQL VARCHAR(30); + EMB_SQL_CHECK("CREATE INDEX"); + + sprintf(stmt, "XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + "/company/emp[dept/text()='Finance' or dept/" + "text()='Marketing'] return $i/name"); + + EXEC SQL PREPARE s3 from :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c3 CURSOR FOR s3; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c3; + EMB_SQL_CHECK("cursor -- open"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + xmlblob.length = 0; + EXEC SQL FETCH c3 into :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + printf("\n\n\n%s\n",xmlblob.data); + /* Display results */ + } + + EXEC SQL CLOSE c3; + EMB_SQL_CHECK("cursor -- close"); + + + /* create index when 2 paths are qualified by an xml pattern */ + + printf("\n\ncreate index when 2 paths are qualified by an xml pattern\n"); + printf("--------------------------------------------------------------\n"); + EXEC SQL CREATE INDEX empindex4 on company(doc) GENERATE KEY USING + XMLPATTERN '//@id' AS SQL VARCHAR(25); + EMB_SQL_CHECK("CREATE INDEX"); + + sprintf(stmt, "XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + "/company/emp[@id='31201'] return $i/name"); + sprintf(stmt1, "XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + " /company/emp/dept[@id='K55'] return $i/name "); + + EXEC SQL PREPARE s5 from :stmt; + EXEC SQL PREPARE s4 from :stmt1; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c5 CURSOR FOR s5; + EXEC SQL DECLARE c4 CURSOR FOR s4; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c5; + EXEC SQL OPEN c4; + EMB_SQL_CHECK("cursor -- open"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + xmlblob.length = 0; + xmlblob1.length = 0; + EXEC SQL FETCH c5 into :xmlblob; + EXEC SQL FETCH c4 into :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + printf("\n\n\n%s\n",xmlblob.data); + printf("\n\n\n%s\n",xmlblob1.data); + /* Display results */ + } + + EXEC SQL CLOSE c4; + EXEC SQL CLOSE c5; + EMB_SQL_CHECK("cursor -- close"); + + + /* create index with namespace */ + + printf("\n\ncreate index with namespace \n"); + printf("----------------------------------\n"); + EXEC SQL CREATE INDEX empindex5 on company(doc) GENERATE KEY USING + XMLPATTERN 'declare default element namespace \ + "http://www.mycompany.com/";declare namespace \ + m="http://www.mycompanyname.com/";/company/emp/@m:id' + AS SQL VARCHAR(30); + EMB_SQL_CHECK("CREATE INDEX"); + + + /* create indexes with same XMLPATTERN but with different data types */ + + printf("\n\ncreate indexes with different data types \n"); + printf("----------------------------------------------\n"); + EXEC SQL CREATE INDEX empindex7 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(10); + EXEC SQL CREATE INDEX empindex8 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@id' AS SQL DOUBLE; + EMB_SQL_CHECK("CREATE INDEX"); + + /* create index to use in joins (Anding) */ + + printf("\n\ncreate index to use in joins (Anding) \n"); + printf("---------------------------------------------\n"); + EXEC SQL CREATE INDEX empindex9 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/name/last' AS SQL VARCHAR(100); + EXEC SQL CREATE INDEX deptindex on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/dept/text()' AS SQL VARCHAR(30); + EMB_SQL_CHECK("CREATE INDEX"); + + sprintf(stmt, "XQuery for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + "/company/emp[name/last='Murphy' and dept/text()='Sales']" + " return $i/name/last"); + + EXEC SQL PREPARE s6 from :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c6 CURSOR FOR s6; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c6; + EMB_SQL_CHECK("cursor -- open"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + xmlblob.length = 0; + EXEC SQL FETCH c6 into :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + printf("\n\n\n%s\n",xmlblob.data); + /* Display results */ + } + + EXEC SQL CLOSE c6; + EMB_SQL_CHECK("cursor -- close"); + + + /* create indexes to use in joins ( Anding or Oring ) */ + + printf("\n\ncreate indexes to use in joins ( Anding or Oring ) \n"); + printf("-------------------------------------------------------\n"); + EXEC SQL CREATE INDEX empindex10 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@salary' AS SQL DOUBLE; + EXEC SQL CREATE INDEX empindex11 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/dept' AS SQL VARCHAR(25); + EXEC SQL CREATE INDEX empindex12 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/name/last' AS SQL VARCHAR(25); + EMB_SQL_CHECK("CREATE INDEX"); + + sprintf(stmt, "XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + "/company.emp[ @salary > 50000 or dept='Finance'] " + "/name [ last = 'Brown'] return $i/name/last"); + + EXEC SQL PREPARE s7 from :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c7 CURSOR FOR s7; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c7; + EMB_SQL_CHECK("cursor -- open"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + xmlblob.length = 0; + EXEC SQL FETCH c7 into :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + printf("\n\n\n%s\n",xmlblob.data); + /* Display results */ + } + + EXEC SQL CLOSE c7; + EMB_SQL_CHECK("cursor -- close"); + + + /* create index with Date Data type */ + + printf("\n\nCreate index with Data type date \n"); + printf("-------------------------------------\n"); + EXEC SQL CREATE INDEX empindex13 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@DOB' as SQL DATE; + EMB_SQL_CHECK("CREATE INDEX"); + + sprintf(stmt, "XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + "/company/emp[@DOB < '11-11-78'] return $i/name"); + + EXEC SQL PREPARE s8 from :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c8 CURSOR FOR s8; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c8; + EMB_SQL_CHECK("cursor -- open"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + xmlblob.length = 0; + EXEC SQL FETCH c8 into :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + printf("\n\n\n%s\n",xmlblob.data); + /* Display results */ + } + + EXEC SQL CLOSE c8; + EMB_SQL_CHECK("cursor -- close"); + + + + /* create index on comment node */ + + printf("\n\nCreate index on comment node \n"); + printf("---------------------------------\n"); + EXEC SQL CREATE INDEX empindex14 on company(doc) GENERATE KEY USING + XMLPATTERN '/company//comment()' AS SQL VARCHAR HASHED; + EMB_SQL_CHECK("CREATE INDEX"); + + sprintf(stmt, "XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + "/company/emp[comment()=' good ']return $i/name"); + + EXEC SQL PREPARE s9 from :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c9 CURSOR FOR s9; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c9; + EMB_SQL_CHECK("cursor -- open"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + xmlblob.length = 0; + EXEC SQL FETCH c9 into :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + printf("\n\n\n%s\n",xmlblob.data); + /* Display results */ + } + + EXEC SQL CLOSE c9; + EMB_SQL_CHECK("cursor -- close"); + + + EXEC SQL DROP INDEX "EMPINDEX1"; + EXEC SQL DROP INDEX "EMPINDEX2"; + EXEC SQL DROP INDEX "EMPINDEX3"; + EXEC SQL DROP INDEX "EMPINDEX4"; + EXEC SQL DROP INDEX "EMPINDEX5"; + EXEC SQL DROP INDEX "EMPINDEX7"; + EXEC SQL DROP INDEX "EMPINDEX8"; + EXEC SQL DROP INDEX "EMPINDEX9"; + EXEC SQL DROP INDEX "DEPTINDEX"; + EXEC SQL DROP INDEX "EMPINDEX10"; + EXEC SQL DROP INDEX "EMPINDEX11"; + EXEC SQL DROP INDEX "EMPINDEX12"; + EXEC SQL DROP INDEX "EMPINDEX13"; + EXEC SQL DROP INDEX "EMPINDEX14"; + EMB_SQL_CHECK("DROP INDEX"); + + /* drop the table company */ + + printf("DROP the table \n"); + EXEC SQL DROP TABLE "COMPANY"; + EMB_SQL_CHECK("DROP TABLE COMPANY"); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if(rc != 0) + { + return rc; + } + + return 0; +} diff --git a/xml/c/xmlinsert.sqc b/xml/c/xmlinsert.sqc new file mode 100644 index 0000000..43dc8c8 --- /dev/null +++ b/xml/c/xmlinsert.sqc @@ -0,0 +1,290 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlinsert.sqc +** SAMPLE: This sample demonstrates different ways of inserting a XML document +** into a column of XML data type. +** +** SQL STATEMENTS USED: +** INSERT +** ROLLBACK +** SQL/XML FUNCTION USED: +** XMLPARSE +** XMLVALIDATE +** DOCUMENT +** XMLCAST +** OUTPUT FILE: xmlinsert.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +EXEC SQL BEGIN DECLARE SECTION; + char xmldata[2000]; + char invalidxmldata[2000]; + short nullind; + static SQL TYPE IS XML AS CLOB(1k) xmlclob1=SQL_CLOB_INIT(" a ") ; + static SQL TYPE IS BLOB(1k) hv_blob2 = SQL_BLOB_INIT(" a "); + static SQL TYPE IS XML AS BLOB(1k) xmlblob3 = SQL_BLOB_INIT(" a"); + static SQL TYPE IS XML AS CLOB(1k) invaliddata = SQL_BLOB_INIT(" a "); +EXEC SQL END DECLARE SECTION; + +int createtables(void); +int droptables(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + int charcount = 0; + char prep_string[200]; + char stmt[600]; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + nullind = 0; + + + /* Create a XML document that will be used to INSERT in the table */ + strcpy (xmldata, "" + " Plastic Casing " + "
Blue Color
" + " 2.89 " + " 0.23 "); + + /* invalid xml data will not have the closing tags for */ + /* description and product */ + strcpy(invalidxmldata, xmldata); + + strcat(xmldata, "
"); + strcpy(xmlclob1.data, xmldata); + strcpy(hv_blob2.data, xmldata); + strcpy(xmlblob3.data, xmldata); + + /* Set the length of the data */ + xmlclob1.length = strlen(xmldata) + 1; + hv_blob2.length = xmlclob1.length; + xmlblob3.length = xmlclob1.length; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* call function to create needed tables */ + rc = createtables(); + + /* inserting when source is from host variable of type XML AS CLOB */ + printf(" Inserting when source is from host variable of type XML AS CLOB\n"); + EXEC SQL INSERT INTO purchaseorder (poid, porder) + VALUES (1612, :xmlclob1:nullind); + EMB_SQL_CHECK("INSERTING with host variable of type XML as CLOB"); + + /* inserting when source is from host variable of type BLOB */ + printf(" Inserting when source is from host variable of type BLOB\n"); + EXEC SQL INSERT INTO purchaseorder (poid, porder) + VALUES (712, XMLPARSE(DOCUMENT :hv_blob2:nullind STRIP WHITESPACE)); + EMB_SQL_CHECK("INSERTING with host variable of type BLOB"); + + /* inserting when source is from host variable of type BLOB */ + /* implicit parsing is done here */ + printf(" Inserting when source is from host variable of type BLOB with Implicit parsing\n"); + EXEC SQL INSERT INTO purchaseorder (poid, porder) + VALUES (1111, :hv_blob2:nullind); + EMB_SQL_CHECK("INSERTING with host varible of type BLOB"); + + printf(" This insert should fail as the XML doc is not well-formed\n"); + /* inserting when source is from hostvariable of type VARCHAR */ + /* and the data is not a well-formed XML document */ + EXEC SQL INSERT INTO purchaseorder (poid, porder) + VALUES (2181, XMLPARSE(DOCUMENT :invalidxmldata:nullind preserve whitespace)); + if (sqlca.sqlcode != 0) + { + printf("\n Insertion failed as the document is not a wellformed document\n"); + printf(" FAILED WITH SQLCODE = %d\n\n", sqlca.sqlcode); + } + + /* insert a XML document when target is from another column of type XML */ + /* using Implicit parsing */ + /* add a number to POID to avoid unique constraint conflict */ + printf(" Insert a XML document when target is from another column of type XML\n"); + printf(" Using Implicit parsing\n"); + EXEC SQL INSERT INTO purchaseorder(poid, porder) + (SELECT POID+5, porder FROM purchaseorder WHERE poid = 1111); + EMB_SQL_CHECK("Insert from another column of XML data type"); + + /* insert when source is a XML document from a column */ + /* of type VARCHAR */ + printf(" Insert when source is a XML document from a column of type VARCHAR\n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "(SELECT id, XMLPARSE( DOCUMENT desc) FROM vartable where " + "id = 11111)"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK(" Insert from another column of type VARCHAR"); + + /* insert when source is a XML document from a column */ + /* of type VARCHAR, Using Implicit Parsing */ + printf(" Insert when source is a XML document from a column of type VARCHAR, Using Implicit Parsing\n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "(SELECT id, desc FROM vartable WHERE " + "id = 22222)"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Insert from another column of type VARCHAR using implicit Parsing"); + + /* insert when source is a variable of a simple type */ + /* it is typecasted to XML using the XMLCAST function */ + printf(" Insert when source is a variable of a simple type\n"); + strcpy(prep_string, "INSERT INTO purchaseorder (poid, porder) "); + strcat(prep_string, "VALUES ( 1092, XMLCAST( ? AS XML))"); + EXEC SQL PREPARE stmt FROM :prep_string; + EMB_SQL_CHECK("Preparing the statement"); + EXEC SQL EXECUTE stmt using :xmldata; + EMB_SQL_CHECK("Executing the Insert statement"); + + /* use XML Functions to create a XML document */ + /* insert this document into the table */ + printf(" Use XML Functions to create a XML document\n"); + printf(" Insert this document into the table \n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder)" + "(SELECT id, XMLDOCUMENT( XMLELEMENT( NAME \"PORDER\"," + " XMLELEMENT( NAME \"ID\", XMLATTRIBUTES( v.id as PRODID))," + " XMLELEMENT( NAME \"DESC\", v.desc)))" + " FROM vartable AS v WHERE ID = 33333)"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Use XML functions to create XML doc"); + + printf(" This insert should fail as the XML doc is as per Schema\n"); + + /* validate an invalid XML document before inserting into the table */ + printf(" Validate an invalid XML document before inserting into the table\n"); + EXEC SQL INSERT INTO purchaseorder(poid, porder) + VALUES (2181, XMLVALIDATE(:invaliddata:nullind ACCORDING TO XMLSCHEMA ID PRODUCT)); + if (sqlca.sqlcode != 0) + { + printf("\n Insertion failed as the document is not a VALID XML document\n"); + printf(" FAILED WITH SQLCODE = %d\n\n", sqlca.sqlcode); + } + + /* validate an XML document when target is from another column */ + /* add a number to POID to avoid unique constraint conflict */ + printf(" Validate an XML document when target is from another column\n"); + EXEC SQL INSERT INTO purchaseorder(poid, porder) + (SELECT poid+15, XMLVALIDATE(porder ACCORDING TO XMLSCHEMA ID PRODUCT) FROM purchaseorder + WHERE poid = 1111); + EMB_SQL_CHECK("Insert from another column of XML data type"); + + EXEC SQL ROLLBACK; + EMB_SQL_CHECK("ROLLBACK"); + + /* Call function for cleanup */ + rc = droptables(); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if (rc != 0) + { + return rc; + } + + return 0; +} /* main */ + +/* Create tables */ +int createtables(void) +{ + int rc = 0; + char stmt[800]; + + strcpy(stmt, "CREATE TABLE vartable (id INT," + " desc VARCHAR(200), comment VARCHAR(25))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Creation"); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(11111, \' Neeraj " + " Gaurav \', " + "\'Final Year\')"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Insert"); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(22222, '" + " Plastic Casing " + "
Green Color
" + " 7.89 " + " 6.23 " + "
', " + "'Last Product')"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Insert"); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(33333, \' Neeraj " + " Gaurav \', " + "\'Final Year\')"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Insert"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + return 0; +} + +int droptables(void) +{ + int rc = 0; + char stmt[200]; + + strcpy(stmt, "DROP TABLE VARTABLE"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Drop"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + return 0; +} diff --git a/xml/c/xmlintegrate.sqc b/xml/c/xmlintegrate.sqc new file mode 100644 index 0000000..83b240e --- /dev/null +++ b/xml/c/xmlintegrate.sqc @@ -0,0 +1,525 @@ +/*************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SAMPLE FILE NAME: xmlintegrate.sqc +** +** PURPOSE: To show how to use XMLROW and XMLGROUP functions to publish +** relational information as XML. +** To show XMLQuery default passing mechanism. +** To show default column specification for XMLTABLE. +** +** USAGE SCENARIO: The super marker manager maintains a database to store +** all customer's addresses in a relational table called +** "addr" so that whenever a customer places an order for +** any item, he can use this "addr" table to deliver the +** item. As the number of customers grew year after +** year,there was a need to change the table structure +** to have one single XML column for address and maintain +** the data in a new table called "customerinfo_new". +** +** PREREQUISITE: NONE +** +** EXECUTION: bldapp xmlintegrate; +** xmlintegrate +** +** INPUTS: NONE +** +** OUTPUTS: Shows comparison of XML documents created using different +** SQLXML functions and using XMLROW, XMLGROUP functions +** +** OUTPUT FILE: xmlintegrate.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** CREATE TABLE +** INSERT +** SELECT +** +** SQL/XML FUNCTIONS USED: +** XMLROW +** XMLGROUP +** XMLDOCUMENT +** XMLELEMENT +** XMLCONCAT +** XMLATTRIBUTES +** +************************************************************************** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +** +************************************************************************** +** +** SAMPLE DESCRIPTION +** +************************************************************************** +** +** 1. Shows comparison of publishing XML documents using different +** SQL/XML functions and XMLROW function. +** +** 1.1 Element centric mapping comparison. +** +** 1.2 Attribute centric mapping comparison. +** +** 2. Shows the comparison of publishing XML documents using different +** SQL/XML publishing functions and XMLGROUP function. +** +** 3. Shows XMLQuery default parameter passing mechanism. +** +** 4. Shows default column specification for XMLTABLE. +** +*************************************************************************** +** +** INCLUDE ALL HEADER FILES +** +**************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +/************************************************************************** +* DECLARATION SECTION +* +***************************************************************************/ + +EXEC SQL BEGIN DECLARE SECTION; /* start of declaration section */ + char dbAlias[700]; + char user[700]; + char pswd[700]; + char stmt[1000]; + sqlint32 custid; + short empno; + SQL TYPE IS XML AS BLOB( 10K ) address; + SQL TYPE IS XML AS BLOB( 10K ) address1; + SQL TYPE IS XML AS BLOB( 10K ) address2; +EXEC SQL END DECLARE SECTION; /* end of declaration section */ + +int main(int argc, char *argv[]) +{ + + int rc = 0; + struct sqlca sqlca; + int len; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\n--------------------------------------------------"); + printf("\nThis sample shows " + "1. How to use XMLROW and XMLGROUP functions to publish" + " relational information as XML."); + printf("\n2. Shows XMLQuery default passing mechanism"); + printf("\n3. Shows default column specification for XMLTABLE"); + printf("\n--------------------------------------------------"); + printf("\n"); + + + + /**********************************************************************/ + /* Connect to SAMPLE database */ + /**********************************************************************/ + + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + + /*********************************************************************/ + /* 1. Shows comparison of publishing XML documents using different */ + /* SQL/XML functions and XMLROW function. */ + /* */ + /*********************************************************************/ + + strcpy(stmt, "CREATE TABLE addr (custid int, name varchar(20),"); + strcat(stmt, "street varchar(20), city varchar(20), province varchar(20),"); + strcat(stmt, "postalcode BIGINT)"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("create table addr"); + + + strcpy(stmt, "CREATE TABLE customerinfo_new (custid smallint, " + "address XML)"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE customerinfo_new"); + + + /*********************************************************************/ + /* 1.1 Element centric mapping comparison */ + /*********************************************************************/ + + strcpy(stmt, "INSERT INTO addr " + "VALUES (1000, 'madhavi', 'madivala', " + "'Bangalore', 'Karnataka', 500056)"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO addr"); + + strcpy(stmt, "INSERT INTO customerinfo_new (Custid, Address)" + "SELECT Custid, XMLDOCUMENT(" + "XMLElement(NAME \"row\", XMLCONCAT(" + "XMLElement(NAME \"name\", name OPTION NULL ON NULL)," + "XMLElement(NAME \"street\", street OPTION NULL ON NULL)," + "XMLElement(NAME \"city\", city OPTION NULL ON NULL)," + "XMLElement(NAME \"province\", province OPTION NULL ON NULL)," + "XMLElement(NAME \"postalcode\",postalcode OPTION NULL ON NULL))" + " OPTION NULL ON NULL ))" + " FROM addr "); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO customerinfo_new"); + + strcpy(stmt, "INSERT INTO customerinfo_new (Custid, Address)" + "(SELECT Custid, XMLROW(C.name, C.street, C.city, " + " C.province,C.postalcode)" + " FROM addr C) "); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO customerinfo_new"); + + printf("\n\n"); + printf("----------------------------------------------------"); + printf("\nCheck if both the documents created using different "); + printf("SQL/XML publishing functions and the one created using"); + printf(" XMLROW are same"); + printf("\n----------------------------------------------------"); + printf("\n\n"); + + strcpy(stmt, "SELECT * FROM customerinfo_new"); + + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("PREPARE s1"); + + EXEC SQL DECLARE cur1 CURSOR FOR s1; + EMB_SQL_CHECK("DECLARE CURSOR CUR1"); + + EXEC SQL OPEN cur1; + EMB_SQL_CHECK("OPEN cur1"); + + EXEC SQL FETCH cur1 INTO :custid, :address; + EMB_SQL_CHECK("FETCH cursor"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + printf("\n\n\n%d, %s\n",custid, address.data); + + EXEC SQL FETCH cur1 INTO :custid, :address; + EMB_SQL_CHECK("FETCH cursor"); + } + + EXEC SQL CLOSE cur1; + EMB_SQL_CHECK("CLOSE cursor"); + + + /************************************************************************/ + /* 1.2 Attribute Centric mapping comparison */ + /************************************************************************/ + printf("\n\n"); + printf("--------------------------------------------------------"); + printf("\n Attribute centric mapping using SQL/XML functions "); + printf("\n--------------------------------------------------------"); + printf("\n\n"); + + strcpy(stmt, "SELECT Custid, CASE WHEN C.name is NULL and " + "C.street is NULL and C.City is NULL and " + "C.province is NULL and C.postalcode is NULL " + "THEN cast(NULL as XML) " + "ELSE XMLDOCUMENT(" + " XMLElement(name \"row\", XMLAttributes(C.name," + " C.street,C.city, C.province, C.postalcode)))" + " END FROM addr C"); + + + EXEC SQL PREPARE s2 FROM :stmt; + EMB_SQL_CHECK("PREPARE stmt s2"); + + EXEC SQL DECLARE cur2 CURSOR FOR s2; + EMB_SQL_CHECK("DECLARE CURSOR cur2"); + + EXEC SQL OPEN cur2; + EMB_SQL_CHECK("OPEN cur2"); + + EXEC SQL FETCH cur2 INTO :custid, :address; + EMB_SQL_CHECK("FETCH cursor"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + printf("\n\n\n%d, %s\n",custid, address.data); + + EXEC SQL FETCH cur2 INTO :custid, :address; + EMB_SQL_CHECK("FETCH cursor"); + } + + EXEC SQL CLOSE cur2; + EMB_SQL_CHECK("CLOSE cur2"); + + printf("\n\n"); + printf("--------------------------------------------------------"); + printf("\n Attribute centric mapping using XMLROW "); + printf("\n--------------------------------------------------------"); + printf("\n\n"); + + strcpy(stmt, "SELECT Custid, XMLROW(C.name, C.street, C.city, " + "C.province,C.postalcode OPTION AS ATTRIBUTES) " + "FROM addr as C"); + + EXEC SQL PREPARE s3 FROM :stmt; + EMB_SQL_CHECK("PREPARE STMT s3"); + + EXEC SQL DECLARE cur3 CURSOR FOR s3; + EMB_SQL_CHECK("DECLARE CURSOR cur3"); + + EXEC SQL OPEN cur3; + EMB_SQL_CHECK("OPEN cur3"); + + EXEC SQL FETCH cur3 INTO :custid, :address; + EMB_SQL_CHECK("FETCH cur3"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + printf("\n\n\n%d, %s\n",custid, address.data); + + EXEC SQL FETCH cur3 INTO :custid, :address; + EMB_SQL_CHECK("FETCH cur3"); + } + + EXEC SQL CLOSE cur3; + EMB_SQL_CHECK("cursor -- close"); + + + /************************************************************************/ + /* 2. Shows the comparison of publishing XML documents using different */ + /* SQL/XML publishing functions and XMLGROUP function */ + /************************************************************************/ + + printf("\n\n"); + printf("-----------------------------------------------------------"); + printf("\nCreate an XML document using SQL/XML publishing functions"); + printf("\n---------------------------------------------------------"); + printf("\n\n"); + + strcpy(stmt, "SELECT XMLDOCUMENT(XMLElement(NAME \"rowset\", " + "XMLAgg(XMLElement(NAME \"row\", " + "XMLElement(NAME \"orderdate\",p.orderdate OPTION NULL ON NULL)," + " XMLElement(NAME \"porder\", p.porder OPTION NULL ON NULL)" + " OPTION NULL ON NULL)ORDER BY p.orderdate)" + " OPTION NULL ON NULL))" + " FROM purchaseorder p, customer c " + "WHERE p.custid=c.Cid"); + + EXEC SQL PREPARE s4 FROM :stmt; + EMB_SQL_CHECK("PREPARE STMT s4"); + + EXEC SQL DECLARE cur4 CURSOR FOR s4; + EMB_SQL_CHECK("DECLARE CURSOR cur4"); + + EXEC SQL OPEN cur4; + EMB_SQL_CHECK("OPEN cur4"); + + EXEC SQL FETCH cur4 INTO :address; + EMB_SQL_CHECK("FETCH cur4"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + printf("\n\n\n%s\n",address.data); + + EXEC SQL FETCH cur4 INTO :address; + EMB_SQL_CHECK("FETCH cur4"); + } + + EXEC SQL CLOSE cur4; + EMB_SQL_CHECK("CLOSE cursor"); + + + printf("\n\n"); + printf("----------------------------------------------------"); + printf("\nCreate an XML document using XMLGROUP function"); + printf("\n----------------------------------------------------"); + printf("\n\n"); + + strcpy(stmt, "SELECT XMLGroup(p.orderdate, p.porder ORDER BY p.orderdate) " + "FROM purchaseorder p, customer c " + "WHERE p.custid=c.Cid"); + + EXEC SQL PREPARE s5 FROM :stmt; + EMB_SQL_CHECK("PREPARE STMT s5"); + + EXEC SQL DECLARE cur5 CURSOR FOR s5; + EMB_SQL_CHECK("DECLARE CURSOR cur5"); + + EXEC SQL OPEN cur5; + EMB_SQL_CHECK("OPEN CURSOR cur5"); + + EXEC SQL FETCH cur5 INTO :address; + EMB_SQL_CHECK("FETCH CURSOR cur5"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + printf("\n\n\n%s\n",address.data); + + EXEC SQL FETCH cur5 INTO :address; + EMB_SQL_CHECK("FETCH CURSOR cur5"); + } + + EXEC SQL CLOSE cur5; + EMB_SQL_CHECK("CLOSE cur5"); + + /********************************************************************/ + /* */ + /* Shows XMLQuery default parameter passing mechanism */ + /* */ + /********************************************************************/ + + printf("\n\n"); + printf("CREATE TABLE EMPLOYEES (empno int,lastname varchar(20), "); + printf("firstname varchar(20), workdept varchar(20), "); + printf("phoneno varchar(20), hiredate DATE)"); + + printf("\n\n"); + strcpy(stmt, "CREATE TABLE EMPLOYEES (empno int,lastname varchar(20), " + "firstname varchar(20), workdept varchar(20), " + "phoneno varchar(20), hiredate DATE)"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE employees"); + + strcpy(stmt, "INSERT INTO employees " + "VALUES (100, 'latha', 'suma'," + "'Informix', '5114', '03/01/2006')"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO employees"); + + printf("\n\n"); + printf("-------------------------------------------------------"); + printf("\nSELECT empno, XMLQuery('"); + printf(" {$WORKDEPT}"); + printf(" {$PHONENO}"); + printf(" {$HIREDATE}')"); + printf(" FROM employees"); + printf("\n-------------------------------------------------------"); + printf("\n\n"); + + strcpy(stmt, "SELECT empno, XMLQuery('" + "{$WORKDEPT}" + "{$PHONENO}" + "{$HIREDATE}')" + " FROM employees"); + + EXEC SQL PREPARE s6 FROM :stmt; + EMB_SQL_CHECK("PREPARE STMT s6"); + + EXEC SQL DECLARE cur6 CURSOR FOR s6; + EMB_SQL_CHECK("DECLARE CURSOR cur6"); + + EXEC SQL OPEN cur6; + EMB_SQL_CHECK("OPEN CURSOR cur6"); + + EXEC SQL FETCH cur6 INTO :empno, :address1; + EMB_SQL_CHECK("FETCH CURSOR cur6"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + printf("\n\n\n%d, %s\n",empno, address1.data); + + EXEC SQL FETCH cur6 INTO :empno, :address1; + EMB_SQL_CHECK("FETCH CURSOR cur6"); + } + + EXEC SQL CLOSE cur6; + EMB_SQL_CHECK("CLOSE cur6"); + + + /*************************************************************************/ + /* */ + /* 4. Shows the default column specification of XMLTABLE */ + /* */ + /*************************************************************************/ + + printf("\n\n"); + printf("--------------------------------------------------"); + printf("\nShows the default column specification of XMLTABLE"); + printf("\n--------------------------------------------------"); + printf("\n\n"); + + printf("--------------------------------------------------"); + printf("\nSELECT X.* FROM XMLTABLE ('db2-fn:xmlcolumn"); + printf("(\"CUSTOMER.INFO\")/customerinfo/phone') as X"); + printf("\n--------------------------------------------------"); + printf("\n\n"); + + strcpy(stmt, "XQuery for $plist in db2-fn:sqlquery(\"SELECT X.phone FROM customer," + "XMLTABLE('$INFO/customerinfo/phone') AS X(phone)\")" + "order by $plist/@type, $plist/text() return $plist"); + + EXEC SQL PREPARE s7 FROM :stmt; + EMB_SQL_CHECK("PREPARE STMT s7"); + + EXEC SQL DECLARE cur7 CURSOR FOR s7; + EMB_SQL_CHECK("DECLARE CURSOR cur7"); + + EXEC SQL OPEN cur7; + EMB_SQL_CHECK("OPEN cur7"); + + EXEC SQL FETCH cur7 INTO :address2; + EMB_SQL_CHECK("FETCH CURSOR cur7"); + + while(sqlca.sqlcode == SQL_RC_OK) + { + printf("\n\n\n%s\n",address2.data); + + EXEC SQL FETCH cur7 INTO :address2; + EMB_SQL_CHECK("FETCH CURSOR cur7"); + } + + EXEC SQL CLOSE cur7; + EMB_SQL_CHECK("CLSOE cur7"); + + /**************************************************************/ + /* CLEANUP */ + /**************************************************************/ + + EXEC SQL DROP TABLE addr; + EMB_SQL_CHECK("DROP TABLE addr"); + + EXEC SQL DROP TABLE customerinfo_new; + EMB_SQL_CHECK("DROP TAABLE customerinfo_new"); + + EXEC SQL DROP TABLE employees; + EMB_SQL_CHECK("DROP TABLE employees"); + + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); +} diff --git a/xml/c/xmlload.sqc b/xml/c/xmlload.sqc new file mode 100644 index 0000000..4bd1803 --- /dev/null +++ b/xml/c/xmlload.sqc @@ -0,0 +1,394 @@ +/* ************************************************************************* +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +** ************************************************************************* +** +** SAMPLE FILE NAME: xmlload.sqc +** +** PURPOSE: To demonstrate how to load XML content into a table using +** different options of LOAD command. +** +** USAGE SCENARIO: A store manager wants to load bulk of purchase order +** documents into an XML column of a table. +** +** PREREQUISITE: +** The data file and XML documents must exist in the DB2 install path. +** Copy loaddata2.del from directory +** /sqllib/samples/xml/data in UNIX and +** \sqllib\samples\xml\data in Windows to the install path. +** Create a new directory "xmldatadir" in the install path and copy +** loadfile1.xml and loadfile2.xml from directory +** /sqllib/samples/xml/data in UNIX and +** \sqllib\samples\xml\data in Windows to the newly created +** xmldatadir directory. +** +** EXECUTION: bldapp xmlload (Build the sample) +** xmlload (Run the sample) +** +** INPUTS: NONE +** +** OUTPUTS: Successful loading of XML purchase orders. +** +** OUTPUT FILE: xmlload.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** PREPARE +** DECLARE CURSOR +** OPEN +** FETCH +** CLOSE +** CREATE TABLE +** DROP +** +** DB2 APIs USED: +** sqluvqdp -- Quiesce Table Spaces for Table +** db2Load -- Load +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +**************************************************************************** +** +** SAMPLE DESCRIPTION +** +** ************************************************************************* +** 1. LOAD data into the table using XMLVALIDATE USING XDS clause. +** *************************************************************************/ + +/* ************************************************************************** +** SETUP +** **************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +#include +#include "sql.h" +#include "sqlcodes.h" +#include "sqlstate.h" + + +int TbXMLLoad(char *); +int LoadedDataDisplay(void); + +EXEC SQL BEGIN DECLARE SECTION; + char strStmt[256]; + short poid; + SQL TYPE IS XML AS CLOB(50K) porder; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + char loadDataFileName[256]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO LOAD XML DATA USING LOAD UTILITY.\n"); + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + #if(defined(DB2NT)) + sprintf(loadDataFileName, "%s%sloaddata2.del", getenv("DB2PATH"), PATH_SEP); + #else /* UNIX */ + sprintf(loadDataFileName, "%s%sloaddata2.del", getenv("HOME"), PATH_SEP); + #endif + + rc = TbXMLLoad(loadDataFileName); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if (rc != 0) + { + return rc; + } + + return 0; +} /* main */ + + +int LoadedDataDisplay(void) +{ + struct sqlca sqlca = {0}; + + printf("\n SELECT * FROM POtable\n"); + printf(" POID PORDER \n"); + printf(" -------- --------------\n"); + + strcpy(strStmt, "SELECT * FROM POtable"); + + EXEC SQL PREPARE stmt FROM :strStmt; + EMB_SQL_CHECK("statement -- prepare"); + + EXEC SQL DECLARE c0 CURSOR FOR stmt; + + EXEC SQL OPEN c0; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c0 INTO :poid, :porder; + EMB_SQL_CHECK("cursor -- fetch"); + + while (sqlca.sqlcode != 100) + { + printf(" %8d %-s\n", poid, porder.data); + + EXEC SQL FETCH c0 INTO :poid, :porder; + EMB_SQL_CHECK("cursor -- fetch"); + } + + EXEC SQL CLOSE c0; + + return 0; +} /* LoadedDataDisplay */ + +int TbXMLLoad(char *dataFileName) +{ + int rc = 0; + int totalLength = 0; + struct sqlca sqlca; + struct sqldcol dataDescriptor = {0}; + char actionString[256]; + struct sqlchar *pAction = {0}; + struct sqllob *pAction1 = {0}; + struct sqllob *piLongActionString = {0}; + char msgFileName[128]; + struct db2LoadStruct paramStruct = {0}; + struct db2LoadIn inputInfoStruct = {0}; + struct db2LoadOut outputInfoStruct = {0}; + int commitcount = 10; + int whiteSpace = 1; + unsigned short xmlParse = whiteSpace; + struct sqlchar *fileTypeMod = NULL; + struct sqlu_media_list mediaList = {0}; + struct sqlu_media_entry *pPathList; + union sqlu_media_list_targets listTargetsXmlPath; + struct sqlu_media_list mediaListXmlPath = {0}; + struct db2DMUXmlValidate xmlValidate = {0}; + struct db2DMUXmlValidateXds xdsArgs = {0}; + struct db2Char defaultSchema = {0}, ignoreSchemas = {0}; + struct db2DMUXmlMapSchema mapSchemas = {0}; + struct db2Char mapFromSchema = {0}; + struct db2Char mapToSchema = {0}; + char temp[20]; + + + sprintf(strStmt," CREATE TABLE POtable(POid INT NOT NULL PRIMARY KEY,porder XML)"); + printf("\n%s\n", strStmt); + + EXEC SQL EXECUTE IMMEDIATE :strStmt; + EMB_SQL_CHECK("POtable -- create"); + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 API:\n"); + printf(" sqluvqdp -- Quiesce Table Spaces for Table\n"); + printf(" db2Load -- Load\n"); + printf("TO LOAD XML DATA INTO A TABLE.\n"); + + /* quiesce table spaces for table */ + printf("\n Quiesce the table spaces for 'POtable'.\n"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("transaction -- commit"); + /* quiesce table spaces for table */ + sqluvqdp("POtable", SQLU_QUIESCEMODE_RESET_OWNED, NULL, &sqlca); + DB2_API_CHECK("tablespaces for table -- quiesce"); + + /* load table */ + dataDescriptor.dcolmeth = SQL_METH_D; + strcpy(actionString, "INSERT INTO POtable"); + pAction = (struct sqlchar *)malloc(sizeof(short) + sizeof(actionString) + 1); + pAction->length = strlen(actionString); + strcpy(pAction->data, actionString); + strcpy(msgFileName, "tbload.MSG"); + + /* Setup the input information structure */ + inputInfoStruct.piUseTablespace = NULL; + inputInfoStruct.iSavecount = 0; /* consistency points + as infrequently as possible */ + inputInfoStruct.iRestartcount = 0; /* start at row 1 */ + inputInfoStruct.iRowcount = 0; /* load all rows */ + inputInfoStruct.iWarningcount = 0; /* don't stop for warnings */ + inputInfoStruct.iDataBufferSize = 0; /* default data buffer size */ + inputInfoStruct.iSortBufferSize = 0; /* def. warning buffer size */ + inputInfoStruct.iHoldQuiesce = 0; /* don't hold the quiesce */ + inputInfoStruct.iRestartphase = ' '; /* ignored anyway */ + inputInfoStruct.iStatsOpt = SQLU_STATS_NONE; + /* don't bother with them */ + inputInfoStruct.iIndexingMode = SQLU_INX_AUTOSELECT;/* let load choose */ + /* indexing mode */ + inputInfoStruct.iCpuParallelism = 0; + inputInfoStruct.iNonrecoverable = SQLU_NON_RECOVERABLE_LOAD; + inputInfoStruct.iAccessLevel = SQLU_ALLOW_NO_ACCESS; + inputInfoStruct.iLockWithForce = SQLU_NO_FORCE; + + /* From V9.0 onwards, the structure member iCheckPending is */ + /* deprecated and replaced with iSetIntegrityPending. Also the */ + /* possible value to set this variable SQLU_CHECK_PENDING_CASCADE_DEFERRED */ + /* has been replaced with SQLU_SI_PENDING_CASCADE_DEFERRED. */ + inputInfoStruct.iSetIntegrityPending = SQLU_SI_PENDING_CASCADE_DEFERRED; + + /* XML data Path setup */ + pPathList=(struct sqlu_media_entry *)malloc(sizeof(struct sqlu_media_entry)); + #if(defined(DB2NT)) + sprintf(pPathList->media_entry, "%s%sxmldatadir", getenv("DB2PATH"), PATH_SEP); + #else /* UNIX */ + sprintf(pPathList->media_entry, "%s%sxmldatadir", getenv("HOME"), PATH_SEP); + #endif + + listTargetsXmlPath.media = pPathList; + mediaListXmlPath.media_type = 'L'; + mediaListXmlPath.sessions = 1; + mediaListXmlPath.target = listTargetsXmlPath; + + /* File Type Modifier for LOAD utility*/ + strcpy(temp,"XMLCHAR"); + fileTypeMod = (struct sqlchar *) malloc(sizeof(short) + sizeof (temp) + 1); + fileTypeMod->length = strlen(temp); + strcpy(fileTypeMod->data,temp); + + /* XML validate using XDS set up */ + defaultSchema.iLength = 6; + defaultSchema.pioData=malloc(7); + strcpy(defaultSchema.pioData,"porder"); + ignoreSchemas.iLength = 8; + ignoreSchemas.pioData=malloc(9); + strcpy(ignoreSchemas.pioData,"supplier"); + mapFromSchema.iLength = 7; + mapFromSchema.pioData=malloc(8); + strcpy(mapFromSchema.pioData,"product"); + mapToSchema.iLength = 6; + mapToSchema.pioData=malloc(7); + strcpy(mapToSchema.pioData,"porder"); + mapSchemas.iMapFromSchema = mapFromSchema; + mapSchemas.iMapToSchema = mapToSchema; + xdsArgs.piDefaultSchema = &defaultSchema; + xdsArgs.iNumIgnoreSchemas = 1; + xdsArgs.piIgnoreSchemas =&ignoreSchemas; + xdsArgs.iNumMapSchemas = 1; + xdsArgs.piMapSchemas = &mapSchemas; + xmlValidate.iUsing = DB2DMU_XMLVAL_XDS; + xmlValidate.piXdsArgs =&xdsArgs; + + /* load table -- validate the XML documents */ + inputInfoStruct.piXmlParse = &xmlParse; + inputInfoStruct.piXmlValidate = &xmlValidate; + + /* load table -- source file */ + mediaList.media_type = SQLU_CLIENT_LOCATION; + mediaList.sessions = 1; + mediaList.target.location = + (struct sqlu_location_entry *)malloc(sizeof(struct sqlu_location_entry) * + mediaList.sessions); + strcpy(mediaList.target.location->location_entry, dataFileName); + + /* Setup the parameter structure */ + paramStruct.piSourceList = &mediaList; + paramStruct.piLobPathList = NULL; + paramStruct.piDataDescriptor = &dataDescriptor; + paramStruct.piActionString = pAction; + + paramStruct.piFileType = SQL_DEL; + paramStruct.piFileTypeMod = fileTypeMod; + paramStruct.piLocalMsgFileName = msgFileName; + paramStruct.piTempFilesPath = NULL; + paramStruct.piVendorSortWorkPaths = NULL; + paramStruct.piCopyTargetList = NULL; + paramStruct.piNullIndicators = NULL; + paramStruct.piLoadInfoIn = &inputInfoStruct; + paramStruct.poLoadInfoOut = &outputInfoStruct; + paramStruct.piPartLoadInfoIn = NULL; + paramStruct.poPartLoadInfoOut = NULL; + paramStruct.iCallerAction = SQLU_INITIAL; + paramStruct.piXmlPathList = &mediaListXmlPath; + + printf("\n Load table.\n"); + printf(" client source file name : %s\n", dataFileName); + printf(" action : %s\n", actionString); + printf(" client message file name: %s\n", msgFileName); + + /* import table */ + printf("\n LOAD FROM loaddata2.del OF DEL XML FROM xmldatadir\n"); + printf(" MODIFIED BY XMLCHAR XMLVALIDATE USING XDS DEFAULT porder \n"); + printf(" IGNORE (supplier) MAP((product,porder))\n"); + printf(" INSERT INTO POtable \n"); + + /* load table */ + rc = db2Load (db2Version950, /* Database version number */ + ¶mStruct, /* In/out parameters */ + &sqlca); /* SQLCA */ + + EXEC SQL COMMIT; + + /* free memory allocated */ + free(pAction); + free(pPathList); + free(fileTypeMod); + free(defaultSchema.pioData); + free(ignoreSchemas.pioData); + free(mapFromSchema.pioData); + free(mapToSchema.pioData); + + /* display load info */ + printf("\n Load info.\n"); + printf(" rows read : %d\n", (int)outputInfoStruct.oRowsRead); + printf(" rows skipped : %d\n", (int)outputInfoStruct.oRowsSkipped); + printf(" rows loaded : %d\n", (int)outputInfoStruct.oRowsLoaded); + printf(" rows deleted : %d\n", (int)outputInfoStruct.oRowsDeleted); + printf(" rows rejected : %d\n", (int)outputInfoStruct.oRowsRejected); + printf(" rows committed: %d\n", (int)outputInfoStruct.oRowsCommitted); + + /* display content of the new table */ + rc = LoadedDataDisplay(); + + /* drop new table */ + printf("\n DROP TABLE POtable\n"); + + EXEC SQL DROP TABLE POtable; + EMB_SQL_CHECK("POtable -- drop"); + + return 0; +} /* TbXMLLoad */ diff --git a/xml/c/xmlread.sqc b/xml/c/xmlread.sqc new file mode 100644 index 0000000..3bab799 --- /dev/null +++ b/xml/c/xmlread.sqc @@ -0,0 +1,172 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlread.sqc +** +** SAMPLE: This sample demonstrates to read XML data from a table. +** +** SQL STATEMENTS USED: +** DECLARE +** OPEN +** FETCH +** CLOSE +** +** OUTPUT FILE: xmlread.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +EXEC SQL BEGIN DECLARE SECTION; + sqlint32 pid; + sqlint32 cid; + char comment[50]; + char status[20]; + char orderdate[11]; + short porderInd; + short commentInd; + short statusInd; + short orderdateInd; + short infoInd; + short historyInd; + SQL TYPE IS XML AS CLOB (2K) porder; + SQL TYPE IS BLOB(1K) info; + SQL TYPE IS BLOB_FILE history; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + int charcount = 0; + char filename[50]; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + strcpy(filename, "history.TXT"); + strcpy(history.name, filename); + history.name_length = strlen(history.name); + history.file_options = SQL_FILE_OVERWRITE; + + EXEC SQL DECLARE C1 CURSOR FOR SELECT P.POID, P.CUSTID, STATUS, PORDER, ORDERDATE, COMMENTS, INFO + FROM PurchaseOrder As P, customer As C WHERE P.CUSTID = C.CID ORDER BY CID,P.POID; + EXEC SQL OPEN C1; + EMB_SQL_CHECK("OPEN CURSOR"); + + EXEC SQL FETCH C1 INTO :pid, :cid, :status:statusInd, :porder:porderInd, + :orderdate:orderdateInd, :comment:commentInd, :info:infoInd, :history:historyInd ; + EMB_SQL_CHECK("FETCH CURSOR"); + + printf("*** Printing data from the PURCHASEORDER table****\n"); + while (sqlca.sqlcode != 100 ) + { + printf("\n***** NEXT ROW ***** \n\n"); + printf(" CUSTOMER ID : %d\n", cid); + printf(" PURCHASE ORDER NO : %d\n", pid); + if (statusInd >= 0) + { + printf(" STATUS : %s\n", status); + } + else + { + printf(" STATUS : NULL\n"); + } + if (orderdateInd >=0) + { + printf(" ORDER DATE : %s\n", orderdate); + } + else + { + printf(" ORDER DATE : NULL\n"); + } + if (commentInd >=0) + { + printf(" COMMENT : %s\n", comment); + } + else + { + printf(" COMMENT : NULL\n"); + } + if (porderInd >=0) + { + printf(" PURCHASE ORDER : "); + for (charcount = 0; charcount < porder.length; charcount++) + { + printf("%c", porder.data[charcount]); + } + printf("\n"); + } + else + { + printf(" PURCHASE ORDER : NULL\n"); + } + + if (infoInd >= 0) + { + printf(" CUSTOMER INFO : "); + printf("%s\n", info.data); + } + else + { + printf(" CUSTOMER INFO : NULL\n"); + } + + EXEC SQL FETCH C1 INTO :pid, :cid, :status:statusInd, :porder :porderInd, + :orderdate:orderdateInd, :comment:commentInd, :info:infoInd, :history:historyInd ; + EMB_SQL_CHECK("FETCH CURSOR"); + } + + EXEC SQL CLOSE C1 WITH RELEASE; + EMB_SQL_CHECK("CLOSE CURSOR"); + +} /* main */ + diff --git a/xml/c/xmlrunstats.sqc b/xml/c/xmlrunstats.sqc new file mode 100644 index 0000000..8ef6549 --- /dev/null +++ b/xml/c/xmlrunstats.sqc @@ -0,0 +1,276 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlrunstats.sqc +** +** SAMPLE: How to perform runstats on a table containing columns with XML type +** +** DB2 APIs USED: +** db2Runstats -- Runstats +** +** SQL STATEMENT USED: +** SELECT +** +** STRUCTURES USED: +** db2ColumnData +** sqlca +** +** OUTPUT FILE: xmlrunstats.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +int XmlRunstats(void); +int SchemaNameGet(void); /* support function for getting schema name */ + +EXEC SQL BEGIN DECLARE SECTION; + char dbAlias[15]; + char user[129]; + char pswd[15]; + char tableName[129]; + char schemaName[129]; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + char nodeName[SQL_INSTNAME_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck3(argc, argv, dbAlias, nodeName, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\n THIS SAMPLE SHOWS "); + printf("HOW TO PERFROM RUNSTATS ON A TABLE CONTAINING COLUMNS WITH XML TYPE.\n"); + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + rc = XmlRunstats(); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if (rc != 0) + { + return rc; + } + + return 0; +} /* main */ + +/* Gets the schema name of the table */ +int SchemaNameGet(void) +{ + struct sqlca sqlca; + + /* get table schema name */ + EXEC SQL SELECT tabschema INTO :schemaName + FROM syscat.tables + WHERE tabname = :tableName; + EMB_SQL_CHECK("table schema name -- get"); + + /* get rid of spaces from the end of schemaName */ + strtok(schemaName, " "); + + return 0; +} /* SchemaNameGet */ + +/* Performs Runstats on the table with provided options */ +int XmlRunstats(void) +{ + int rc = 0; + struct sqlca sqlca; + char fullTableName[258]; + db2Uint32 versionNumber = db2Version970; + db2RunstatsData runStatData; + db2ColumnData *columnList[2]; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2 APIs:\n"); + printf(" db2Runstats -- Runstats\n"); + printf("TO UPDATE THE STATISTICS OF TABLE.\n"); + + /* get fully qualified name of the table */ + strcpy(tableName, "CUSTOMER"); + rc = SchemaNameGet(); + if (rc != 0) + { + return rc; + } + + strcpy(fullTableName, schemaName); + strcat(fullTableName, "."); + strcat(fullTableName, tableName); + + printf("Perform Runstats and Update statistics for the table: %s\n", fullTableName); + + printf("\n Performing Runstats on table CUSTOMER for all columns Cid, Info and Hisory \n"); + + /* runstats on table CUSTOMER for all columns including XML columns */ + runStatData.iSamplingOption = 0; + runStatData.piTablename = (unsigned char *) fullTableName; + runStatData.piColumnList = NULL; + runStatData.piColumnDistributionList = NULL; + runStatData.piColumnGroupList = NULL; + runStatData.piIndexList = NULL; + runStatData.iRunstatsFlags = DB2RUNSTATS_ALL_COLUMNS; + runStatData.iNumColumns = 0; + runStatData.iNumColdist = 0; + runStatData.iNumColGroups = 0; + runStatData.iNumIndexes = 0; + runStatData.iParallelismOption = 0; + runStatData.iTableDefaultFreqValues = 20; + runStatData.iTableDefaultQuantiles = -1; + runStatData.iUtilImpactPriority = 10; + + /* Performing Runstats */ + db2Runstats(versionNumber, &runStatData, &sqlca); + + DB2_API_CHECK("table -- runstats"); + + printf("\n Performing Runstats on table CUSTOMER for XML columns Info, History \n"); + + columnList[0] = (struct db2ColumnData *)malloc(sizeof(struct db2ColumnData)); + columnList[0]->piColumnName = (unsigned char *)"Info"; + columnList[0]->iColumnFlags = 0; + + columnList[1] = (struct db2ColumnData *)malloc(sizeof(struct db2ColumnData)); + columnList[1]->piColumnName = (unsigned char *)"History"; + columnList[1]->iColumnFlags = 0; + + /* runstats on table CUSTOMER for XML columns Info, History */ + runStatData.iSamplingOption = 0; + runStatData.piTablename = (unsigned char *) fullTableName; + runStatData.piColumnList = columnList; + runStatData.piColumnDistributionList = NULL; + runStatData.piColumnGroupList = NULL; + runStatData.piIndexList = NULL; + runStatData.iRunstatsFlags = 0; + runStatData.iNumColumns = 2; + runStatData.iNumColdist = 0; + runStatData.iNumColGroups = 0; + runStatData.iNumIndexes = 0; + runStatData.iParallelismOption = 0; + runStatData.iTableDefaultFreqValues = 30; + runStatData.iTableDefaultQuantiles = -1; + + /* Performing Runstats */ + db2Runstats(versionNumber, &runStatData, &sqlca); + + DB2_API_CHECK("table -- runstats"); + + printf("\n Performing runstats on table CUSTOMER for XML columns Info, History \n"); + printf("with the following options:\n"); + printf(" Distribution statistics for all partitions\n"); + printf(" Frequent values for table set to 30\n"); + printf(" Quantiles for table set to -1 (NUM_QUANTILES as in DB Cfg)\n"); + printf(" Allow others to have read-only while gathering statistics\n"); + + columnList[1]->iColumnFlags = DB2RUNSTATS_COLUMN_LIKE_STATS; + + /* runstats on table CUSTOMER for XML columns with the following options */ + runStatData.iSamplingOption = 0; + runStatData.piTablename = (unsigned char *) fullTableName; + runStatData.piColumnList = columnList; + runStatData.piColumnDistributionList = NULL; + runStatData.piColumnGroupList = NULL; + runStatData.piIndexList = NULL; + runStatData.iRunstatsFlags = DB2RUNSTATS_KEY_COLUMNS | + DB2RUNSTATS_DISTRIBUTION | DB2RUNSTATS_ALLOW_READ; + runStatData.iNumColumns = 2; + runStatData.iNumColdist = 0; + runStatData.iNumColGroups = 0; + runStatData.iNumIndexes = 0; + runStatData.iParallelismOption = 0; + runStatData.iTableDefaultFreqValues = 30; + runStatData.iTableDefaultQuantiles = -1; + + /* Performing Runstats */ + db2Runstats(versionNumber, &runStatData, &sqlca); + + DB2_API_CHECK("table -- runstats"); + + printf("\nPerforming runstats on table CUSTOMER for XML columns Info, History \n"); + printf("with the following options:\n"); + printf(" excluding xml columns \n"); + + /* runstats on table CUSTOMER with EXCLUDING XML COLUMNS option + This option allows to exclude all XML type columns from statistics collection. + Any XML type columns that have been specified in the cols-list will be ignored + and no statistics will be collected from them. This clause facilitates the collection + of statistics on non-XML columns. + */ + runStatData.iSamplingOption = 0; + runStatData.piTablename = (unsigned char *) fullTableName; + runStatData.piColumnList = columnList; + runStatData.piColumnDistributionList = NULL; + runStatData.piColumnGroupList = NULL; + runStatData.piIndexList = NULL; + runStatData.iRunstatsFlags = DB2RUNSTATS_DISTRIBUTION | + DB2RUNSTATS_KEY_COLUMNS | DB2RUNSTATS_EXCLUDING_XML; + runStatData.iNumColumns = 2; + runStatData.iNumColdist = 0; + runStatData.iNumColGroups = 0; + runStatData.iNumIndexes = 0; + runStatData.iParallelismOption = 0; + runStatData.iTableDefaultFreqValues = 30; + runStatData.iTableDefaultQuantiles = -1; + + /* Performing Runstats */ + db2Runstats(versionNumber, &runStatData, &sqlca); + + DB2_API_CHECK("table -- runstats"); + + free(*columnList); + + printf("\nMake sure to rebind all packages that use this table.\n"); + + return rc; +} /* XmlRunstats */ diff --git a/xml/c/xmlschema.sqc b/xml/c/xmlschema.sqc new file mode 100644 index 0000000..98102f7 --- /dev/null +++ b/xml/c/xmlschema.sqc @@ -0,0 +1,320 @@ +/***************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlschema.sqc +** +** SAMPLE: How to register xml schema +** +** SAMPLE USAGE SCENARIO: Consider a user who needs to insert an XML type value +** into the table. The user would like to ensure that the XML value conforms to a +** deterministic XML schema. +** +** PROBLEM: User has schema's for all the XML values and like to validate the values +** as per schema while inserting it to the tables. +** +** SOLUTION: +** To achieve the goal, the sample will follow the following steps: +** a) Register the primary XML schema +** b) Add the XML schema documents to the primary XML schema to ensure that the +** schema is deterministic +** c) Insert an XML value into an existing XML column and perform validation +** +** SQL STATEMENTS USED: +** PREPARE +** EXECUTE +** +** STORED PROCEDURE USED +** SYSPROC.XSR_REGISTER +** SYSPROC.XSR_ADDSCHEMADOC +** SYSPROC.XSR_COMPLETE +** +** SQL/XML FUNCTION USED +** XMLVALIDATE +** XMLPARSE +** +** PREREQUISITE: copy product.xsd, order.xsd, +** customer.xsd, header.xsd Schema files, order.xml XML +** document from xml/data directory to working +** directory. +** OUTPUT FILE: xmlschema.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilemb.h" + +/* support functions */ +int registerxmlschema(void); +int addxmlschemadoc(char *); +int insertValidatexml(void); + +EXEC SQL INCLUDE SQLCA; + +EXEC SQL BEGIN DECLARE SECTION; + short in_ind = 0; + short null_ind = -1; + char RelSchema[1024]; + char SchemaName[1024]; + char SchemaLocation[1024]; + char PrimaryDocument[1024]; + char MultipleSchema1[1024]; + char MultipleSchema2[1024]; + char MultipleSchema3[1024]; + char XmlDocName[1024]; + short isshred=0; + SQL TYPE IS BLOB_FILE xmlfile; + SQL TYPE IS BLOB(1M) *xmlobjp; + SQL TYPE IS BLOB_FILE xsdfile; + SQL TYPE is BLOB(1M) *xsdobjp; + SQL TYPE IS BLOB(1M) temp; + char stmt[16384]; + sqlint32 poid=10; + char status[10]; + char name[128]; + char schema[128]; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + strcpy((char *)RelSchema,"POSAMPLE"); + strcpy((char *)SchemaName,"order"); + strcpy((char *)SchemaLocation, "http://www.test.com/order"); + strcpy((char *)PrimaryDocument,"order.xsd"); + strcpy((char *)MultipleSchema1,"header.xsd"); + strcpy((char *)MultipleSchema2,"customer.xsd"); + strcpy((char *)MultipleSchema3,"product.xsd"); + strcpy((char *)XmlDocName,"order.xml"); + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + /* register the xmlschema */ + rc=registerxmlschema(); + + /* select from catalog tables to check the entry for the schema registered */ + + EXEC SQL SELECT objectschema, objectname INTO :schema,:name FROM syscat.xsrobjects WHERE objectname='ORDER'; + EMB_SQL_CHECK("SELECT FROM SYSCAT.XSROBJECTS"); + + printf("-------------------------------------------------------------------------\n"); + printf("\n select the information about the registered schema from catalog table"); + printf("\n RELATIONAL SCHEMA RELATIONAL ID FOR XML SCHEMA\n"); + printf(" %s %s \n ",schema, name); + + /* insert the xml value validating with the registered schema */ + rc=insertValidatexml(); + + /* Delete the row */ + EXEC SQL DELETE FROM purchaseorder WHERE poid=10; + EMB_SQL_CHECK("DELETE FROM PURCHASEORDER"); + + /* drop the registered schema */ + EXEC SQL DROP XSROBJECT posample.order; + EMB_SQL_CHECK("DROP XSROBJECT ORDER"); + EXEC SQL COMMIT; +} /* main */ + +int registerxmlschema() +{ + struct sqlca sqlca; + FILE *testfile; + strcpy(xsdfile.name, PrimaryDocument); + xsdfile.name_length = strlen(xsdfile.name); + xsdfile.file_options = SQL_FILE_READ; + + /* read the BLOB file into a BLOB variable */ + if (xsdfile.name_length > 0) + { + testfile = fopen( xsdfile.name, "r" ); + if ( testfile != NULL ) + { + fclose( testfile ); + if ((xsdobjp = (struct xsdobjp_t *) + malloc (sizeof (*xsdobjp))) != NULL ) + { + memset(xsdobjp, 0, sizeof(*xsdobjp)); + EXEC SQL VALUES (:xsdfile) INTO :*xsdobjp; + } + } + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xsdfile.name); + exit(0); + } + } + + + printf("----------------------------------------------------------------\n"); + printf("\nFilename : %s\n",xsdfile.name); + printf("XSD Data : %s\n",xsdobjp->data); + printf("CALLING SYSPROC.XSR_REGISTER TO REGISTER THE SCHEMA %s......\n\n",SchemaName); + + /* call SYSPROC.XSR_REGISTER to register the primary schema */ + EXEC SQL CALL SYSPROC.XSR_REGISTER(:RelSchema, + :SchemaName, + :SchemaLocation, + :*xsdobjp, + :*xsdobjp:null_ind ); + + EMB_SQL_CHECK("CALLING SYSPROC.XSR_REGISTER"); + + /* call the function to all the xml schema document to primary schema */ + /* add schema document header.xsd */ + addxmlschemadoc(MultipleSchema1); + + /* add schema document customer.xsd */ + addxmlschemadoc(MultipleSchema2); + + /* add schema document product.xsd */ + addxmlschemadoc(MultipleSchema3); + + /* call SYSPROC.XSR_COMPLETE the complete the registeration of the schema */ + printf("----------------------------------------------------------------\n"); + printf("CALLING SYSPROC.XSR_COMPLETE TO COMPLETE THE SCHEMA REGISTERATION.....\n\n"); + EXEC SQL CALL SYSPROC.XSR_COMPLETE(:RelSchema, + :SchemaName, + :*xsdobjp:null_ind, + :isshred); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_COMPLETE"); + EXEC SQL COMMIT; + return 0; +} /* registerxmlschema */ + + +int addxmlschemadoc(char *xmlschemadoc) +{ + FILE *testfile; + strcpy((char *)RelSchema,"POSAMPLE"); + strcpy((char *)SchemaName,"order"); + strcpy((char *)SchemaLocation, "http://www.test.com/order"); + strcpy(xsdfile.name, xmlschemadoc); + xsdfile.name_length = strlen(xsdfile.name); + xsdfile.file_options = SQL_FILE_READ; + + /* read the xsd file into a BLOB variable */ + if (xsdfile.name_length > 0) + { + testfile = fopen( xsdfile.name, "r" ); + if ( testfile != NULL ) + { + fclose( testfile ); + if ((xsdobjp = (struct xsdobjp_t *) + malloc (sizeof (*xsdobjp))) != NULL ) + { + memset(xsdobjp, 0, sizeof(*xsdobjp)); + EXEC SQL VALUES (:xsdfile) INTO :*xsdobjp; + } + } + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xsdfile.name); + exit(0); + } + } + + printf("-----------------------------------------------------------------------------\n"); + printf("\nFilename : %s\n",xsdfile.name); + printf("Data : %s\n",xsdobjp->data); + /* call SYSPROC.XSR_ADDSCHEMADOC to add the xml schema document */ + printf("CALLING SYSPROC.XSR_ADDSCHEMADOC TO ADD THE SCHEMA DOCUMENT %s......\n\n",xmlschemadoc); + EXEC SQL CALL SYSPROC.XSR_ADDSCHEMADOC(:RelSchema, + :SchemaName, + :SchemaLocation, + :*xsdobjp, + :*xsdobjp:null_ind ); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_ADDSCHEMADOC FOR FIRST DOCUMENT"); + return 0; +} /* addxmlschemadoc */ + +int insertValidatexml() +{ + FILE *testfile=NULL; + strcpy(status,"shipped"); + strcpy(xmlfile.name,"order.xml"); + xmlfile.name_length = strlen(xmlfile.name); + xmlfile.file_options = SQL_FILE_READ; + + /* read the xml value */ + if (xmlfile.name_length > 0) + { + testfile = fopen( xmlfile.name, "r" ); + if ( testfile != NULL ) + { + fclose(testfile); + if ((xmlobjp = (struct xmlobjp_t *) + malloc (sizeof (*xmlobjp))) != NULL ) + { + memset(xmlobjp, 0, sizeof(*xmlobjp)); + EXEC SQL VALUES (:xmlfile) INTO :*xmlobjp; + } + } + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xmlfile.name); + exit(0); + } + } + printf("-------------------------------------------------------------------------\n"); + printf("Filename : %s\n",xmlfile.name); + printf("Data : %s\n",xmlobjp->data); + printf("\n inserting xml value......"); + sprintf( stmt,"INSERT INTO PURCHASEORDER (poid,status,porder)" + " VALUES(?,?,xmlvalidate(xmlparse(document cast(? as BLOB))" + "ACCORDING TO XMLSCHEMA ID posample.order))"); + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("PREAPRE STATEMENT"); + EXEC SQL EXECUTE s1 using :poid, :status, :*xmlobjp; + EMB_SQL_CHECK("EXECUTE STATEMENT"); + return 0; +} /* insertValidatexml */ + diff --git a/xml/c/xmltrig.sqc b/xml/c/xmltrig.sqc new file mode 100644 index 0000000..ff7b2ac --- /dev/null +++ b/xml/c/xmltrig.sqc @@ -0,0 +1,562 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SAMPLE FILE NAME: xmltrig.sqc +** +** PURPOSE: This sample shows how triggers are used to enforce automatic +** validation while inserting/updating XML documents +** +** USAGE SCENARIO: When a customer places a purchase order request an entry +** is made in the "customer" table by inserting customer +** information and his history details. If the customer is +** new, and is placing request for the first time with this +** supplier, then the history column in the "customer" table +** wil be NULL. If he's an old customer, data in "customer" +** table info and history columns are inserted. +** +** PREREQUISITE: +** On Unix : copy boots.xsd from /sqllib/samples/xml/data +** directory to current directory. +** On Windows: copy boots.xsd from /sqllib/samples/xml/data +** directory to current directory. +** +** EXECUTION: bldapp xmltrig +** xmltrig +** +** INPUTS: NONE +** +** OUTPUTS: The last trigger statement which uses XMLELEMENT on transition +** variable will fail. All other trigger statements will succeed. +** +** OUTPUT FILE: xmltrig.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** CREATE TRIGGER +** INSERT +** DELETE +** DROP +** +** SQL/XML FUNCTIONS USED: +** XMLDOCUMENT +** XMLPARSE +** XMLVALIDATE +** XMLELEMENT +** +** +***************************************************************************** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +** +***************************************************************************** +** SAMPLE DESCRIPTION +** +***************************************************************************** +** 1. Register boots.xsd schema with http://posample1.org namespace. +** +** 2. This sample consists of four different cases of create trigger +** statements to show automatic validation of xml documents with +** triggers. +** +** Case1: This first trigger statement shows how to assign values to +** non-xml transition variables, how to validate XML documents and +** also to show that NULL values can be assigned to XML transition +** variables in triggers. +** +** Case2: Create a BEFORE INSERT trigger to validate info column in +** "customer" table and insert a value for history column without +** any validation +** +** Case3: Create a BEFORE UPDATE trigger with ACCORDING TO clause used +** with WHEN clause.This trigger statement shows that only when WHEN +** condition is satisfied, the action part of the trigger will be +** executed.WHEN conditions are used with BEFORE UPDATE triggers. +** +** Case4: Create a BEFORE INSERT trigger with XMLELEMENT function being +** used on a transition variable. This case results in a failure as only +** XMLVALIDATE function is allowed on transition variables. +** +** NOTE: In a typical real-time scenario, DBAs will create triggers and users +** will insert records using multiple insert/update statements, not just +** one insert statement as shown in this sample. +****************************************************************************/ +/* INCLUDE ALL HEADER FILES */ +/***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +/***************************************************************************/ +/* DECLARE ALL HOST VARIABLES */ +/***************************************************************************/ +EXEC SQL BEGIN DECLARE SECTION; /* Start of declare section */ + char dbAlias[700]; + char user[700]; + char pswd[700]; + short custid; + SQL TYPE IS XML AS CLOB( 100K ) info; + SQL TYPE IS XML AS CLOB( 10K ) history; + short null_ind = -1; + char RelSchema[1024]; + char SchemaName[1024]; + char SchemaLocation[1024]; + char PrimaryDocument[1024]; + short isshred=0; + SQL TYPE IS BLOB_FILE xsdfile; + SQL TYPE is BLOB(1M) *xsdobjp; + char stmt[16384]; +EXEC SQL END DECLARE SECTION; /* End of declare section */ + + +int main(int argc, char *argv[]) +{ + + int rc = 0; + struct sqlca sqlca; + int len; + + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\n\nTHIS SAMPLE SHOWS HOW TO AUTOMATE XML DATA "); + printf("VALIDATION USING TRIGGERS\n"); + + /*************************************************************************/ + /* Connect to SAMPLE database */ + /*************************************************************************/ + + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /*************************************************************************/ + /* Register boots schema */ + /*************************************************************************/ + + + rc = registerxmlschema(); + if (rc != 0) + { + return rc; + } + + + /*************************************************************************/ + /* Case1: This first trigger statement shows how to assign values to */ + /* non-xml transition variables, how to validate XML documents and */ + /* also to show that NULL values can be assigned to XML transition */ + /* variables in triggers. */ + /*************************************************************************/ + + printf("----------------------------------------------------------\n\n"); + + printf("\n\nCREATE TRIGGER TO VALIDATE XML DOC BEFORE INSERTING "); + printf("AND SETTING ONE XML COLUMN VALUE TO NULL\n"); + + + printf("\n\nCREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON customer"); + printf("\n REFERENCING NEW AS n"); + printf("\nFOR EACH ROW MODE DB2SQL"); + printf("\nBEGIN ATOMIC"); + printf("\n set n.Cid = 5000"); + printf("\n set n.info = xmlvalidate(n.info ACCORDING TO XMLSCHEMA "); + printf("ID customer"); + printf("\n set n.history = NULL"); + printf("\nEND"); + + /* Assigning value to one xml column and NULL to another xml column + value */ + EXEC SQL CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON CUSTOMER + REFERENCING NEW AS n + FOR EACH ROW MODE DB2SQL + BEGIN ATOMIC + set n.Cid = 5000; + set n.info = xmlvalidate(n.info ACCORDING TO XMLSCHEMA + ID customer); + set n.history = NULL; + END; + EMB_SQL_CHECK("CREATE TRIGGER"); + + printf("\n\nUSE THE SQL STATEMENT: \n"); + printf(" INSERT INTO \n"); + printf("TO INSERT DATA INTO CUSTOMER TABLE USING VALUES\n"); + + strcpy(stmt, "INSERT INTO customer VALUES (1008,xmlparse(document "\ + "'"\ + "Larry Menard"\ + "223 Koramangala ring Road"\ + "TorontoOntario"\ + "M4C 5K8"\ + "905-555-9146416-555-6121 "\ + "Goose Defender416-555-1943"\ + "' preserve whitespace), NULL)"); + + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO CUSTOMER"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + EXEC SQL SELECT Cid, info INTO :custid, :info + FROM customer + WHERE Cid = 5000; + EMB_SQL_CHECK("SELECT FROM CUSTOMER"); + + printf("\n\n SELECT Cid, info INTO :custid, :info FROM customer "); + printf("WHERE Cid = 5000\n\n"); + printf("custid info\n"); + printf("------ ---- \n"); + printf("%d ", custid); + + /* print info column data */ + for(len = 0; len < info.length; len++) + { + printf("%c", info.data[len]); + } + + EXEC SQL DROP TRIGGER TR1; + EMB_SQL_CHECK("DROP TRIGGER"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + /*************************************************************************/ + /* Case2: Create a BEFORE INSERT trigger to validate info column in */ + /* "customer" table and insert a value for history column without */ + /* any validation */ + /*************************************************************************/ + + printf("\n\n----------------------------------------------------------\n\n"); + printf("\n\nCREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON customer"); + printf("\n REFERENCING NEW AS n"); + printf("\nFOR EACH ROW MODE DB2SQL"); + printf("\nBEGIN ATOMIC"); + printf("\n set n.Cid = 5001"); + printf("\n set n.info = xmlvalidate(n.info ACCORDING TO XMLSCHEMA "); + printf("ID customer)"); + printf("\n set n.history = \'suzan\'"); + printf("\nEND\n\n"); + + + /* Assinging values for both xml columns but validating only one column + data */ + EXEC SQL CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON customer + REFERENCING NEW AS n + FOR EACH ROW MODE DB2SQL + BEGIN ATOMIC + set n.Cid = 5001; + set n.info = xmlvalidate(n.info ACCORDING TO XMLSCHEMA ID customer); + set n.history = ' \ + suzan'; + END; + EMB_SQL_CHECK("CREATE TRIGGER"); + + printf("\n\nUSE THE SQL STATEMENT: \n"); + printf(" INSERT INTO \n"); + printf("TO INSERT DATA INTO CUSTOMER TABLE USING VALUES\n"); + + strcpy(stmt, "INSERT INTO CUSTOMER VALUES (1009, xmlparse(document "\ + "'"\ + "Larry Menard223 Koramangala ring Road"\ + "BangaloreOntario"\ + "M4C 5K8"\ + "905-555-9146416-555-6121 "\ + "Tim Luther416-555-1943"\ + "'), NULL)"); + + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO CUSTOMER"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + EXEC SQL SELECT Cid, info, history INTO :custid, :info, :history + FROM customer WHERE Cid = 5001; + EMB_SQL_CHECK("SELECT FROM CUSTOMER"); + + printf("\n\n SELECT Cid, info, history INTO :custid, :info, :history"); + printf(" FROM customer WHERE Cid = 5001\n\n"); + printf("custid info history\n"); + printf("------ ---- -------\n"); + printf("%d ", custid); + + /* print info column data */ + for(len = 0; len < info.length; len++) + { + printf("%c", info.data[len]); + } + + printf(" "); + + /* print history column data */ + for(len = 0; len < history.length; len++) + { + printf("%c", history.data[len]); + } + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + /*************************************************************************/ + /* Case3: Create a BEFORE UPDATE trigger with ACCORDING TO clause used*/ + /* with WHEN clause.This trigger statement shows that only when WHEN */ + /* condition is satisfied, the action part of the trigger will be */ + /* executed.WHEN conditions are used with BEFORE UPDATE triggers. */ + /*************************************************************************/ + + printf("\n\n----------------------------------------------------------\n\n"); + printf("\n\nCREATE TRIGGER TR2 NO CASCADE BEFORE UPDATE ON customer"); + printf("\n REFERENCING NEW AS n"); + printf("\nFOR EACH ROW MODE DB2SQL"); + printf("\nWHEN (n.info IS NOT VALIDATED ACCORDING TO XMLSCHEMA ID CUSTOMER)"); + printf("\nBEGIN ATOMIC"); + printf("\n set n.Cid = 5002"); + printf("\n set n.info = xmlvalidate(n.info ACCORDING TO XMLSCHEMA ID customer)"); + printf("\n set n.history = \'malaika\'"); + printf("\nEND"); + + /* using ACCORDING TO clause in WHEN clause */ + EXEC SQL CREATE TRIGGER TR2 NO CASCADE BEFORE UPDATE ON customer + REFERENCING NEW AS n + FOR EACH ROW MODE DB2SQL + WHEN (n.info IS NOT VALIDATED ACCORDING TO XMLSCHEMA ID CUSTOMER) + BEGIN ATOMIC + set n.Cid = 5002; + set n.info = xmlvalidate(n.info ACCORDING TO XMLSCHEMA ID customer); + set n.history = 'malaika'; + END; + EMB_SQL_CHECK("CREATE TRIGGER"); + + + printf("\n\nUSE THE SQL STATEMENT: \n"); + printf(" UPDATE \n"); + printf("TO UPDATE DATA IN CUSTOMER TABLE WHERE Cid = 5001\n"); + + strcpy(stmt, "UPDATE CUSTOMER SET customer.info = XMLPARSE(document "\ + "'"\ + " Russel223 Koramangala ring Road"\ + "BangaloreKarnataka"\ + "M4C 5K8"\ + "905-555-9146416-555-6121 "\ + "Vincent luther416-555-1943"\ + "' preserve whitespace) WHERE Cid=5001"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("UPDATE CUSTOMER INFO"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + EXEC SQL SELECT Cid, info, history INTO :custid, :info, :history + FROM customer + WHERE Cid = 5002; + EMB_SQL_CHECK("SELECT FROM CUSTOMER"); + + + printf("\n\n SELECT Cid, info, history INTO :custid, :info, :history "); + printf("FROM customer WHERE Cid = 5002\n\n"); + printf("custid info history \n"); + printf("------ ---- --------\n"); + printf("%d ", custid); + + /* print the info column data */ + for(len = 0; len < info.length; len++) + { + printf("%c", info.data[len]); + } + + printf(" "); + + /* print history column data */ + for(len = 0; len < history.length; len++) + { + printf("%c", history.data[len]); + } + + + EXEC SQL DROP TRIGGER TR1; + EMB_SQL_CHECK("DROP TRIGGER"); + + EXEC SQL DROP TRIGGER TR2; + EMB_SQL_CHECK("DROP TRIGGER"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + /* rollback all the changes made to the customer table */ + EXEC SQL DELETE FROM CUSTOMER where Cid > 1005; + EMB_SQL_CHECK("DELETE FROM CUSTOMER"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + /*************************************************************************/ + /* Case4: Create a BEFORE INSERT trigger with XMLELEMENT function */ + /* being used on a tranistion variable. This case results in a */ + /* failure case, as only XMLVALIDATE function is allowed */ + /* on transition variables. */ + /*************************************************************************/ + + /* create table boots */ + EXEC SQL CREATE TABLE boots (Cid int, xmldoc1 XML, xmldoc2 XML); + EMB_SQL_CHECK("CREATE TABLE BOOTS"); + + printf("\n\n-----------------------------------------------\n\n"); + printf("CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON BOOTS"); + printf("\nREFERENCING NEW as n"); + printf("\nFOR EACH ROW MODE DB2SQL"); + printf("\nBEGIN ATOMIC"); + printf("\n set n.Cid=5004;"); + printf("\n set n.xmldoc1 = XMLVALIDATE(xmldoc1 ACCORDING TO "); + printf("\n XMLSCHEMA URI 'http://posample1.org');"); + printf("\n set n.xmldoc2 = XMLDOCUMENT(XMLELEMENT(name adidas, n.xmldoc2))"); + printf("\nEND"); + + /* Trigger creation itself fails as XMLELEMENT is not allowed + on transition variable */ + EXEC SQL CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON boots + REFERENCING NEW as n + FOR EACH ROW MODE DB2SQL + BEGIN ATOMIC + set n.Cid=5004; + set n.xmldoc1 = XMLVALIDATE(xmldoc1 ACCORDING TO XMLSCHEMA URI + 'http://posample1.org'); + set n.xmldoc2 = XMLDOCUMENT(XMLELEMENT(name adidas, n.xmldoc2)); + END; + + printf("ERROR: SQL Code = %d\n", sqlca.sqlcode); + rc = sqlaintp(stmt, sizeof(stmt), 16384, &sqlca); + printf("%s", stmt); + + EXEC SQL ROLLBACK; + EMB_SQL_CHECK("ROLLBACK"); + + EXEC SQL DROP XSROBJECT POSAMPLE1.BOOTS; + EMB_SQL_CHECK("DROP XSROBJECT"); + + + /*************************************************************************/ + /* Disconnect from the database */ + /*************************************************************************/ + + + rc = DbDisconn(dbAlias); + if(rc != 0) + { + return rc; + } + + + return 0; +} + +int registerxmlschema() +{ + struct sqlca sqlca; + FILE *testfile; + + /* Initialize host variables for schema registration */ + strcpy((char *)RelSchema,"POSAMPLE1"); + strcpy((char *)SchemaName,"boots"); + strcpy((char *)SchemaLocation, "http://www.test.com/order"); + strcpy((char *)PrimaryDocument,"boots.xsd"); + strcpy(xsdfile.name, PrimaryDocument); + + xsdfile.name_length = strlen(xsdfile.name); + xsdfile.file_options = SQL_FILE_READ; + + + /* read the BLOB file into a BLOB variable */ + if (xsdfile.name_length > 0) + { + testfile = fopen( xsdfile.name, "r" ); + if ( testfile != NULL ) + { + fclose( testfile ); + if ((xsdobjp = (struct xsdobjp_t *) + malloc (sizeof (*xsdobjp))) != NULL ) + { + memset(xsdobjp, 0, sizeof(*xsdobjp)); + EXEC SQL VALUES (:xsdfile) INTO :*xsdobjp; + } + } + else + { + printf("fopen() error.\n"); + printf("Error accessing file: %s \n", xsdfile.name); + exit(0); + } + } + + + printf("----------------------------------------------------------------\n"); + printf("\nFilename : %s\n",xsdfile.name); + printf("XSD Data : %s\n",xsdobjp->data); + printf("CALLING SYSPROC.XSR_REGISTER TO REGISTER THE SCHEMA %s......\n\n",SchemaName); + + /* call SYSPROC.XSR_REGISTER to register the primary schema */ + EXEC SQL CALL SYSPROC.XSR_REGISTER(:RelSchema, + :SchemaName, + :SchemaLocation, + :*xsdobjp, + :*xsdobjp:null_ind ); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_REGISTER"); + + /* call SYSPROC.XSR_COMPLETE the complete the registeration of the schema */ + printf("----------------------------------------------------------------\n"); + printf("CALLING SYSPROC.XSR_COMPLETE TO COMPLETE THE SCHEMA REGISTERATION.....\n\n"); + EXEC SQL CALL SYSPROC.XSR_COMPLETE(:RelSchema, + :SchemaName, + :*xsdobjp:null_ind, + :isshred); + EMB_SQL_CHECK("CALLING SYSPROC.XSR_COMPLETE"); + EXEC SQL COMMIT; + return 0; +} /* registerxmlschema */ + diff --git a/xml/c/xmludfs.sqc b/xml/c/xmludfs.sqc new file mode 100644 index 0000000..06cd50b --- /dev/null +++ b/xml/c/xmludfs.sqc @@ -0,0 +1,737 @@ +/*************************************************************************** +** (c) Copyright IBM Corp. 2008 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SAMPLE FILE NAME: xmludfs.sqc +** +** PURPOSE: The purpose of this sample is to show extended support of XML for +** sourced UDF and SQL bodied UDF in serial and DPF environment +** for DB2 Cobra. +** +** USAGE SCENARIO: The scenario is for a Book Store that has two types of +** customers, retail customers and corporate customers. Corporate +** customers do bulk purchases of books for their company libraries. +** The Book Store also maintains list of �registered customers� +** who are frequent buyers from the store and have registered +** themselves with the store. The store has a DBA, sales clerk and a +** manager for maintaining the database and to run queries on different +** tables to view the book sales. +** +** The store manager frequently queries various tables to get +** information such as contact numbers of different departments, +** location details, location manager details, employee details +** in order to perform various business functions like promoting +** employees, analysing sales, giving awards and bonus to employees +** based on their sales. +** +** The manager is frustrated writing the same queries every time to +** get the information and observes performance degradation as well. +** So he decides to create a user-defined function and a stored +** procedure for each of his requirements. +** +** PREREQUISITE: NONE +** +** EXECUTION: bldapp xmludfs; +** xmludfs +** +** INPUTS: NONE +** +** OUTPUTS: Successfull execution of all UDFs and stored procedures. +** +** OUTPUT FILE: xmludfs.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** CREATE TABLE +** INSERT +** DROP +** +** SQL/XML FUNCTIONS USED: +** XMLPARSE +** XMLQUERY +** XMLEXISTS +** +***************************************************************************** +** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +***************************************************************************** +** +** SAMPLE DESCRIPTION +** +***************************************************************************** +** 1. UDF Scalar function which takes an XML variable as input the parameter +** and returns XML value as output. +** +** 2. UDF Table function which takes an XML variable as input the parameter +** and returns table with XML values as output. +** +** 3. Sourced UDF which takes an XML variable as the input parameter +** and returns XML value as output. +** +** 4. SQL bodied UDF which takes an XML variable as the input parameter +** and returns a table with XML values as output. This UDF +** internally calls a stored procedure which takes an XML variable +** as the input parameter and returns an XML value as output. +************************************************************************ +** +** INCLUDE ALL HEADER FILES +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +/***************************************************************************/ +/* DECLARE ALL HOST VARIABLES */ +/***************************************************************************/ + +EXEC SQL BEGIN DECLARE SECTION; /* Start of declare section */ + struct { + short len; + char arr[50+1]; + } name; + char dbAlias[700]; + char user[700]; + char pswd[700]; + sqlint32 emp_id; + short sk_lvl; + sqlint32 sales; + double sal; + SQL TYPE IS XML AS CLOB (1024K) xmldata; + char stmt[16384]; +EXEC SQL END DECLARE SECTION; /* End of declare section */ + +int setuptables(); +int scalarUDF(); +int tableUDF(); +int sourcedUDF(); +int invokespfromUDF(); +int cleanuptables(); + +int main(int argc, char *argv[]) +{ + + int rc = 0; + struct sqlca sqlca; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /*************************************************************************/ + /* Connect to SAMPLE database */ + /*************************************************************************/ + + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\n\n This sample shows how to pass XML type variables"); + printf(" as input parameters, return type or local "); + printf(" variables in SQL bodied UDFs\n\n"); + + rc = setuptables(); + rc = scalarUDF(); + rc = sourcedUDF(); + rc = tableUDF(); + rc = invokespfromUDF(); + rc = cleanuptables(); + +} + +int setuptables() +{ + + printf("---------------------------------\n"); + printf("Setting up tables for the sample\n"); + printf("---------------------------------\n"); + + strcpy(stmt, "CREATE TABLE sales_department(dept_id CHAR(10), dept_info XML)"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE"); + printf("%s\n\n", stmt); + + strcpy(stmt, "CREATE TABLE sales_employee (emp_id INTEGER, total_sales INTEGER, " + "emp_details XML)"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE"); + printf("%s\n\n", stmt); + + strcpy(stmt, "CREATE TABLE performance_bonus_employees(bonus_info XML)"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE"); + printf("%s\n\n", stmt); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + strcpy(stmt, "INSERT INTO sales_employee VALUES (5001, 40000, XMLPARSE(document " + "'" + "Lethar Kessy" + "
" + "555 M G Road" + "Bangalore" + "Karnataka" + "India" + "411004" + "
" + "" + "9435344354" + "" + "DS02" + "7" + "40000" + "25500" + "Sr. Manager" + "regular" + "Harry " + "
'))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO "); + printf("%s\n\n", stmt); + + + strcpy(stmt, "INSERT INTO sales_employee VALUES (5002, 50000, XMLPARSE(document " + "'" + "Mathias Jessy" + "
" + "Indra Nagar Road No. 5" + "Bangalore" + "Karnataka" + "India" + "411004" + "
" + "" + "9438884354" + "" + "DS02" + "6" + "50000" + "22500" + "Manager" + "regular" + "Harry" + "
'))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO "); + printf("%s\n\n", stmt); + + strcpy(stmt, "INSERT INTO sales_employee VALUES (5003, 40000, XMLPARSE(document " + "'" + "Mohan Kumar" + "
" + "Vijay Nagar Road No. 5" + "Bangalore" + "Karnataka" + "India" + "411004" + "
" + "" + "9438881234" + "" + "DS02" + "5" + "40000" + "15500" + "Associate Manager" + "regular" + "Harry" + "
'))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO "); + printf("%s\n\n", stmt); + + strcpy(stmt, "INSERT INTO sales_department VALUES ('DS02', XMLPARSE(document " + "'" + "sales" + "" + "Harry Thomas" + "" + "9732432423" + "" + "" + "
" + "Bannerghatta" + "Bangalore" + "Karnataka" + "India" + "560012" + "
" + "" + "080-23464879" + "080-56890728" + "080-45282976" + "" + "
'))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO "); + printf("%s\n\n", stmt); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT "); + return 0; +} + +/*----------------------------------------------------------------------- +-- 1. UDF Scalar function which takes an XML variable as input parameter +-- and returns an XML value as output. +-------------------------------------------------------------------------*/ + +int scalarUDF() +{ + int rc = 0, count; + + printf("---------------------------------\n"); + printf("Create a scalar function 'getDeptContactNumbers' which "); + printf("returns a list of department phone numbers\n"); + printf("---------------------------------\n"); + + strcpy(stmt, "CREATE FUNCTION getDeptContactNumbers(dept_info_p XML) " + "RETURNS XML " + "LANGUAGE SQL " + "SPECIFIC contactNumbers " + "NO EXTERNAL ACTION " + "BEGIN ATOMIC " + "RETURN XMLQuery('document {{" + "$dep/department/phone}}' " + "PASSING dept_info_p as \"dep\"); " + "END"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE FUNCTION "); + printf("%s\n\n", stmt); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT "); + + printf("--------------------------------------------------\n"); + printf("Call scalar UDF 'getDeptContactNumbers' to get contact"); + printf(" numbers of the department \"DS02\"\n\n"); + printf("--------------------------------------------------\n"); + strcpy(stmt, "SELECT getDeptContactNumbers(sales_department.dept_info)" + " FROM sales_department " + " WHERE dept_id = 'DS02'"); + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("PREPARE s1"); + printf("%s\n\n", stmt); + + EXEC SQL DECLARE c1 CURSOR FOR s1; + EMB_SQL_CHECK("DECLARE c1"); + + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN c1"); + + EXEC SQL FETCH c1 INTO :xmldata; + EMB_SQL_CHECK("FETCH c1"); + + for (count = 0; count < xmldata.length; count++) + { + printf("%c", xmldata.data[count]); + } + printf("\n"); + + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("CLOSE c1"); + + return 0; +} + +/*------------------------------------------------------------------------ +-- 2. UDF Table function which takes an XML variable as input parameter +-- and returns a table with XML values as output. +--------------------------------------------------------------------------*/ + +int tableUDF() +{ + + int count = 0; + struct sqlca sqlca; + + printf("\n\n---------------------------------\n"); + printf("The store opens new branches in different parts of the city. "); + printf("The book store manager wants to promote senior managers and associate "); + printf("managers and designate them to manage these new branches. He wants to "); + printf("update the skill level and salaries of all the promoted managers in the"); + printf("sales_employee table. He asks the DBA to create a table function for "); + printf("this requirement. The DBA creates the 'updatePromotedEmployeesInfo' "); + printf("table function. This function updates the skill level and salaries of"); + printf("the promoted managers in sales_employee table and returns details of "); + printf("all the managers who got promoted. \n"); + printf("---------------------------------\n"); + + strcpy(stmt, "CREATE FUNCTION updatePromotedEmployeesInfo(emp_id_p INTEGER) " + "RETURNS TABLE (name VARCHAR(50), emp_id integer, skill_level integer, " + "salary double, address XML) " + "LANGUAGE SQL " + "MODIFIES SQL DATA " + "SPECIFIC func1 " + "BEGIN ATOMIC " + "UPDATE sales_employee SET emp_details = XMLQuery('transform " + "copy $emp_info := $emp " + " modify if ($emp_info/employee[skill_level = 7 and " + " designation = \"Sr. Manager\"]) " + "then " + "( " + "do replace value of $emp_info/employee/skill_level with 8, " + "do replace value of $emp_info/employee/salary with " + " $emp_info/employee/salary * 9.5 " + ") " + "else if ($emp_info/employee[skill_level = 6 and " + " designation = \"Manager\"])" + "then " + "( " + "do replace value of $emp_info/employee/skill_level with 7, " + " do replace value of $emp_info/employee/salary with " + " $emp_info/employee/salary * 7.5 " + ") " + "else if ($emp_info/employee[skill_level = 5 and " + " designation = \"Associate Manager\"]) " + "then " + "( " + " do replace value of $emp_info/employee/skill_level with 6, " + " do replace value of $emp_info/employee/salary with " + " $emp_info/employee/salary * 5.5 " + ")" + "else ()" + "return $emp_info' PASSING emp_details as \"emp\") " + " WHERE emp_id = emp_id_p; " + " RETURN SELECT X.* " + "FROM sales_employee, XMLTABLE('$e_info/employee' PASSING " + " emp_details as \"e_info\" " + "COLUMNS " + "name VARCHAR(50) PATH 'name', " + "emp_id integer PATH '@id', " + "skill_level integer path 'skill_level', " + "salary double path 'salary', " + "addr XML path 'address') AS X WHERE sales_employee.emp_id = emp_id_p; " + "END"); + + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE FUNCTION "); + printf("%s\n\n", stmt); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT "); + + printf("---------------------------------------------------------\n"); + printf("Call the 'updatePromotedEmployeesInfo' table function to "); + printf("update the details of promoted employees in 'sales_employee' table\n "); + printf("---------------------------------------------------------\n\n"); + + strcpy(stmt, "SELECT A.* FROM sales_employee AS E, " + "table(updatePromotedEmployeesInfo(E.emp_id)) AS A"); + printf("%s\n\n", stmt); + + EXEC SQL PREPARE s2 FROM :stmt; + EMB_SQL_CHECK("PREPARE s2"); + + EXEC SQL DECLARE cur CURSOR FOR s2; + EMB_SQL_CHECK("DECLARE cur"); + + EXEC SQL OPEN cur; + EMB_SQL_CHECK("OPEN cur"); + + EXEC SQL FETCH cur INTO :name, :emp_id, :sk_lvl, :sal, :xmldata; + EMB_SQL_CHECK("FETCH cur"); + + printf("\n--------------------------------------------------\n"); + while (sqlca.sqlcode == SQL_RC_OK) + { + + printf("%s %d %d %f ", name.arr, emp_id, sk_lvl, sal); + for(count = 0; count < xmldata.length; count++) + { + printf("%c", xmldata.data[count]); + } + + EXEC SQL FETCH cur INTO :name, :emp_id, :sk_lvl, :sal, :xmldata; + EMB_SQL_CHECK("FETCH cur"); + printf("\n"); + } + printf("\n--------------------------------------------------\n"); + + + EXEC SQL CLOSE cur; + EMB_SQL_CHECK("CLOSE cur"); + + return 0; +} + +/*-------------------------------------------------------------------------- +-- 3. Sourced UDF which takes an XML variable as the input parameter +-- and returns an XML value as output. +--------------------------------------------------------------------------*/ + +int sourcedUDF() +{ + int count = 0; + + printf("---------------------------------\n"); + printf("The store manager would like to get a particular dept manager "); + printf("name and his contact numbers. The DBA then creates a "); + printf("'getManagerDetails' UDF to get a particular department manager "); + printf("name and manager contact details. \n"); + printf("---------------------------------\n\n"); + + strcpy(stmt, "CREATE FUNCTION getManagerDetails(dept_info_p XML, " + "dept_p VARCHAR(5)) " + "RETURNS XML " + "LANGUAGE SQL " + "SPECIFIC getManagerDetails " + "BEGIN ATOMIC " + "RETURN XMLQuery('$info/department[name=$dept_name]/manager' " + "PASSING dept_info_p as \"info\", dept_p as \"dept_name\"); " + "END"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE FUNCTION "); + printf("%s\n\n", stmt); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT "); + + printf("Create a sourced UDF 'getManagerInfo' based on "); + printf("'getManagerDetails' user defined function \n\n"); + + strcpy(stmt, "CREATE FUNCTION getManagerInfo(XML, CHAR(10))" + "RETURNS XML " + "SOURCE getManagerDetails(XML, VARCHAR(5)) "); + EXEC SQL EXECUTE IMMEDIATE :stmt; + printf("%s\n\n", stmt); + + printf("Call the sourced UDF 'getManagerInfo' to get "); + printf("'sales' department manager details"); + + strcpy(stmt, "SELECT getManagerInfo(sales_department.dept_info, 'sales') " + "FROM sales_department WHERE dept_id='DS02'"); + printf("%s\n\n", stmt); + + EXEC SQL PREPARE s3 FROM :stmt; + EMB_SQL_CHECK("PREPARE stmt"); + + EXEC SQL DECLARE cur1 CURSOR FOR s3; + EMB_SQL_CHECK("DECLARE cur1"); + + EXEC SQL OPEN cur1; + EMB_SQL_CHECK("OPEN cur1"); + + EXEC SQL FETCH cur1 INTO :xmldata; + EMB_SQL_CHECK("FETCH INTO"); + + for (count = 0; count < xmldata.length; count++) + { + printf("%c", xmldata.data[count]); + } + printf("\n"); + + EXEC SQL CLOSE cur1; + EMB_SQL_CHECK("CLOSE cur1"); + + return 0; +} + +/*----------------------------------------------------------------------- +-- 4. SQL bodied UDF which takes an XML variable as the input parameter +-- and returns a table with XML values as output. This UDF +-- calls a stored procedure which takes an XML variable +-- as the input parameter and returns an XML value as output. +------------------------------------------------------------------------*/ + +int invokespfromUDF() +{ + + int count = 0; + + printf("---------------------------------\n"); + printf("Create a function which calculates an employee gift cheque "); + printf("amount and adds this value as a new element into the "); + printf("employee information document\n"); + printf("---------------------------------\n"); + + strcpy(stmt, "CREATE PROCEDURE calculateGiftChequeAmount(" + " INOUT emp_info_p XML, " + "IN emp_name_p VARCHAR(20)) " + "LANGUAGE SQL " + "MODIFIES SQL DATA " + "SPECIFIC customer_award " + "BEGIN " + "DECLARE emp_bonus_info_v XML; " + "IF XMLEXISTS('$e_info/employee[name = $emp1]' " + "PASSING emp_info_p as \"e_info\"," + "emp_name_p as \"emp1\")" + "THEN " + "SET emp_bonus_info_v = XMLQuery('copy $bonus := $info " + "modify " + "do insert {" + " $bonus/employee/salary * 0.50 + 25000} " + " into $bonus/employee " + "return $bonus' PASSING emp_info_p as \"info\"); " + "END IF; " + "SET emp_info_p = emp_bonus_info_v; " + "END "); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE PROCEDURE "); + printf("%s\n\n", stmt); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT "); + + printf("-----------------------------------------------------\n"); + printf("Some employees who got customer appreciation awards "); + printf("and whose total sales are greater than expected sales "); + printf("were given gift cheques by the store. The DBA creates "); + printf("'calculatePerformanceBonus' function to calculate "); + printf("employee performance bonus along with customer gift "); + printf("cheque amount and update the employee information "); + printf("in sales_employee table. \n"); + printf("-----------------------------------------------------\n\n"); + + strcpy(stmt, "CREATE FUNCTION calculatePerformanceBonus(sales_info_p XML) " + "RETURNS table(info XML) " + "LANGUAGE SQL " + "SPECIFIC awardedemployees " + "MODIFIES SQL DATA " + "BEGIN ATOMIC " + "DECLARE awarded_emp_info_v XML; " + "DECLARE emp_name VARCHAR(20); " + "DECLARE min_sales_v INTEGER; " + "DECLARE avg_sales_v INTEGER; " + "SET min_sales_v = XMLCAST(XMLQuery('$info/sales_per_annum/min_sales' " + "PASSING sales_info_p as \"info\") AS INTEGER); " + "SET avg_sales_v = XMLCAST(XMLQuery('$info/sales_per_annum/avg_sales' " + "PASSING sales_info_p as \"info\") AS INTEGER); " + "FOR_LOOP: FOR EACH_ROW AS " + "SELECT XMLCAST(XMLQuery('$info/employee/name' PASSING awarded_emp_info_v " + "as \"info\") AS VARCHAR(20)) as name, " + "XMLQuery('copy $e_info := $inf " + "modify " + "do insert {$e_info/employee/salary " + "* 0.25 + 5000} " + " into $e_info/employee " + "return $e_info' PASSING emp_details as \"inf\") " + "as info " + "FROM sales_employee " + "WHERE total_sales between min_sales_v and avg_sales_v " + "DO " + "SET awarded_emp_info_v = EACH_ROW.info; " + "SET emp_name = EACH_ROW.name; " + "CALL calculateGiftChequeAmount(awarded_emp_info_v, emp_name); " + "INSERT INTO performance_bonus_employees " + "VALUES (EACH_ROW.info); " + "END FOR; " + "RETURN SELECT * FROM performance_bonus_employees; " + "END "); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE FUNCTION "); + printf("%s\n\n", stmt); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT "); + + printf("Call the table function 'calculatePerformanceBonus' "); + printf("to get the information of all the employees who got gift "); + printf("cheques and performance bonus."); + + strcpy(stmt, "SELECT * FROM table(calculatePerformanceBonus(" + "XMLPARSE(document " + "' " + "80000 " + "70000 " + "35000 " + "')))"); + printf("%s\n\n", stmt); + + EXEC SQL PREPARE s4 FROM :stmt; + EMB_SQL_CHECK("PREPARE"); + + EXEC SQL DECLARE cur3 CURSOR FOR s4; + EMB_SQL_CHECK("DECLARE CURSOR"); + + EXEC SQL OPEN cur3; + EMB_SQL_CHECK("OPEN cur3"); + + EXEC SQL FETCH cur3 INTO :xmldata; + EMB_SQL_CHECK("FECTH INTO"); + + printf("\n"); + while(sqlca.sqlcode == SQL_RC_OK) + { + + for (count = 0; count < xmldata.length; count++) + { + printf("%c", xmldata.data[count]); + } + printf("\n\n\n"); + + EXEC SQL FETCH cur3 INTO :xmldata; + EMB_SQL_CHECK("FECTH INTO"); + } + + EXEC SQL CLOSE cur3; + EMB_SQL_CHECK("CLOSE cur3"); + + return 0; +} + +int cleanuptables() +{ + EXEC SQL DROP FUNCTION getDeptContactNumbers; + EMB_SQL_CHECK("DROP FUNCTION"); + + EXEC SQL DROP FUNCTION getManagerInfo; + EMB_SQL_CHECK("DROP FUNCTION"); + + EXEC SQL DROP TABLE sales_department; + EMB_SQL_CHECK("DROP TABLE"); + + EXEC SQL DROP FUNCTION updatePromotedEmployeesInfo; + EMB_SQL_CHECK("DROP FUNCTION"); + + EXEC SQL DROP FUNCTION calculatePerformanceBonus; + EMB_SQL_CHECK("DROP FUNCTION"); + + EXEC SQL DROP PROCEDURE calculateGiftChequeAmount; + EMB_SQL_CHECK("DROP FUNCTION"); + + EXEC SQL DROP TABLE sales_employee; + EMB_SQL_CHECK("DROP TABLE"); + + EXEC SQL DROP TABLE performance_bonus_employees; + EMB_SQL_CHECK("DROP TABLE"); + + EXEC SQL DROP FUNCTION getManagerDetails; + EMB_SQL_CHECK("DROP FUNCTION"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT "); +} diff --git a/xml/c/xmlupdel.sqc b/xml/c/xmlupdel.sqc new file mode 100644 index 0000000..d0e27aa --- /dev/null +++ b/xml/c/xmlupdel.sqc @@ -0,0 +1,269 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlinsert.sqc +** +** SAMPLE: This sample demonstrates how to insert a XML document into +** a column of XML data type. +** +** SQL STATEMENTS USED: +** INSERT +** DECLARE +** OPEN +** FETCH +** CLOSE +** +** OUTPUT FILE: xmlinsert.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +EXEC SQL BEGIN DECLARE SECTION; + char xmldata[2000]; + char parse_option[30]; + short nullind = 0; + static SQL TYPE IS XML AS CLOB(1k) xmlclob1=SQL_CLOB_INIT(" a ") ; + static SQL TYPE IS BLOB(1k) hv_blob2 = SQL_BLOB_INIT(" a "); + static SQL TYPE IS XML AS BLOB(1k) xmlblob3 = SQL_BLOB_INIT(" a"); +EXEC SQL END DECLARE SECTION; + +int createtables(void); +int droptables(void); + +int main(int argc, char *argv[]) +{ + int rc = 0; + int charcount = 0; + char stmt[500]; + char xmlfilename[50]; + char prep_string[200]; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* Create a XML document that will be used to INSERT in the table */ + strcpy(xmldata, "" + " Plastic Casing " + "
Blue Color
" + " 2.89 " + " 0.23 " + "
"); + + strcpy(xmlclob1.data, xmldata); + strcpy(hv_blob2.data, xmldata); + strcpy(xmlblob3.data, xmldata); + strcpy(parse_option, "preserve whitespace"); + + xmlclob1.length = strlen(xmldata) + 1; + hv_blob2.length = xmlclob1.length; + xmlblob3.length = xmlclob1.length; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* Call function to create needed tables */ + rc = createtables(); + + /* Inserting when source is from host variable of type XML AS CLOB */ + printf("\n Insert into Purchaseorder table\n"); + EXEC SQL INSERT INTO purchaseorder (poid, porder) + VALUES (1612, :xmlclob1:nullind); + EMB_SQL_CHECK("INSERTING with host variable of type XML as CLOB"); + + EXEC SQL INSERT INTO purchaseorder (poid, porder) + VALUES (2341, :xmlclob1:nullind); + EMB_SQL_CHECK("INSERTING with host variable of type XML as CLOB"); + + /* Update the XML column using host varable of type XML */ + printf(" Update XML column using varibale of type XML\n"); + EXEC SQL UPDATE purchaseorder SET porder = :xmlclob1 WHERE poid = 1612; + EMB_SQL_CHECK("UPDATE using XML type host variable"); + + /* Update the XML colum using the BLOB host variable */ + printf(" Update Purchaseorder with a varibalre of type BLOB\n"); + EXEC SQL UPDATE purchaseorder SET porder = XMLPARSE( + DOCUMENT :hv_blob2 STRIP WHITESPACE) WHERE POID = 1612; + EMB_SQL_CHECK("UPDATE using BLOB type host variable"); + + /* Update the XML column using the BLOB host variable */ + /* with IMPLICIT parsing */ + printf(" Update using Implicit Parsing and a BLOB variable\n"); + EXEC SQL UPDATE purchaseorder SET porder = :hv_blob2 WHERE poid = 1612; + EMB_SQL_CHECK("UPDATE using BLOB type host variable with implicit parsing"); + + /* SET the register with the option PRESERVE WHITESPACE */ + printf(" Set the CURRENT IMPLICIT XMLPARSE OPTION register\n"); + EXEC SQL SET CURRENT IMPLICIT XMLPARSE OPTION = :parse_option; + EMB_SQL_CHECK("SET THE CURRENT IMPLICIT PARSE REGISTER"); + + /* UPDATE the XML column using varchar */ + printf(" UPDATE XML column using VARCHAR type variable\n"); + EXEC SQL UPDATE purchaseorder SET porder = XMLPARSE (DOCUMENT + ' 123 ' + PRESERVE WHITESPACE) WHERE POID = 1612; + EMB_SQL_CHECK("UPDATE USING VARCHAR"); + + /* UPDATE THE XML COLUMN USING VARCHAR WITH IMPLICIT PARSING */ + printf(" UPDATE XML column using VARCHAR and IMPLICIT PARSING\n"); + EXEC SQL UPDATE PURCHASEORDER SET PORDER = + ' 123 ' + WHERE POID = 1612; + EMB_SQL_CHECK("UPDATE USING varchar WITH IMPLICT PARSING"); + + /* UPDATE the xml column using another column of varchar */ + printf(" UPDATE XML column from another column of type VARCHAR\n"); + strcpy(stmt, "UPDATE purchaseorder SET PORDER = (SELECT XMLPARSE( DOCUMENT desc PRESERVE WHITESPACE) " + " FROM vartable where id = 11111)" + " WHERE POID = 1612"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK(" Update using column of type VARCHAR"); + + /* Insert when source is a XML document from a column */ + /* of type VARCHAR, Using Implicit Parsing */ + printf(" Upate whne source is a XML document from a column of type VARCHAR, Using Implicit Parsing\n"); + strcpy(stmt, "UPDATE purchaseorder SET PORDER = " + "(SELECT desc FROM vartable where id = 22222)" + " WHERE POID = 1612"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Insert from another column of type VARCHAR using implicit Parsing"); + + /* update the xml column with XMLVALIDATE and source is a XML host variable */ + printf(" UPDATE XML column when host variable is xml, using XMLVALIDATE\n"); + EXEC SQL UPDATE PURCHASEORDER SET PORDER = XMLVALIDATE (:xmlclob1 + ACCORDING TO XMLSCHEMA ID product) where POID = 1631; + EMB_SQL_CHECK("UPDATE USING XML HOST VARIABLE WITH XMLVALIDATE"); + + printf(" UPDATE using XML document returned by select using XMLVALIDATE\n"); + EXEC SQL UPDATE PURCHASEORDER SET PORDER = (Select + XMLVALIDATE( porder ACCORDING TO XMLSCHEMA ID product) + FROM purchaseorder WHERE poid = 2341) WHERE POID = 1631; + EMB_SQL_CHECK("UPDATE USING VARCHAR VARIABLE WITH XMLVALIDATE"); + + printf(" Perform Searched delete\n"); + strcpy((char *)prep_string, "DELETE FROM PURCHASEORDER WHERE " + "XMLEXISTS('$p/product[@pid=\"10\"]' " + "passing by ref PURCHASEORDER.PORDER as \"p\")"); + EXEC SQL EXECUTE IMMEDIATE :prep_string; + EMB_SQL_CHECK("DELETE"); + + EXEC SQL ROLLBACK; + EMB_SQL_CHECK("ROLLBACK"); + + /* Call function for cleanup */ + rc = droptables(); + + /* disconnect from the database */ + rc = DbDisconn(dbAlias); + if (rc != 0) + { + return rc; + } + + return 0; +} /* main */ + +/* Create tables */ +int createtables(void) +{ + int rc = 0; + char stmt[800]; + + strcpy(stmt, "CREATE TABLE vartable (id INT," + " desc VARCHAR(200), comment VARCHAR(25))"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Creation"); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(11111, \' Neeraj " + " Gaurav \', " + "\'Final Year\')"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Insert"); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(22222, '" + " Plastic Casing " + "
Green Color
" + " 7.89 " + " 6.23 " + "
', " + "'Last Product')"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Insert"); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(33333, \' Neeraj " + " Gaurav \', " + "\'Final Year\')"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Insert"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + return 0; +}/* createtables */ + +/* droptables */ +int droptables(void) +{ + int rc = 0; + char stmt[200]; + + strcpy(stmt, "DROP TABLE VARTABLE"); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Table--Drop"); + + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + return 0; +}/* droptables */ + diff --git a/xml/c/xmlxslt.sqc b/xml/c/xmlxslt.sqc new file mode 100644 index 0000000..a225743 --- /dev/null +++ b/xml/c/xmlxslt.sqc @@ -0,0 +1,329 @@ +/*************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SAMPLE FILE NAME: xmlxslt.sqc +** +** PURPOSE: The purpose of this sample is to show: +** 1. Using XSLTRANSFORM function to convert one XML document into another +** using an XSLT stylesheet. +** 2. Passing an XSL parameter document to the XSLTRANSFORM function +** at runtime. +** +** USAGE SCENARIO: A supermarket manager maintains a webpage to show +** the details of the products available in his shop. +** He maintains two tables, namely "product_details" +** and "display_productdetails". +** The "product_details" table contains information about +** all of the products available in his shop, where the +** details for each product are in an XML document format. +** The "display_productdetails" table contains the XSLT +** stylesheet, which specifies how to display the product +** details on the webpage. +** +** PREREQUISITE: NONE +** +** EXECUTION: bldapp xmlxslt; +** xmlxslt +** +** INPUTS: NONE +** +** OUTPUTS: Displays new XML documents that result from the XSLT conversion. +** +** OUTPUT FILE: xmlxslt.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** CREATE TABLE +** INSERT +** DROP +** +** SQL/XML FUNCTIONS USED: +** XSLTRANSFORM +** +***************************************************************************** +** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +***************************************************************************** +** +** SAMPLE DESCRIPTION +** +***************************************************************************** +** 1. Using the XSLTRANSFORM function to convert one XML document to another +** using an XSLT stylesheet. +** 1.1 Insert an XML document into the "product_details" table. +** 1.2 Insert an XSL stylesheet into the "display_productdetails" table. +** 1.3 Display the new XML document after transforming the XML document +** in the "product_details" table using the XSL stylesheet. +** +** 2. Passing an XSL parameter document to the XSLTRANSFORM function +** during transformation. +** 2.1 Insert a parameter document into the "param_tab" table. +** 2.2 Display the new XML document after transforming the XML document +** in the "product_details" table using the XSL stylesheet with +** the parameter document. +** +**************************************************************************** +** +** INCLUDE ALL HEADER FILES +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +/**************************************************************************** +** +** DECLARE HOST VARIABLES +** +*****************************************************************************/ + +EXEC SQL BEGIN DECLARE SECTION; /* Start of declare section */ + char dbAlias[8]; + char user[30]; + char pswd[30]; + char stmt[1000]; +EXEC SQL END DECLARE SECTION; /* End of declare section */ + + +int main(int argc, char *argv[]) +{ + int rc = 0; + struct sqlca sqlca; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to the sample database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\n\nThis sample shows how to use XSLTRANSFORM function "); + printf(" to convert one XML document into another.\n"); + printf("------------------------------------------------------\n"); + + /*************************************************************************** + ** 1. Using the XSLTRANSFORM function to convert one XML document to another + ** using an XSLT stylesheet. + ****************************************************************************/ + + printf("CREATE TABLE product_details (productid INTEGER, description XML)"); + EXEC SQL CREATE TABLE product_details (productid INTEGER, description XML); + EMB_SQL_CHECK("CREATE TABLE product_details"); + + + printf("\n\nCREATE TABLE display_productdetails (productid INTEGER,"); + printf("stylesheet CLOB (1M))"); + EXEC SQL CREATE TABLE display_productdetails (productid INTEGER, + stylesheet CLOB (1M)); + EMB_SQL_CHECK("CREATE TABLE display_productdetails"); + + /*************************************************************************** + ** 1.1 Insert an XML document into the "product_details" table. + ****************************************************************************/ + + printf("\n\nINSERT an XML document into the product_details table"); + strcpy(stmt, "INSERT INTO product_details " + "VALUES (1, ' " + "" + "" + "" + "Ice Scraper,Windshield 4 inch" + "
Basic Ice Scraper 4 inches wide, foam handle
" + "3.99" + "
" + " BIG BAZAR
" + "
')"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO product_details"); + + /*************************************************************************** + ** 1.2 Insert an XSL stylesheet into the "display_productdetails" table. + ****************************************************************************/ + + printf("\n\nINSERT XSLT document into the display_productdetails table"); + strcpy(stmt, "INSERT INTO display_productdetails VALUES(1, " + "'" + "" + "" + "" + "" + "" + "

" + "" + "" + "" + "" + "" + "" + "" + "
product IDproduct namepricedetailssupermarket name
" + "" + "" + "" + "" + "" + "
')"); + + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO display_productdetails"); + + /*************************************************************************** + ** 1.3 Display the new XML document after transforming the XML document + ** in the "product_details" table using the XSL stylesheet. + ****************************************************************************/ + + printf("\n\nDisplay the final document in HTML format"); + printf("\nSELECT XSLTRANSFORM (description USING stylesheet AS CLOB(1M))"); + printf(" FROM product_details X, display_productdetails D"); + printf(" WHERE X.productid = D.productid"); + + + strcpy(stmt,"SELECT XSLTRANSFORM (description USING stylesheet AS CLOB (1M))" + " FROM product_details X, display_productdetails D " + "WHERE X.productid = D.productid"); + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("PREPARE statement"); + + EXEC SQL DECLARE c1 CURSOR FOR s1; + EMB_SQL_CHECK("DECLARE CURSOR c1"); + + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN CURSOR c1"); + + EXEC SQL FETCH c1 INTO :stmt; + EMB_SQL_CHECK("FETCH CURSOR c1"); + + + printf("\n------------------------------------------------------------"); + printf("\n\n%s\n", stmt); + + printf("\n------------------------------------------------------------"); + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("CLOSE c1"); + + /************************************************************************** + ** 2. Passing an XSL parameter document to the XSLTRANSFORM function + ** during transformation. + ***************************************************************************/ + + printf("\n\nThe following part shows how to pass parameters to"); + printf(" XSLTRANSFORM function"); + printf("\n----------------------------------------------------------"); + + printf("\n\nCREATE TABLE param_tab(productid INTEGER, "); + printf("param VARCHAR (1000))"); + + EXEC SQL CREATE TABLE param_tab(productid INTEGER, + param VARCHAR (1000)); + EMB_SQL_CHECK("CREATE TABLE param_tab"); + + /************************************************************************** + ** 2.1 Insert a parameter document into the table "param_tab". + ***************************************************************************/ + + printf("\n\nInsert parameter value into param_tab table"); + strcpy(stmt, "INSERT INTO param_tab " + "VALUES (1, '" + "" + "" + "BIG BAZAR super market" + "')"); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO param_tab"); + + /************************************************************************** + ** 2.2 Display the new XML document after transforming the XML document + ** in the "product_details" table using the XSL stylesheet with + ** the parameter document. + ***************************************************************************/ + + printf("\n\nDisplay final document in new format"); + printf("\nSELECT XSLTRANSFORM (description USING stylesheet WITH param AS"); + printf(" CLOB (1M)) FROM product_details X, param_tab P,"); + printf("display_productdetails D WHERE X.productid=P.productid "); + printf("and X.productid = D.productid "); + + strcpy(stmt,"SELECT XSLTRANSFORM (description USING stylesheet WITH param" + " AS CLOB (1M)) " + "FROM product_details X,param_tab P,display_productdetails D " + "WHERE X.productid=P.productid AND X.productid = D.productid"); + + EXEC SQL PREPARE s2 FROM :stmt; + EMB_SQL_CHECK("PREPARE statement s2"); + + EXEC SQL DECLARE c2 CURSOR FOR s2; + EMB_SQL_CHECK("DECLARE CURSOR c2"); + + EXEC SQL OPEN c2; + EMB_SQL_CHECK("OPEN CURSOR c2"); + + EXEC SQL FETCH c2 INTO :stmt; + EMB_SQL_CHECK("FETCH CURSOR c2"); + + printf("\n--------------------------------------------------------"); + printf("\n\n%s\n", stmt); + printf("\n--------------------------------------------------------"); + + EXEC SQL CLOSE c2; + EMB_SQL_CHECK("CLOSE c2"); + + /******************************************************************** + ** + ** CLEANUP + ** + *********************************************************************/ + + printf("\ndrop all of the tables created\n"); + EXEC SQL DROP TABLE display_productdetails; + EMB_SQL_CHECK("DROP TABLE display_productdetails"); + + EXEC SQL DROP TABLE product_details; + EMB_SQL_CHECK("DROP TABLE product_details"); + + EXEC SQL DROP TABLE param_tab; + EMB_SQL_CHECK("DROP TABLE param_tab"); +} diff --git a/xml/catalog.xsd b/xml/catalog.xsd new file mode 100644 index 0000000..e15caf1 --- /dev/null +++ b/xml/catalog.xsd @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/cli/README b/xml/cli/README new file mode 100644 index 0000000..33aec70 --- /dev/null +++ b/xml/cli/README @@ -0,0 +1,316 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for CLI XML Samples +* +* The "/sqllib/samples/xml/cli" directory on Unix or +* "\sqllib\samples\xml\cli" directory on Windows +* contains this README file. +* where is the location of DB2 9.7 on +* your hard drive. +* The default location for is +* C:\Program Files\IBM on Windows, +* $HOME on Unix. +* +* This README describes how to build and run CLI XML sample code for DB2 9.7. +* DB2 9.7 sample code and build files for CLI XML are located in the +* following directory: +* \sqllib\samples\xml\cli for Windows and +* /sqllib/samples/xml/cli for Unix +* +* It is recommended that you copy the sample files from this directory +* to a working directory prior to building the sample programs. +* The sample program directories are typically read-only on most +* platforms and some samples produce output files that require write +* perimssions on the directory. +* +* WARNING: +* 1. Some of these samples may change your database or database manager +* configuration. Execute the samples against a test database +* only, such as the DB2 SAMPLE database. +* +****************************************************************************** +* +* Prepare your DB2 sample development environment for Windows/Unix +* +* 1) Copy the files in \sqllib\samples\xml\cli\* for Windows and +* $HOME/sqllib/samples/xml/cli/* for Unix to a working directory and +* ensure that directory has write permission. +* +* 2) On Windows platform, all samples should be run and built in DB2 +* Command Window. +* The DB2 command window is needed to execute the db2 specific commands. +* You can follow the step below to open DB2 command window. +* From the Start Menu click Start --> Programs --> IBM DB2 --> +* --> Command Line Tools --> Command Window. +* +* 3) Start the database manager with the following command: +* db2start +* +* 4) Create the sample database with the following command: +* db2sampl -xml +* +* 5) Connect to the sample database with the following command: +* db2 connect to sample +* +* 6) To build stored procedures and User defined functions, +* ensure that you have write permission on the +* \sqllib\function directory on Windows and +* /sqllib/function directory on Unix. +* +* 7) Change directory (CD) to the directory containing the files +* copied in step 1. +* +****************************************************************************** +* +* Building DB2 samples +* +* There are two ways to build DB2 samples: using a nmake utility for +* windows (make utility for Unix) or using build scripts that +* are included with DB2 sample programs. +* +* o To build samples using the nmake utility for windows see +* 'BUILDING SAMPLES USING nmake UTILITY on Windows'. +* o To build samples using the make utility for unix see +* 'BUILDING SAMPLES USING make UTILITY on Unix'. +* o To build samples using the build scripts or when you +* don't have a compatible make/namke utility, +* see 'BUILDING SAMPLES USING BUILD SCRIPTS'. +* +* NOTE : +* +* 1. Some of the samples might need one or more data files at runtime. +* some of the samples may also need setup script to be run before +* running the sample.See the specific sample descriptions in +* "File Descriptions" section for more details. +* +* 2. There are utility files available in this directory that are used +* by these samples for error checking. Please make sure that these +* files are present in you working directory. The information +* about these files can be found in "File Descriptions" section of this +* README. +* +* 3. Refer to the "File Descriptions" section in this README for +* information on specific samples and any special considerations +* relevant for each.The HEADER sections of these samples also provide +* further details on each sample. +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING nmake UTILITY ON Windows *** +* +* If you have a compatible nmake utility on your system, you can use +* the makefile provided. Such a nmake utility may be provided by +* another language compiler.If Windows, modify the PATH variable +* to include the directory containing the nmake utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'nmake' command in your working +* directory: +* +* nmake - Builds the program designated by . +* +* nmake all - Builds all supplied sample programs +* +* nmake srv - Builds sample that can only be run on the server +* (stored procedure) +* +* nmake all_client - Builds all client samples (all programs in the +* 'call_rtn' and 'client_run' categories). +* +* nmake call_rtn - Builds client programs that call stored procedure +* +* nmake client_run - Builds all programs that run completely on the +* client (not ones that call stored procedure) +* +* nmake clean - Erases all intermediate files produced in the +* build process. +* +* nmake cleanall - Erases all files produced in the build process +* (all files except the original source files). +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING make UTILITY ON Unix *** +* +* If you have a compatible make utility on your system, you +* can use the makefile provided. Modify the PATH +* variable to include the directory containing the make +* utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'make' command in your working directory: +* make - Builds the program designated by . +* +* make all - Builds all supplied sample programs +* +* make srv - Builds sample that can only be run on the server +* (stored procedure) +* +* make all_client - Builds all client samples (all programs in the +* 'call_rtn' and 'client_run' categories). +* +* make call_rtn - Builds client programs that call stored procedure +* +* make client_run - Builds all programs that run completely on the +* client (not ones that call stored procedure) +* +* make clean - Erases all intermediate files produced in the +* build process. +* +* make cleanall - Erases all files produced in the build process +* (all files except the original source files). +* +****************************************************************************** +* +* *** BUILDING SAMPLES USING BUILD SCRIPTS *** +* +* As an alternative to the makefile, the build files included with the DB2 +* samples can be used to build the CLI XML sample programs. +* +* Building Standalone Samples: +* o bldapp +* - the name of the sample program without +* extension. +* For any additional dependencies refer to the individual sample. +* +* Building and Executing Stored Procedures: +* o Build stored procedure server and copy the resulting binary file to +* the sqllib/function directory with the following command: +* bldrtn +* - Name of the sample program without +* extension. +* o Catalog stored procedures with the following command: +* spcat +* o Build stored procedure client with the following command: +* bldapp +* - Name of the sample program without +* extension. +****************************************************************************** +* +* Common file Descriptions +* +* The following are the common files for CLI XML samples. For more +* information on these files, refer to the program source files. +* +******************************************************************************* +* +* Common files +* +* README - this file +* makefile - makefile for all files. +* +****************************************************************************** +* Common Utility Function files +* +* utilapi.c - Error-checking utility file for DB2 API programs. +* utilapi.h - Header file for utilapi.c. +* utilemb.sqc - Error-checking utility file for embedded SQL programs. +* utilemb.h - Header file for utilemb.sqc. +* +* Batch files(for Windows) and Shell Scripts(for Unix) +* +* bldapp - Builds an application program. +* bldrtn - Builds a routine (stored procedure and UDF) program. +* embprep - Precompiles and binds embedded SQL programs. +* +****************************************************************************** +* +* CLI XML sample descriptions +* +* The following are the CLI XML sample files included with DB2. For more +* information on these files, refer to program source files. +* +****************************************************************************** +* CLI XML sample files description +* +* xmltotable.c - How to insert the data from XML document to a relational +* table using XML Constructor functions and SQL/XML functions. +* PREREQUISITE: copy purchaseorder.xml XML document from +* xml/data directory to the working directory. +* +* reltoxmldoc.c - How to create XML object from data stored in relational +* tables using various SQL/XML Constructor functions and +* SQL/XML functions. +* PREREQUISITE: This sample uses a stored procedure. +* Stored procedure should be registered before running the +* sample. Follow the step given in the header of the sammple +* for more details.Run the cleanup.db2 and setupscript.db2 +* scripts before running this simple. +* Run the cleanupscript.db2 script to cleanup the +* database objects after running the sample. +* These scripts can be found in xml/data directory. +* +* xmlread.c - How to read XML data from a table. +* +* xmlinsert.c - How to insert XML data into a table having an XML column. +* +* xmlupdel.c - How to update and delete XML documents in a table. +* +* xmlindex.c - How to create index on an XML column. +* +* xmlconst.c - How to put constraints on an XML column. +* NOTE : This sample demonstrate the how to enforce the +* constraints on an XML value. There are some statement +* in the samples which are expected to fail because of +* constraint violation so The sql error SQL803N, +* SQL20305N and SQL20306N are expected. +* +* xsupdate.c - How to update an XML schema with a compatible schema. +* PREREQUISITE: The original schema and the new schema +* should be present in the same directory as the sample. +* Copy prod.xsd, newprod.xsd from directory +* /xml/data to the working directory. +* +* xmludfs.c - How XML data type is supported in Scalar UDFs, Sourced +* UDFs and SQL bodied UDFs. +* +****************************************************************************** +* Stored Procedures (program files that demonstrate stored procedures) +* +* simple_xmlproc_client.c - Client application that calls the stored +* procedure in simple_xmlproc.c. +* PREREQUISITE: Build the server +* "simple_xmlproc.c" and register the procedure +* using spcat_xml. +* For more information, See the Samples header. +* +* simple_xmlproc.c - Stored procedure function built and run on the +* server +* +* spcat_xml - CLP script that first calls +* simple_xmlproc_drop.db2 and then calls +* simple_xmlproc_create.db2. +* +* simple_xmlproc_create.db2 - CLP script to issue CREATE PROCEDURE statement. +* +* simple_xmlproc_drop.db2 - CLP script to drop stored procedure from the +* catalog. +* +* simple_xmlproc.exp - export file for simple_xmlproc. +* +***************************************************************************** diff --git a/xml/cli/bldapp b/xml/cli/bldapp new file mode 100644 index 0000000..4ac3d5d --- /dev/null +++ b/xml/cli/bldapp @@ -0,0 +1,94 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldapp +# Builds CLI applications for Linux +# Usage: bldapp [ [ ]] + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then + BITWIDTH=64 +else + # x86 is the only native 32-bit platform + BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] +then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 $3 $4 +fi + +# Compile the error-checking utility. +gcc $EXTRA_C_FLAGS -I$DB2PATH/include -c utilcli.c + +# Compile the program. +gcc $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c + +# Link the program. +gcc $EXTRA_C_FLAGS -o $1 $1.o utilcli.o $EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2 diff --git a/xml/cli/bldrtn b/xml/cli/bldrtn new file mode 100644 index 0000000..880545c --- /dev/null +++ b/xml/cli/bldrtn @@ -0,0 +1,94 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldrtn +# Builds CLI routines (stored procedures or UDFs) for Linux +# Usage: bldrtn + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then + BITWIDTH=64 +else + # x86 is the only native 32-bit platform + BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] +then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# Compile the error-checking utility. +gcc $EXTRA_C_FLAGS -fpic -I$DB2PATH/include -c utilcli.c -D_REENTRANT + +# Compile the program. +gcc $EXTRA_C_FLAGS -fpic -I$DB2PATH/include -c $1.c -D_REENTRANT + +# Link the program. +gcc $EXTRA_C_FLAGS -o $1 $1.o utilcli.o -shared $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 -lpthread + +# Copy the shared library to the function subdirectory. +# The user must have write permission to this directory. +rm -f $DB2PATH/function/$1 +cp $1 $DB2PATH/function diff --git a/xml/cli/makefile b/xml/cli/makefile new file mode 100644 index 0000000..4904e0f --- /dev/null +++ b/xml/cli/makefile @@ -0,0 +1,175 @@ +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# +# MAKEFILE for XML CLI samples on Unix +# +# Enter one of the following commands +# +# make - Builds the program designated by +# make all - Builds all supplied sample programs +# make srv - Builds sample that run on the server +# (stored procedure) +# make all_client - Builds all client samples (all programs in the +# call_rtn and client_run categories) +# make call_rtn - Builds client programs that call stored procedure +# make client_run - Builds all programs that run completely on the +# client (not ones that call stored procedure) +# make clean - Erases intermediate files +# make cleanall - Erases all files produced in the build process +# except the original source files +# +############################################################################# +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +############################################################################## +# 1 -- VARIABLES +############################################################################## + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +BLDAPP=bldapp +BLDRTN=bldrtn + +# To connect to a remote SAMPLE database cataloged on the client machine +# with another name, update the ALIAS variable. +ALIAS=sample +# Set UID and PWD if neccesary +UID= +PWD= + +# To connect to a remote SAMPLE2 database cataloged on the client machine +# with another name, update the ALIAS2 variable. +ALIAS2=sample2 +# Set UID2 and PWD2 if neccesary +UID2=$(UID) +PWD2=$(PWD) + +COPY=cp +ERASE=rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all (rtn + all_client) +# 2b - make srv +# 2c - make all_client (client_run) +# 2d - make call_rtn +# 2e - make client_run +# 2f - make clean +# 2g - make cleanall +############################################################################# + + +#**************************************************************************** +# 2a - make all +#**************************************************************************** + +all : \ + all_client + +#**************************************************************************** +# 2b - make srv +#**************************************************************************** + +srv : \ + spcat_xml \ + simple_xmlproc + +#**************************************************************************** +# 2c - make all_client (call_rtn + client_run) +#**************************************************************************** + +all_client : \ + client_run + +#**************************************************************************** +# 2d - make call_rtn +#**************************************************************************** + +call_rtn : \ + simple_xmlproc_client + +#**************************************************************************** +# 2e - make client_run +#**************************************************************************** + +client_run : \ + xmlconst simple_xmlproc_client xmlindex xmlinsert xmlread \ + xmltotable xmlupdel reltoxmldoc xsupdate xmludfs + +#**************************************************************************** +# 2f - make clean +#**************************************************************************** + +clean : + $(ERASE) *.o + $(ERASE) *.DEL *.TXT *.MSG + $(ERASE) *.bnd + +#**************************************************************************** +# 2g - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) xmlconst xmlindex xmlinsert xmlread xmltotable xmlupdel \ + reltoxmldoc simple_xmlproc_client simple_xmlproc xsupdate xmludfs + $(ERASE) $(DB2PATH)/function/simple_xmlproc + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - regular samples +# 3b - client/server samples +############################################################################# + +xmlconst : + $(BLDAPP) xmlconst +xmlindex : + $(BLDAPP) xmlindex +xmlinsert : + $(BLDAPP) xmlinsert +xmlread : + $(BLDAPP) xmlread +xmltotable : + $(BLDAPP) xmltotable +xmlupdel : + $(BLDAPP) xmlupdel +reltoxmldoc : + $(BLDAPP) reltoxmldoc +xsupdate : + $(BLDAPP) xsupdate +xmludfs: + $(BLDAPP) xmludfs + +#**************************************************************************** +# 3b - client/server samples +#**************************************************************************** + +simple_xmlproc_client : + $(BLDAPP) simple_xmlproc_client $(ALIAS) $(UID) $(PWD) +simple_xmlproc : + $(BLDRTN) simple_xmlproc $(ALIAS) + spcat_xml diff --git a/xml/cli/reltoxmldoc.c b/xml/cli/reltoxmldoc.c new file mode 100644 index 0000000..71d3ad5 --- /dev/null +++ b/xml/cli/reltoxmldoc.c @@ -0,0 +1,355 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: reltoxmldoc.c +** +** SAMPLE: Purchase order database uses relational tables to store the orders of +** different customers. This data can be returned as an XML object to the +** application. The XML object can be created using the XML constructor +** functions on the server side. +** To achieve this, the user can +** 1. Create a stored procedure to implement the logic to create the XML +** object using XML constructor functions. +** 2. Register the above stored procedure to the database. +** 3. Call the procedure whenever all the PO data is needed instead of using complex joins. +** +** To run this sample, peform the following steps: +** 1. create and populate the SAMPLE database +** 2. create stored procedure reltoxmlproc by executing +** db2 -td@ -f reltoxmlproc.db2 +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLEndTran -- End Transactions of a Connection +** SQLExecDirect -- Execute a Statement Directly +** SQLExecute -- Execute a Statement +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLNumResultCols -- Get Number of Result Columns +** SQLPrepare -- Prepare a Statement +** +** SQL/XML FUNCTIONS USED: +** XMLELEMENT +** XMLATTRIBUTES +** XMLCONCAT +** XMLNAMESPACES +** XMLCOMMENT +** +** EXTERNAL DEPENDENCIES: +** Ensure that the stored procedures called from this program have +** been built and cataloged with the database. +** +** OUTPUT FILE: reltoxmldoc.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilcli.h" /* header file for CLI sample code */ + +int SelectFromRelationalTable(SQLHANDLE); +int callRelToXmlProc(SQLHANDLE); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + double medSalary = 0; + char language[9]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + + printf("PERFORMING SELECT FROM RELATIONAL TABLES\n"); + rc = SelectFromRelationalTable(hdbc); + + printf("CALL STORED PROCEDURE RELTOXMLPROC.\n"); + /********************************************************/ + /* call RELTOXMLPROC stored procedure */ + /********************************************************/ + rc = callRelToXmlProc(hdbc); + + /* rollback any changes to the database made by this sample */ + printf("\nRoll back the transaction.\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* terminate the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; +} /* end main */ + + +/* perform a basic SELECT operation using SQLBindCol */ +int SelectFromRelationalTable(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLINTEGER CustId; /* variable to be bound to the CustId column */ + SQLINTEGER PoNum; /* variable to be bound to the PoNum column */ + SQLVARCHAR OrderDate[11]; /* variable to be bound to OrderDate Comment column */ + SQLVARCHAR Status[30]; /* variable to be bound to the Status column */ + SQLVARCHAR ProdId[10]; /* variable to be bound to the ProdId column */ + SQLDOUBLE Price; /* variable to be bound to the Price column */ + SQLVARCHAR Name[30]; /* Variable to be bound to the Name column */ + SQLVARCHAR Street[20]; /* Variable to be bound to the Street column */ + SQLVARCHAR City[20]; /* Variable to be bound to the City column */ + SQLVARCHAR Province[20]; /* Variable to be bound to the Province column */ + SQLINTEGER PostalCode; /* Variable to be bound to the PostalCode column */ + SQLVARCHAR Comment[200]; /* Variable to be bound to the Comment column */ + SQLCHAR stmt[500] = {0}; + + /* The SQL statement that has to be executed is copied to stmt */ + /* using the strcpy and strcat functions */ + strcpy((char *)stmt, "SELECT po.CustID, po.PoNum, po.OrderDate, po.Status, "); + strcat((char *)stmt, "count(l.ProdID) as Items, sum(p.Price) as total, po.Comment, "); + strcat((char *)stmt, "c.Name, c.Street, c.City, c.Province, c.PostalCode "); + strcat((char *)stmt, "FROM PurchaseOrder_relational as po,CustomerInfo_relational as c, "); + strcat((char *)stmt, "Lineitem_relational as l, Products_relational as p "); + strcat((char *)stmt, "WHERE po.CustID = c.CustID and po.PoNum = l.PoNum "); + strcat((char *)stmt, "and l.ProdID = p.ProdID "); + strcat((char *)stmt, "GROUP BY po.PoNum,po.CustID,po.OrderDate,po.Status,c.Name, "); + strcat((char *)stmt, "c.Street, c.City,c.Province, c.PostalCode,po.Comment "); + strcat((char *)stmt, "ORDER BY po.CustID,po.OrderDate"); + + /* set AUTOCOMMIT on */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_ON, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n\n"); + printf(" SELECT po.CustID, po.PoNum, po.OrderDate, po.Status,\n"); + printf(" count(l.ProdID) as Items, sum(p.Price) as total,\n"); + printf(" po.Comment, c.Name, c.Street, c.City, c.Province, c.PostalCode\n"); + printf(" FROM PurchaseOrder_relational as po, CustomerInfo_relational as c,\n"); + printf(" Lineitem_relational as l, Products_relational as p\n"); + printf(" WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID\n"); + printf(" GROUP BY po.PoNum,po.CustID,po.OrderDate,po.Status,c.Name,\n"); + printf(" c.Street, c.City,c.Province, c.PostalCode,po.Comment\n"); + printf(" ORDER BY po.CustID,po.OrderDate\n"); + + /* directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_LONG, &CustId, 0, NULL ); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 2 to variable */ + cliRC = SQLBindCol(hstmt, 2, SQL_C_LONG, &PoNum, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 3 to variable */ + cliRC = SQLBindCol(hstmt, 3, SQL_C_CHAR, &OrderDate, 11, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 4 to variable */ + cliRC = SQLBindCol(hstmt, 4, SQL_C_CHAR, &Status, 30, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 5 to variable */ + cliRC = SQLBindCol(hstmt, 5, SQL_C_CHAR, &ProdId, 10, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 6 to variable */ + cliRC = SQLBindCol(hstmt, 6, SQL_C_DOUBLE, &Price, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 7 to variable */ + cliRC = SQLBindCol(hstmt, 7, SQL_C_CHAR, &Comment, 200, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 8 to variable */ + cliRC = SQLBindCol(hstmt, 8, SQL_C_CHAR, &Name, 30, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 9 to variable */ + cliRC = SQLBindCol(hstmt, 9, SQL_C_CHAR, &Street, 20, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 10 to variable */ + cliRC = SQLBindCol(hstmt, 10, SQL_C_CHAR, &City, 20, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 11 to variable */ + cliRC = SQLBindCol(hstmt, 11, SQL_C_CHAR, &Province, 20, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 12 to variable */ + cliRC = SQLBindCol(hstmt, 12, SQL_C_LONG, &PostalCode, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\n Fetch each row and display.\n"); + printf(" CUSTOMER_ID PO_NO ORDER_DATE STATUS TOTAL_PROD PRICE COMMENT"); + printf(" NAME STREET CITY PROVINCE POSTAL_CODE\n"); + printf(" ------------------- ---------------------------------------------------------------------\n"); + + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + printf(" %-8d %-8d %-11s %-30s %-10s %f %-200s %-30s %-20s %-20s %-20s %d\n", + CustId, PoNum, OrderDate, Status, ProdId, Price, Comment, Name, Street, City, Province, PostalCode); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* SelectFromRelationalTable */ + + +/* call the RELTOXMLPROC stored procedure */ +int callRelToXmlProc(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + char procName[] = "RELTOXMLPROC"; + SQLCHAR *stmt = (SQLCHAR *)"CALL RELTOXMLPROC ()"; + SQLSMALLINT numCols; + SQLUINTEGER PoNum; + SQLUINTEGER CustId; + SQLCHAR OrderDate[11]; + SQLVARCHAR PurchaseOrder[2000]; + + + printf("CALL stored procedure: %s\n", procName); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* get number of result columns */ + cliRC = SQLNumResultCols(hstmt, &numCols); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("Result set returned %d columns\n", numCols); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_LONG, &PoNum, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 2 to variable */ + cliRC = SQLBindCol(hstmt, 2, SQL_C_LONG, &CustId, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 3 to variable */ + cliRC = SQLBindCol(hstmt, 3, SQL_C_CHAR, &OrderDate, 11, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 4 to variable */ + cliRC = SQLBindCol(hstmt, 4, SQL_C_CHAR, &PurchaseOrder,3000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("Stored procedure returned successfully.\n"); + + /* fetch result set returned from stored procedure */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\nFirst result set returned from %s", procName); + printf("\n------PoNum------, --CustId--, ---OrderDate--, --PurchaseOrder-- \n"); + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("%17d, %11d, %11s, %s\n\n\n", PoNum, CustId, OrderDate, PurchaseOrder); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handles */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* end callRelToXmlProc */ diff --git a/xml/cli/reltoxmlproc.db2 b/xml/cli/reltoxmlproc.db2 new file mode 100644 index 0000000..50846a3 --- /dev/null +++ b/xml/cli/reltoxmlproc.db2 @@ -0,0 +1,79 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: reltoxmlproc.db2 +-- +-- SAMPLE: This stored procedure uses the constructor functions to create an XML +-- document with all the purchase order details. The input to the constructor +-- function will be the relational data stored in the tables. The final +-- output of the constructor functions will be a well formed XML document having +-- all the purchase orders. The stored procedure will return the purchase order +-- XML document back to the application. +-- +-- This stored procedure will be called by samples +-- a)reltoxmldoc.db2 +-- b)reltoxmldoc.sqc +-- +-- SQL STATEMENTS USED: +-- CREATE PROCEDURE +-- OPEN +-- +-- OUTPUT FILE: NA +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CONNECT TO SAMPLE@ +CREATE PROCEDURE reltoxmlproc() +RESULT SETS 1 +LANGUAGE SQL +BEGIN +DECLARE C1 CURSOR WITH RETURN FOR +SELECT po.PoNum, po.CustID, po.OrderDate, XMLCONCAT( XMLPI(NAME "pi", 'MESSAGE("valid, well-formed d +ocument")'), +XMLELEMENT (NAME "PurchaseOrder", XMLNAMESPACES( 'http://www.example.org' AS "e"), +XMLATTRIBUTES (po.CustID as "CustID", po.PoNum as "PoNum", po.OrderDate as "OrderDate", po.Status as "Status" ), + XMLELEMENT (NAME "CustomerAddress", XMLCONCAT( + XMLELEMENT (NAME "e.Name", c.Name ), + XMLELEMENT (NAME "e.Street", c.Street ), + XMLELEMENT (NAME "e.City", c.City ), + XMLELEMENT (NAME "e.Province", c.Province ), + XMLELEMENT (NAME "e.PostalCode", c.PostalCode ) ) ), + XMLELEMENT (NAME "ItemList" , +XMLELEMENT (NAME "Item", +XMLELEMENT (NAME "PartId", l.ProdID ), +XMLELEMENT (NAME "Description", p.Description ), +XMLELEMENT (NAME "Quantity", l.Quantity ), +XMLELEMENT (NAME "Price", p.Price ) , +XMLCOMMENT(po.comment) ) ) ) ) +FROM PurchaseOrder_Relational as Po, CustomerInfo_Relational AS c, Lineitem_Relational AS l, Products_Relational AS p +WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID +ORDER BY po.PoNum; +OPEN C1; +END@ + diff --git a/xml/cli/simple_xmlproc.c b/xml/cli/simple_xmlproc.c new file mode 100644 index 0000000..8289db3 --- /dev/null +++ b/xml/cli/simple_xmlproc.c @@ -0,0 +1,659 @@ +/************************************************************************* +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +*************************************************************************** +** +** SOURCE FILE NAME: simple_xmlproc.c +** +** SAMPLE: Code implementation of a stored procedure Simple_XML_Proc_CLI +** +** The stored procedures defined in this program is called by the client +** application simple_xmlproc_client.c. Before building and running +** simple_xmlproc_client.c, build the shared library by completing the +** following steps: +** +** BUILDING THE SHARED LIBRARY: +** 1. Ensure the Database Manager Configuration file has the keyword +** KEEPFENCED set to "no". This allows shared libraries to be unloaded +** while you are developing stored procedures. You can view the file's +** settings by issuing the command: "db2 get dbm cfg". You can set +** KEEPFENCED to "no" with this command: "db2 update dbm cfg using +** KEEPFENCED no". NOTE: Setting KEEPFENCED to "no" reduces performance +** the performance of accessing stored procedures, because they have +** to be reloaded into memory each time they are called. If this is a +** concern, set KEEPFENCED to "yes", stop and then restart DB2 before +** building the shared library, by entering "db2stop" followed by +** "db2start". This forces DB2 to unload shared libraries and enables +** the build file or the makefile to delete a previous version of the +** shared library from the "sqllib/function" directory. +** 2. To build the shared library, enter "bldrtn simple_xmlproc", or use the +** makefile: "make simple_xmlproc" (UNIX) or "nmake simple_xmlproc" (Windows). +** +** CATALOGING THE STORED PROCEDURES +** 1. The stored procedures are cataloged automatically when you build +** the client application "simple_xmlproc_client" using the appropriate "make" +** utility for your Operating System and the "makefile" provided with these +** samples. If you wish to catalog or recatalog them manually, enter +** "spcat_xml". The spcat_xml script (UNIX) or spcat_xml.bat batch file (Windows) +** connects to the database, runs simple_xmlproc_drop.db2 to uncatalog the stored +** procedures if they were previously cataloged, then runs simple_xmlproc_create.db2 +** which catalogs the stored procedures, then disconnects from the database. +** +** CALLING THE STORED PROCEDURES IN THE SHARED LIBRARY: +** 1. Compile the simple_xmlproc_client program with "bldapp simple_xmlproc_client" or use the +** makefile: "make simple_xmlproc_client" (UNIX) or "nmake simple_xmlproc_client" (Windows). +** 2. Run simple_xmlproc_client: "simple_xmlproc_client" (if calling remotely add the parameters +** for database, user ID and password.) +** +** DESCRIPTION OF FUNCTION SIMPLE_PROC: +** This function will take Customer Information ( of type XML) as input , +** finds whether the customer with Cid in Customer Information exists in the +** customer table or not, if not this will insert the customer information +** into the customer table with same Customer id, and returns all the customers +** from the same city of the input customer information in XML format to the caller +** along with location as an output parameter in XML format. +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLBindParameter -- Bind a Parameter Marker to a Buffer or +** LOB locator +** SQLConnect -- Connect to a Data Source +** SQLDisconnect -- Disconnect from a Data Source +** SQLExecDirect -- Execute a Statement Directly +** SQLExecute -- Execute a Statement +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLPrepare -- Prepare a Statement +** SQLSetConnectAttr -- Set Connection Attributes +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilcli.h" + +/* macros for handle checking */ +#define SRV_HANDLE_CHECK(htype, hndl, CLIrc, henv, hdbc) \ +if (CLIrc == SQL_INVALID_HANDLE) \ +{ \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} \ +if (CLIrc == SQL_ERROR) \ +{ \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} + +#define \ +SRV_HANDLE_CHECK_SETTING_SQLST(htype, hndl, CLIrc, henv, hdbc, sqlstate) \ +If (CLIrc == SQL_INVALID_HANDLE) \ +{ \ + memset(sqlstate, '0', 6); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} \ +if (CLIrc == SQL_ERROR) \ +{ \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} + +#define \ +SRV_HANDLE_CHECK_SETTING_SQLRC_AND_MSG(htype, \ + hndl, \ + CLIrc, \ + henv, \ + hdbc, \ + outReturnCode, \ + outErrorMsg, \ + inMsg) \ +if (CLIrc == SQL_INVALID_HANDLE) \ +{ \ + *outReturnCode = 0; \ + strcpy(outErrorMsg, inMsg); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} \ +if (CLIrc == SQL_ERROR) \ +{ \ + *outReturnCode = -1; \ + strcat(outErrorMsg, inMsg); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} + +#define \ +SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(htype, \ + hndl, \ + CLIrc, \ + henv, \ + hdbc, \ + sqlstate, \ + outMsg, \ + inMsg) \ +if (CLIrc == SQL_INVALID_HANDLE) \ +{ \ + memset(sqlstate, '0', 6); \ + strcpy(outMsg, inMsg); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} \ +if (CLIrc != 0 && CLIrc != SQL_NO_DATA_FOUND ) \ +{ \ + SetErrorMsg(htype, hndl, henv, hdbc, outMsg, inMsg); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} + +void StpCleanUp(SQLHANDLE henv, SQLHANDLE hdbc) +{ + /* disconnect from a data source */ + SQLDisconnect(hdbc); + + /* free the database handle */ + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + + /* free the environment handle */ + SQLFreeHandle(SQL_HANDLE_ENV, henv); +} + +void SetErrorMsg(SQLSMALLINT htype, + SQLHANDLE hndl, + SQLHANDLE henv, + SQLHANDLE hdbc, + char *outMsg, + char *inMsg) +{ + SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; + SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER sqlcode; + SQLSMALLINT length; + SQLGetDiagRec(htype, + hndl, + 1, + sqlstate, + &sqlcode, + message, + SQL_MAX_MESSAGE_LENGTH + 1, + &length); + sprintf(outMsg, "%ld: ", sqlcode); + strcat(outMsg, inMsg); +} + +/************************************************************************** +** Stored procedure: simple_proc +** +** Purpose: +** This sample will take Customer Information ( of type XML) as input , +** finds whether the customer with Cid in Customer Information exists in the +** customer table or not, if not this will insert the customer information +** into the customer table with same Customer id, and returns all the customers +** from the same city of the input customer information in XML format to the caller +** along with location as an output parameter in XML format. +** +** Shows how to: +** - define XML type parameters in a Stored Procedure +** - return a result set to the client +** +** Parameters: +** +** IN: inXML - Customer information an XML document +** OUT: outXML - Location of input customer as an XML document +** Returns Customers from that city to caller. +** +** When the PARAMETER STYLE SQL clause is specified +** in the CREATE PROCEDURE statement for the procedure +** (see the script xquery_xmlproc_create.db2), in addition to the +** parameters passed at procedure invocation time, the +** following parameters are passed to the routine +** in the following order: +** - one null indicator for each IN/INOUT/OUT parameter +** is specified in the same order as the corresponding +** parameter declarations. +** - sqlstate: to be returned to the caller to indicate +** state (output) +** - routine-name: qualified name of the routine (input) +** - specific-name: the specific name of the routine (input) +** - diagnostic-message: an optional text string returned to the +** caller (output) +** See the actual parameter declarations below to see +** the recommended datatypes and sizes for them. +** +** CODE TIP: +** -------- +** As an alternative to coding the non-functional parameters +** required with parameter style SQL (sqlstate, routine-name, +** specific-name, diagnostic-message), you can use a macro: +** SQLUDF_TRAIL_ARGS. This macro is defined in DB2 include +** file sqludf.h +** +**************************************************************************/ + +SQL_API_RC SQL_API_FN simple_proc ( SQLUDF_CLOB* inXML, + SQLUDF_CLOB* outXML, + sqlint16 *inXML_ind, + sqlint16 *outXML_ind, + char sqlstate[6], + char qualName[28], + char specName[19], + char diagMsg[71]) +{ + SQLHANDLE henv; + SQLHANDLE hdbc = 0; + SQLHANDLE hstmt,hstmt1,hstmt2,hstmt3,hstmt4,hstmt5; + SQLRETURN cliRC; + SQLCHAR stmt[1024],stmt1[1024],stmt2[1024],stmt3[1024],stmt4[1024],stmt5[1024]; + SQLINTEGER custid,quantity,count; + char city[100]; + + /* Initialize output parameters to NULL*/ + memset(outXML->data,'\0',5000); + *outXML_ind=-1; + + /* intilize the application variables */ + quantity=0; + count=0; + custid=0; + + cliRC = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + SRV_HANDLE_CHECK(SQL_HANDLE_ENV, henv, cliRC, henv, hdbc); + + /* allocate the database handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); + SRV_HANDLE_CHECK(SQL_HANDLE_ENV, henv, cliRC, henv, hdbc); + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + SQL_AUTOCOMMIT_OFF, + SQL_NTS); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* issue NULL Connect, because in CLI a statement handle is + required and thus a connection handle and environment handle. + A connection is not established; rather the current + connection from the calling application is used. */ + + /* connect to a data source */ + cliRC = SQLConnect(hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt1); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt2); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt3); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt4); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt5); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* find whether the customer with that Info exists in the customer table */ + strcpy((char *)stmt,"SELECT COUNT(*) FROM customer WHERE " + "XMLEXISTS('$info/customerinfo[@Cid=$id]' " + "PASSING by ref cast(? as XML) AS \"info\", cid as \"id\")"); + + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement stmt failed."); + /* bind the input XML document */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(inXML->data), + inXML->length, + (SQLINTEGER *)&(inXML->length)); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter1"); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement failed."); + + /* bind the column to an application variable */ + cliRC = SQLBindCol(hstmt, + 1, + SQL_C_LONG, + &count, + 0, + NULL); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + /* fetch a row */ + cliRC = SQLFetch(hstmt); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + + /* if customer doesn't exist ...... insert into the table */ + if(count < 1 ) + { + /* get the custid from the customer information */ + strcpy((char *)stmt1,"SELECT XMLCAST( XMLQUERY('$info/customerinfo/@Cid' " + "passing by ref cast(? as XML) as \"info\") as " + "BIGINT) FROM SYSIBM.SYSDUMMY1"); + cliRC = SQLPrepare(hstmt1, stmt1, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement stmt failed."); + cliRC = SQLBindParameter(hstmt1, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(inXML->data), + inXML->length, + (SQLINTEGER *)&(inXML->length)); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter1"); + + cliRC = SQLExecute(hstmt1); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement failed."); + /* get customer id into custid */ + cliRC = SQLBindCol(hstmt1, + 1, + SQL_C_LONG, + &custid, + 0, + NULL); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt1, cliRC, henv, hdbc); + /* fetch a row */ + cliRC = SQLFetch(hstmt1); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt1, cliRC, henv, hdbc); + + /* insert into customer table with that custid */ + strcpy((char *)stmt2,"INSERT INTO customer(Cid, Info) VALUES (?,?)"); + cliRC = SQLPrepare(hstmt2, stmt2, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt2, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement stmt failed."); + /* bind the parameter to the statement */ + cliRC = SQLBindParameter(hstmt2, + 1, + SQL_PARAM_INPUT, + SQL_C_LONG, + SQL_INTEGER, + 0, + 0, + &custid, + 0, + NULL); + SRV_HANDLE_CHECK_SETTING_SQLRC_AND_MSG(SQL_HANDLE_STMT, + hstmt2, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter1"); + cliRC = SQLBindParameter(hstmt2, + 2, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(inXML->data), + inXML->length, + (SQLINTEGER *)&(inXML->length)); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt2, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter1"); + + cliRC = SQLExecute(hstmt2); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt2, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement failed."); + } + /* find the city of the customer and assign it to an application variable */ + strcpy((char *)stmt3,"SELECT XMLCAST( XMLQUERY('$info/customerinfo//city' " + "passing by ref cast(? as XML) as \"info\") as " + "VARCHAR(100)) FROM SYSIBM.SYSDUMMY1"); + cliRC = SQLPrepare(hstmt3, stmt3, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt3, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement stmt failed."); + cliRC = SQLBindParameter(hstmt3, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(inXML->data), + inXML->length, + (SQLINTEGER *)&(inXML->length)); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt3, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter1"); + + cliRC = SQLExecute(hstmt3); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt3, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement failed."); + /* bind a column to an application variable */ + cliRC = SQLBindCol(hstmt3, 1, SQL_C_CHAR, city, 100, NULL); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt3, cliRC, henv, hdbc); + + /* fetch each row */ + cliRC = SQLFetch(hstmt3); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt3, cliRC, henv, hdbc); + + /* Location of the input information as XML output */ + strcpy((char *)stmt4,"SELECT XMLQUERY('let $city:=$info/customerinfo//city " + "let $prov:=$info/customerinfo//prov-state return " + "{$city}{$prov} ' passing by ref cast(? as XML) as " + "\"info\") FROM SYSIBM.SYSDUMMY1"); + cliRC = SQLPrepare(hstmt4, stmt4, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt4, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "statement stmt4 failed."); + cliRC = SQLBindParameter(hstmt4, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(inXML->data), + inXML->length, + (SQLINTEGER *)&(inXML->length)); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt4, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter1"); + + cliRC = SQLExecute(hstmt4); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt4, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "EXECUTE statement failed."); + /* bind a column to an application variable */ + cliRC = SQLBindCol(hstmt4, + 1, + SQL_C_CHAR, + &(outXML->data), + 5000, + (SQLINTEGER*)&(outXML->length)); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt4, cliRC, henv, hdbc); + + /* fetch a row */ + cliRC = SQLFetch(hstmt4); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt4, cliRC, henv, hdbc); + + *outXML_ind = 0; + + /* findout all he customers from that city and return as an XML to caller */ + strcpy((char *)stmt5,"XQUERY for $cust in db2-fn:xmlcolumn" + "(\"CUSTOMER.INFO\")/customerinfo/addr[city=\""); + strcat((char *)stmt5, city); + strcat((char *)stmt5, "\"] order by xs:double($cust/../@Cid) return {$cust/../@Cid}{$cust/../name}"); + + cliRC = SQLPrepare(hstmt5, stmt5, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt5, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "XQUERY statement failed."); + cliRC = SQLExecute(hstmt5); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt5, cliRC, henv, hdbc); + + /* free the handles */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt1); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt1, cliRC, henv, hdbc); + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt2); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt2, cliRC, henv, hdbc); + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt3); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt3, cliRC, henv, hdbc); + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt4); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt4, cliRC, henv, hdbc); + + /* disconnect from the data source */ + cliRC = SQLDisconnect(hdbc); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* free the database handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* free the environment handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_ENV, henv); + SRV_HANDLE_CHECK(SQL_HANDLE_ENV, henv, cliRC, henv, hdbc); + + return (0); +} diff --git a/xml/cli/simple_xmlproc.exp b/xml/cli/simple_xmlproc.exp new file mode 100644 index 0000000..7865d3b --- /dev/null +++ b/xml/cli/simple_xmlproc.exp @@ -0,0 +1 @@ +simple_proc diff --git a/xml/cli/simple_xmlproc_client.c b/xml/cli/simple_xmlproc_client.c new file mode 100644 index 0000000..c028c2f --- /dev/null +++ b/xml/cli/simple_xmlproc_client.c @@ -0,0 +1,250 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: simple_xmlproc_client.c +** +** SAMPLE: Call the stored procedure implemented in simple_xmlproc.c +** +** To run this sample, peform the following steps: +** (1) see and complete the instructions in simple_xmlproc.c for building +** the shared library +** (2) compile simple_xmlproc_client.c (nmake xquery_xmlproc_client (Windows) +** or make simple_xmlproc_client(UNIX), or bldapp xquery_xmlproc_client +** for the Microsoft Visual C++ compiler on Windows) +** (3) run simple_xmlproc_client (xquery_xmlproc_client) +** +** simple_xmlproc_client.c uses a function to call stored procedure defined +** in simple_xmlproc.c. +** +** callsimple_proc: Calls the stored procedure defined in simple_xmlproc.c +** This function will take Customer Information ( of type XML) as input , +** finds whether the customer with cid in Customer Information exists in the +** customer table , if not this will insert the customer info with that cid +** into the customer table, and find out all the customers from the same city +** of this customer and returns the resultset to caller. +** +** Parameter types used: +** IN XML AS CLOB(5000) +** OUT XML AS CLOB(5000) +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLBindParameter -- Bind a Parameter Marker to a Buffer or +** LOB locator +** SQLEndTran -- End Transactions of a Connection +** SQLExecute -- Execute a Statement +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLPrepare -- Prepare a Statement +** +** EXTERNAL DEPENDENCIES: +** Ensure that the stored procedures called from this program have +** been built and cataloged with the database (see the instructions in +** simple_xmlproc.c). +** +** OUTPUT FILE: simple_xmlproc_client.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilcli.h" + +int callsimple_proc(SQLHANDLE); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + SQL_AUTOCOMMIT_OFF); + if (rc != 0) + { + return rc; + } + + /* calling stored procedure */ + rc = callsimple_proc(hdbc); + + /* rollback any changes to the database made by this sample */ + printf("\nRoll back the transaction.\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* terminate the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; +} /* end main */ + +/* call the Simple_XML_Proc_CLI stored procedure */ +int callsimple_proc(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + SQLHANDLE hstmt; /* statement handle */ + int rc = 0; + char temp[5000]=""; + char temp1[5000]=""; + SQLSMALLINT numCols; + struct inXML_t + { + sqluint32 length; + char data[5000]; + } inXML; + struct outXML_t + { + sqluint32 length; + char data[5000]; + } outXML,tempXML; + + char procName[] = "Simple_XML_Proc_CLI"; + SQLCHAR *stmt = (SQLCHAR *)"CALL Simple_XML_Proc_CLI(?,?)"; + /* input data */ + strcpy( inXML.data, "" + "Kathy Smith25 EastCreek" + "MarkhamOntario" + "N9C-3T6905-566-7258" + ""); + inXML.length=strlen(inXML.data); + + printf("\n ******************************************************************************\n"); + printf("\n CALL stored procedure: %s\n", procName); + + outXML.length = 0; + memset(outXML.data,' ',5000); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind the parameters to the statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(inXML.data), + 5000, + (SQLINTEGER *)&(inXML.length)); + STMT_HANDLE_CHECK(hstmt,hdbc,cliRC); + cliRC = SQLBindParameter(hstmt, + 2, + SQL_PARAM_OUTPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(outXML.data), + 5000, + (SQLINTEGER*)&(outXML.length)); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + + printf("Stored procedure returned successfully.\n"); + + /* place the results into application variables */ + strncpy(temp, outXML.data,outXML.length); + temp[outXML.length] = '\n'; + printf("\n Location is: \n %s \n", temp); + + /* get number of result columns */ + cliRC = SQLNumResultCols(hstmt, &numCols); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("Result set returned %d columns...\n", numCols); + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, + 1, + SQL_C_CHAR, + &(tempXML.data), + 5000, + (SQLINTEGER*)&(tempXML.length)); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch result set returned from stored procedure */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + while (cliRC != SQL_NO_DATA_FOUND) + { + /* place the results into application variables */ + strncpy(temp1, tempXML.data, tempXML.length); + temp[outXML.length] = '\n'; + printf("\n %s", temp1 ); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +}/* end callsimple_proc */ diff --git a/xml/cli/simple_xmlproc_create.db2 b/xml/cli/simple_xmlproc_create.db2 new file mode 100644 index 0000000..558952b --- /dev/null +++ b/xml/cli/simple_xmlproc_create.db2 @@ -0,0 +1,55 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: simple_xmlproc_create.db2 +-- +-- SAMPLE: How to catalog the DB2 CLI stored procedure contained in +-- simple_xmlproc.c +-- +-- To run this script from the CLP, issue the command +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- +-- For more information on the sample programs, see the README file. +-- +-- For information on developing CLI applications, see the CLI Guide +-- and Reference. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- creating procedure +CREATE PROCEDURE Simple_XML_Proc_CLI( IN inXML XML as CLOB(5000), + OUT outXML XML as CLOB(5000)) +LANGUAGE C +DYNAMIC RESULT SETS 1 +PARAMETER STYLE SQL +FENCED +PARAMETER CCSID UNICODE +EXTERNAL NAME 'simple_xmlproc!simple_proc'@ + +CONNECT RESET@ diff --git a/xml/cli/simple_xmlproc_drop.db2 b/xml/cli/simple_xmlproc_drop.db2 new file mode 100644 index 0000000..3896100 --- /dev/null +++ b/xml/cli/simple_xmlproc_drop.db2 @@ -0,0 +1,36 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: simple_xmlproc_drop.db2 +-- +-- SAMPLE: Uncatalog the DB2 CLI stored procedure contained in simple_xmlproc.c +-- +-- To run this script from the CLP, issue the command +-- "db2 -td@ -vf " +-- where represents the name of this script +---------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- drop the procedure +DROP PROCEDURE Simple_XML_Proc_CLI ( XML as CLOB(5000), + XML as CLOB(5000))@ +CONNECT RESET@ diff --git a/xml/cli/spcat_xml b/xml/cli/spcat_xml new file mode 100644 index 0000000..f7036e1 --- /dev/null +++ b/xml/cli/spcat_xml @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: spcat_xml +# To catalo XML CLI stored procedures on UNIX +# Catalogs the stored procedures in the simple_xmlproc library +# simple_xmlproc_drop.db2 uncatalogs the stored procedures if previously cataloged +# simple_xmlproc_create.db2 catologs the stored procedures +# Both CLP scripts can be run on their own +# Usage: spcat_xml + +db2 -td@ -vf simple_xmlproc_drop.db2 +db2 -td@ -vf simple_xmlproc_create.db2 diff --git a/xml/cli/utilcli.c b/xml/cli/utilcli.c new file mode 100644 index 0000000..7f7a1ca --- /dev/null +++ b/xml/cli/utilcli.c @@ -0,0 +1,638 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilcli.c +** +** SAMPLE: Utility functions used by DB2 CLI samples +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLColAttribute -- Return a Column Attribute +** SQLConnect -- Connect to a Data Source +** SQLDescribeCol -- Return a Set of Attributes for a Column +** SQLDisconnect -- Disconnect from a Data Source +** SQLEndTran -- End Transactions of a Connection +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLFreeStmt -- Free (or Reset) a Statement Handle +** SQLGetDiagRec -- Get Multiple Field Settings of Diagnostic Record +** SQLNumResultCols -- Get Number of Result Columns +** SQLSetConnectAttr -- Set Connection Attributes +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilcli.h" + +/* local functions for utilcli.c */ +void HandleLocationPrint(SQLRETURN, int, char *); +void HandleDiagnosticsPrint(SQLSMALLINT, SQLHANDLE); + +/* funtion used in DB2_API_CHECK */ +void SqlInfoPrint(char *, struct sqlca*, int, char*); + +/* outputs to screen unexpected occurrences with CLI functions */ +int HandleInfoPrint(SQLSMALLINT htype, /* handle type identifier */ + SQLHANDLE hndl, /* handle used by the CLI function */ + SQLRETURN cliRC, /* return code of the CLI function */ + int line, + char *file) +{ + int rc = 0; + + switch (cliRC) + { + case SQL_SUCCESS: + rc = 0; + break; + case SQL_INVALID_HANDLE: + printf("\n-CLI INVALID HANDLE-----\n"); + HandleLocationPrint(cliRC, line, file); + rc = 1; + break; + case SQL_ERROR: + printf("\n--CLI ERROR--------------\n"); + HandleLocationPrint(cliRC, line, file); + HandleDiagnosticsPrint(htype, hndl); + rc = 2; + break; + case SQL_SUCCESS_WITH_INFO: + rc = 0; + break; + case SQL_STILL_EXECUTING: + rc = 0; + break; + case SQL_NEED_DATA: + rc = 0; + break; + case SQL_NO_DATA_FOUND: + rc = 0; + break; + default: + printf("\n--default----------------\n"); + HandleLocationPrint(cliRC, line, file); + rc = 3; + break; + } + + return rc; +} /* HandleInfoPrint */ + +void HandleLocationPrint(SQLRETURN cliRC, int line, char *file) +{ + printf(" cliRC = %d\n", cliRC); + printf(" line = %d\n", line); + printf(" file = %s\n", file); +} /* HandleLocationPrint */ + +void HandleDiagnosticsPrint(SQLSMALLINT htype, /* handle type identifier */ + SQLHANDLE hndl /* handle */ ) +{ + SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; + SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER sqlcode; + SQLSMALLINT length, i; + + i = 1; + + /* get multiple field settings of diagnostic record */ + while (SQLGetDiagRec(htype, + hndl, + i, + sqlstate, + &sqlcode, + message, + SQL_MAX_MESSAGE_LENGTH + 1, + &length) == SQL_SUCCESS) + { + printf("\n SQLSTATE = %s\n", sqlstate); + printf(" Native Error Code = %d\n", sqlcode); + printf("%s\n", message); + i++; + } + + printf("-------------------------\n"); +} /* HandleDiagnosticsPrint */ + +/* free statement handles and print unexpected occurrences */ +/* this function is used in STMT_HANDLE_CHECK */ +int StmtResourcesFree(SQLHANDLE hstmt) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + /* free the statement handle */ + cliRC = SQLFreeStmt(hstmt, SQL_UNBIND); + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, cliRC, __LINE__, __FILE__); + if (rc != 0) + { + return 1; + } + + /* free the statement handle */ + cliRC = SQLFreeStmt(hstmt, SQL_RESET_PARAMS); + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, cliRC, __LINE__, __FILE__); + if (rc != 0) + { + return 1; + } + + /* free the statement handle */ + cliRC = SQLFreeStmt(hstmt, SQL_CLOSE); + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, cliRC, __LINE__, __FILE__); + if (rc != 0) + { + return 1; + } + + return 0; +} /* StmtResourcesFree */ + +/* rollback transactions on a single connection */ +/* this function is used in HANDLE_CHECK */ +void TransRollback(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + rc = HandleInfoPrint(SQL_HANDLE_DBC, hdbc, cliRC, __LINE__, __FILE__); + if (rc == 0) + { + printf(" The transaction rolled back.\n"); + } +} /* TransRollback */ + +/* rollback transactions on mutiple connections */ +/* this function is used in HANDLE_CHECK */ +void MultiConnTransRollback(SQLHANDLE henv) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + printf("\n Rolling back the transactions...\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_ENV, henv, SQL_ROLLBACK); + rc = HandleInfoPrint(SQL_HANDLE_ENV, henv, cliRC, __LINE__, __FILE__); + if (rc == 0) + { + printf(" The transactions are rolled back.\n"); + } +} /* MultiConnTransRollback */ + +/* check command line arguments */ +int CmdLineArgsCheck1(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck1 */ + +/* check command line arguments */ +int CmdLineArgsCheck2(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[], + char remoteNodeName[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + strcpy(remoteNodeName, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + strcpy(remoteNodeName, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + strcpy(remoteNodeName, ""); + break; + case 5: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + strcpy(remoteNodeName, argv[4]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd [remoteNodeName]]]\n", + argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck2 */ + +/* check command line arguments */ +int CmdLineArgsCheck3(int argc, + char *argv[], + char dbAlias1[], + char dbAlias2[], + char user1[], + char pswd1[], + char user2[], + char pswd2[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias1, "sample"); + strcpy(dbAlias2, "sample2"); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 3: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 5: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[3]); + strcpy(pswd2, argv[4]); + break; + case 7: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[5]); + strcpy(pswd2, argv[6]); + break; + default: + printf("\nUSAGE: %s " + "[dbAlias1 dbAlias2 [user1 pswd1 [user2 pswd2]]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck3 */ + +/* initialize a CLI application by: + o allocating an environment handle + o allocating a connection handle + o setting AUTOCOMMIT + o connecting to the database */ +int CLIAppInit(char dbAlias[], + char user[], + char pswd[], + SQLHANDLE *pHenv, + SQLHANDLE *pHdbc, + SQLPOINTER autocommitValue) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + /* allocate an environment handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, pHenv); + if (cliRC != SQL_SUCCESS) + { + printf("\n--ERROR while allocating the environment handle.\n"); + printf(" cliRC = %d\n", cliRC); + printf(" line = %d\n", __LINE__); + printf(" file = %s\n", __FILE__); + return 1; + } + + /* set attribute to enable application to run as ODBC 3.0 application */ + cliRC = SQLSetEnvAttr(*pHenv, + SQL_ATTR_ODBC_VERSION, + (void *)SQL_OV_ODBC3, + 0); + ENV_HANDLE_CHECK(*pHenv, cliRC); + + /* allocate a database connection handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_DBC, *pHenv, pHdbc); + ENV_HANDLE_CHECK(*pHenv, cliRC); + + /* set AUTOCOMMIT off or on */ + cliRC = SQLSetConnectAttr(*pHdbc, + SQL_ATTR_AUTOCOMMIT, + autocommitValue, + SQL_NTS); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + + printf("\n Connecting to %s...\n", dbAlias); + + /* connect to the database */ + cliRC = SQLConnect(*pHdbc, + (SQLCHAR *)dbAlias, + SQL_NTS, + (SQLCHAR *)user, + SQL_NTS, + (SQLCHAR *)pswd, + SQL_NTS); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + printf(" Connected to %s.\n", dbAlias); + + return 0; +} /* CLIAppInit */ + +/* terminate a CLI application by: + o disconnecting from the database + o freeing the connection handle + o freeing the environment handle */ +int CLIAppTerm(SQLHANDLE * pHenv, SQLHANDLE * pHdbc, char dbAlias[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + printf("\n Disconnecting from %s...\n", dbAlias); + + /* disconnect from the database */ + cliRC = SQLDisconnect(*pHdbc); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + + printf(" Disconnected from %s.\n", dbAlias); + + /* free connection handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_DBC, *pHdbc); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + + /* free environment handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_ENV, *pHenv); + ENV_HANDLE_CHECK(*pHenv, cliRC); + + return 0; +} /* CLIAppTerm */ + +/* output result sets */ +int StmtResultPrint(SQLHANDLE hstmt, SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + SQLSMALLINT i; /* index */ + SQLSMALLINT nResultCols; /* variable for SQLNumResultCols */ + SQLCHAR colName[32]; /* variables for SQLDescribeCol */ + SQLSMALLINT colNameLen; + SQLSMALLINT colType; + SQLUINTEGER colSize; + SQLSMALLINT colScale; + SQLINTEGER colDataDisplaySize; /* maximum size of the data */ + SQLINTEGER colDisplaySize[MAX_COLUMNS]; /* maximum size of the column */ + + struct + { + SQLCHAR *buff; + SQLINTEGER len; + SQLINTEGER buffLen; + } + outData[MAX_COLUMNS]; /* variable to read the results */ + + /* identify the output columns */ + cliRC = SQLNumResultCols(hstmt, &nResultCols); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\n"); + for (i = 0; i < nResultCols; i++) + { + + /* return a set of attributes for a column */ + cliRC = SQLDescribeCol(hstmt, + (SQLSMALLINT)(i + 1), + colName, + sizeof(colName), + &colNameLen, + &colType, + &colSize, + &colScale, + NULL); + + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* get display size for column */ + cliRC = SQLColAttribute(hstmt, + (SQLSMALLINT)(i + 1), + SQL_DESC_DISPLAY_SIZE, + NULL, + 0, + NULL, + &colDataDisplaySize); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* set "column display size" to max of "column data display size", + and "column name length", plus at least one space between columns */ + colDisplaySize[i] = max(colDataDisplaySize, colNameLen) + 1; + + /* print the column name */ + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], colName); + + /* set "output data buffer length" to "column data display size" + plus one byte for the null terminator */ + outData[i].buffLen = colDataDisplaySize + 1; + + /* allocate memory to bind column */ + outData[i].buff = (SQLCHAR *)malloc((int)outData[i].buffLen); + + /* bind columns to program variables, converting all types to CHAR */ + cliRC = SQLBindCol(hstmt, + (SQLSMALLINT)(i + 1), + SQL_C_CHAR, + outData[i].buff, + outData[i].buffLen, + &outData[i].len); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + printf("\n"); + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + + while (cliRC == SQL_SUCCESS || cliRC == SQL_SUCCESS_WITH_INFO) + { + for (i = 0; i < nResultCols; i++) + { + /* check for NULL data */ + if (outData[i].len == SQL_NULL_DATA) + { + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], "NULL"); + } + else + { + /* print outData for this column */ + printf("%-*.*s", + (int)colDisplaySize[i], + (int)colDisplaySize[i], outData[i].buff); + } + } /* for all columns in this row */ + + printf("\n"); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } /* while rows to fetch */ + + /* free data buffers */ + for (i = 0; i < nResultCols; i++) + { + free(outData[i].buff); + } + + return rc; +} /* StmtResultPrint */ + +/* prints the warning/error details including file name, line number, + sqlcode and SQLSTATE. */ +void SqlInfoPrint(char *appMsg, struct sqlca *pSqlca, int line, char *file) +{ + int rc = 0; + char sqlInfo[1024]; /* string to store all the error information */ + char sqlInfoToken[1024]; /* string to store tokens of information */ + char sqlstateMsg[1024]; /* string to store SQLSTATE message*/ + char errorMsg[1024]; /* string to store error message */ + + if (pSqlca->sqlcode != 0 && pSqlca->sqlcode != 100) + { + strcpy(sqlInfo, ""); + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "\n---- error report -----------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } + else + { + sprintf(sqlInfoToken, + "\n---- warning report ---------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } /* endif */ + + sprintf(sqlInfoToken, "\napplication message = %s\n", appMsg); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "line = %d\n", line); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "file = %s\n", file); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "SQLCODE = %d\n\n", pSqlca->sqlcode); + strcat(sqlInfo, sqlInfoToken); + + /* get error message */ + rc = sqlaintp(errorMsg, 1024, 80, pSqlca); + if (rc > 0) /* return code is the length of the errorMsg string */ + { + sprintf(sqlInfoToken, "%s\n", errorMsg); + strcat(sqlInfo, sqlInfoToken); + } + + /* get SQLSTATE message */ + rc = sqlogstt(sqlstateMsg, 1024, 80, pSqlca->sqlstate); + if (rc > 0) + { + sprintf(sqlInfoToken, "%s\n", sqlstateMsg); + strcat(sqlInfo, sqlInfoToken); + } + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "---- end error report ------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } + else + { + sprintf(sqlInfoToken, + "---- end warning report ----------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } /* endif */ + } /* endif */ +} /* SqlInfoPrint */ diff --git a/xml/cli/utilcli.h b/xml/cli/utilcli.h new file mode 100644 index 0000000..842026f --- /dev/null +++ b/xml/cli/utilcli.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilcli.h +** +** SAMPLE: Declaration of utility functions used by DB2 CLI samples +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILCLI_H +#define UTILCLI_H + +#define MAX_UID_LENGTH 18 +#define MAX_PWD_LENGTH 30 +#define MAX_STMT_LEN 255 +#define MAX_COLUMNS 255 +#ifdef DB2WIN +#define MAX_TABLES 50 +#else +#define MAX_TABLES 255 +#endif + +#ifndef max +#define max(a,b) (a > b ? a : b) +#endif + +/* macro for environment handle checking */ +#define ENV_HANDLE_CHECK(henv, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_ENV, henv, \ + cliRC, __LINE__, __FILE__); \ + if (rc != 0) return rc; \ +} + +/* macro for connection handle checking */ +#define DBC_HANDLE_CHECK(hdbc, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_DBC, hdbc, \ + cliRC, __LINE__, __FILE__); \ + if (rc != 0) return rc; \ +} + +/* macro for statement handle checking */ +#define STMT_HANDLE_CHECK(hstmt, hdbc, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, \ + cliRC, __LINE__, __FILE__); \ + if (rc == 2) StmtResourcesFree(hstmt); \ + if (rc != 0) TransRollback(hdbc); \ + if (rc != 0) return rc; \ +} + +/* macro for statement handle checking in + applications with multiple connections */ +#define MC_STMT_HANDLE_CHECK(hstmt, henv, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, \ + cliRC, __LINE__, __FILE__); \ + if (rc == 2) StmtResourcesFree(hstmt); \ + if (rc != 0) MultiConnTransRollback(henv); \ + if (rc != 0) return rc; \ +} + +/* macro for DB2_API checking */ +#define DB2_API_CHECK(MSG_STR) \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ +if (sqlca.sqlcode < 0) \ +{ \ + return 1; \ +} + +/* macro for expected error checking checking */ +#define EX_STMT_HANDLE_CHECK(hstmt, hdbc, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, \ + cliRC, __LINE__, __FILE__); \ + if (rc == 2) StmtResourcesFree(hstmt); \ +} + +/* functions used in ...CHECK_HANDLE macros */ +int HandleInfoPrint(SQLSMALLINT, SQLHANDLE, SQLRETURN, int, char *); +void CLIAppCleanUp(SQLHANDLE *, SQLHANDLE a_hdbc[], int); +int StmtResourcesFree(SQLHANDLE); +void TransRollback(SQLHANDLE); +void MultiConnTransRollback(SQLHANDLE); + +/* functions to check the number of command line arguments */ +int CmdLineArgsCheck1(int, char *argv[], char *, char *, char *); +int CmdLineArgsCheck2(int, char *argv[], char *, char *, char *, char *); +int CmdLineArgsCheck3(int, char *argv[], char *, char *, + char *, char *, char *, char *); + +/* function used in DB2_API_CHECK */ +void SqlInfoPrint(char *, struct sqlca*, int, char*); + +/* other utility functions */ +int CLIAppInit(char *, char *, char *, SQLHANDLE *, SQLHANDLE *, SQLPOINTER); +int CLIAppTerm(SQLHANDLE *, SQLHANDLE *, char *); +int StmtResultPrint(SQLHANDLE, SQLHANDLE); + +#endif + diff --git a/xml/cli/xmlconst.c b/xml/cli/xmlconst.c new file mode 100644 index 0000000..8b8d1f0 --- /dev/null +++ b/xml/cli/xmlconst.c @@ -0,0 +1,394 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlconst.c +** +** SAMPLE: Shows how to create a unique index on XML columns +** +** NOTE : +** 1) This sample demonstrate the how to enforce the +** constraints on an XML value. There are some statement +** in the samples which are expected to fail because of +** constraint violation so The sql error SQL803N and +** SQL20305N are expected. +** +** 2) Primary key, unique constraint, or unique index are not supported +** for XML column in the Database Partitioning Feature available with +** DB2 Enterprise Server Edition for Linux, UNIX, and Windows. +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLEndTran -- End Transactions of a Connection +** SQLExecDirect -- Execute a Statement Directly +** SQLFreeHandle -- Free Handle Resources +** SQLSetConnectAttr -- Set Connection Attributes +** +** OUTPUT FILE: xmlconst.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + + +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ +#include + +#define ARRAY_SIZE 700 + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handles */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO CREATE UNIQUE INDEX \n"); + + /* initialize the application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + + /* create index on XML columns */ + TbindexUniqueConstraint(hdbc); + TbindexVarcharConstraint(hdbc); + TbindexVarcharConstraint1(hdbc); + + /* terminate the application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; + +} /* main */ + +int TbindexUniqueConstraint(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + char stmt1[ARRAY_SIZE]; + SQLCHAR *stmt = (SQLCHAR *) "CREATE TABLE COMPANY(ID int," + " DOCNAME VARCHAR(20)," + " DOC XML)"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO PERFORM UNIQUE INDEX OPERATION :\n"); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* create unique index */ + printf("create unique index \n"); + + strcpy(stmt1, " CREATE UNIQUE INDEX empindex on company(doc) GENERATE \ + KEY USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("insert row1 into table \n"); + + strcpy(stmt1, " INSERT INTO company values (1, 'doc1', xmlparse \ + (document 'Laura \ + Brown \ + Finance'))"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("insert row2 into table \n"); + printf("Unique violation error because of id=\"31201\" \n"); + + strcpy(stmt1, "INSERT INTO company values (1, 'doc1', xmlparse \ + (document 'Laura \ + Brown\ + Finance '))"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* create unique index */ + printf("create unique index \n"); + + strcpy(stmt1, "CREATE UNIQUE INDEX empindex on company(doc)\ + GENERATE KEY USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("insert row1 into table \n"); + printf("No index entry is inserted because \"ABCDE\" cannot be cast"); + printf("to the DOUBLE data type. \n"); + + strcpy(stmt1, " INSERT INTO company values (1, 'doc1', xmlparse \ + (document 'Laura \ + Brown \ + Finance'))"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("insert row2 into table \n"); + printf("The insert succeeds because no index entry is inserted since\n"); + printf("\"ABCDE\" cannot be cast to the DOUBLE data type.\n"); + + strcpy(stmt1, "INSERT INTO company values (1, 'doc1', xmlparse \ + (document ' \ + Laura \ + BrownFinancei \ + '))"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\n Rolling back the transaction...\n"); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +int TbindexVarcharConstraint(SQLHANDLE hdbc) +{ + + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + char stmt1[ARRAY_SIZE]; + SQLCHAR *stmt = (SQLCHAR *) "CREATE TABLE COMPANY(ID int," + " DOCNAME VARCHAR(20)," + " DOC XML)"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO PERFORM UNIQUE INDEX :\n"); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* create unique index */ + printf("create unique index \n"); + + strcpy(stmt1, "CREATE UNIQUE INDEX empindex on company(doc)\ + GENERATE KEY USING XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(4)"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("insert row1 into table \n"); + printf("Insert statement succeeds because the length of \"312\" < 4.\n"); + + strcpy(stmt1, "INSERT INTO company values (1, 'doc1', xmlparse \ + (document 'Laura \ + Brown \ + Finance '))"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("insert row2 into table \n"); + printf("Insert statement fails because the length of \"31202\" > 4.\n"); + strcpy(stmt1, " INSERT INTO company values (1, 'doc1', xmlparse \ + (document 'Laura \ + Brown \ + Finance '))"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\n Rolling back the transaction...\n"); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +int TbindexVarcharConstraint1(SQLHANDLE hdbc) +{ + + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + char stmt1[ARRAY_SIZE]; + SQLCHAR *stmt = (SQLCHAR *) "CREATE TABLE COMPANY(ID int," + " DOCNAME VARCHAR(20)," + " DOC XML)"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO PERFORM UNIQUE INDEX :\n"); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("insert row1 into table \n"); + strcpy(stmt1, "INSERT INTO company values (1, 'doc1', xmlparse \ + (document 'Laura \ + Brown \ + Finance '))"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("insert row2 into table \n"); + strcpy(stmt1, " INSERT INTO company values (1, 'doc1', xmlparse \ + (document 'Laura \ + Brown \ + Finance '))"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + + /* create unique index */ + printf("create index with Varchar constraint fails "); + printf("because the length of \"31202\" > 4\n"); + + strcpy(stmt1, "CREATE UNIQUE INDEX empindex on company(doc)\ + GENERATE KEY USING XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(4)"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *) stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\n Rolling back the transaction...\n"); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} diff --git a/xml/cli/xmlindex.c b/xml/cli/xmlindex.c new file mode 100644 index 0000000..f897fd1 --- /dev/null +++ b/xml/cli/xmlindex.c @@ -0,0 +1,957 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlindex.c +** +** SAMPLE: How to create an index on xml column +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLEndTran -- End Transactions of a Connection +** SQLExecDirect -- Execute a Statement Directly +** SQLFreeHandle -- Free Handle Resources +** SQLSetConnectAttr -- Set Connection Attributes +** +** OUTPUT FILE: xmlindex.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ +#include + +#define ARRAY_SIZE 700 + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handles */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO CREATE INDEX ON XML COLUMNS.\n"); + + /* initialize the application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + + /* create index on XML column */ + printf("create index on XML column\n"); + rc = CreateTableWithData(hdbc); + rc = CreateIndexonAttribute(hdbc); + rc = CreateIndexwithSelfForwardaxis(hdbc); + rc = CreateIndexonTextNode(hdbc); + rc = CreateIndexwith2Paths(hdbc); + rc = CreateIndexWithNamespace(hdbc); + rc = CreateIndexWithDifferentTypes(hdbc); + rc = CreateIndexToUseAnding(hdbc); + rc = CreateIndexToUseAndingOrOring(hdbc); + rc = CreateIndexWithDateType(hdbc); + rc = CreateIndexWithCommentNode(hdbc); + rc = droptable(hdbc); + + /* terminate the application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; +} + +int CreateTableWithData(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + char stmt1[ARRAY_SIZE]; + char stmt2[ARRAY_SIZE]; + char stmt3[ARRAY_SIZE]; + + /* create a table called company */ + SQLCHAR *stmt = (SQLCHAR *) "CREATE TABLE COMPANY(ID int, " + " DOCNAME VARCHAR(20), " + " DOC XML)"; + /* drop the index */ + SQLCHAR *drop_index = (SQLCHAR *) "DROP INDEX \"EMPINDEX\""; + + /* insert row1 into table */ + SQLCHAR *row1 = (SQLCHAR *) "INSERT INTO COMPANY VALUES(1, 'doc1', " + " xmlparse (document ' " + " Laura " + " Brown" + " Finance " + "'))"; + + /* insert row2 into table */ + SQLCHAR *row2 = (SQLCHAR *)"INSERT INTO COMPANY VALUES(2, 'doc', xmlparse " + " ( document ' " + " Chris " + " MurphyMarketing Nicole" + "MurphySales " + "'))"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO PERFORM INDEX IN DIFFERENT WAYS :\n"); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* execute create table statement directly */ + printf("create the table called company\n"); + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("Insert row1 into the table\n"); + + cliRC = SQLExecDirect(hstmt, row1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + + printf("Insert row2 into table \n"); + cliRC = SQLExecDirect(hstmt, row2, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + strcpy(stmt1, "COMMIT"); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + printf("\n Rolling back the transaction...\n"); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +int CreateIndexonAttribute(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + char stmt1[1000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex1 on company(doc)" + "GENERATE KEY USING XMLPATTERN '/company/emp/@*' " + "AS SQL VARCHAR(15)"; + + SQLCHAR *xquerystmt = (SQLCHAR *)"XQUERY for $i in db2-fn:xmlcolumn" + "('COMPANY.DOC')/company/emp[@id='42366'] " + "return $i/name"; + + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO PERFORM INDEX ON ATTRIBUTE.\n"); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* example query using above index */ + cliRC = SQLExecDirect(hstmt, xquerystmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("-------------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + printf("\n Rolling back the transaction...\n"); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +int droptable(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + + char stmt1[1000]; + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* drop table */ + strcpy(stmt1, "DROP table \"COMPANY\""); + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT); + DBC_HANDLE_CHECK(hdbc, cliRC); + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +int CreateIndexwithSelfForwardaxis(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + char stmt1[1000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex2 on company(doc)" + " GENERATE KEY USING XMLPATTERN '//@salary' " + "AS SQL DOUBLE"; + + SQLCHAR *xquerystmt = (SQLCHAR *)"XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + "/company/emp[@salary > 35000] return {$i/@salary} "; + + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO PERFORM INDEX WITH SELF OR DESCENDENT FORWARD AXIS:\n"); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* example query using above index */ + cliRC = SQLExecDirect(hstmt, (SQLCHAR * )xquerystmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("----------------------------------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} + +int CreateIndexonTextNode(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + char stmt1[1000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex3 on company(doc)" + "GENERATE KEY USING XMLPATTERN '/company/emp/dept/text()' " + "AS SQL VARCHAR(30)"; + + SQLCHAR *xquerystmt = (SQLCHAR *)"XQUERY for $i in db2-fn:xmlcolumn" + "('COMPANY.DOC')/company/emp[dept/text()=" + "'Finance' or dept/text()='Marketing'] return $i/name"; + + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO PERFORM INDEX ON TEXT NODE\n"); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* example query using above index */ + cliRC = SQLExecDirect(hstmt, xquerystmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("----------------------------------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} + +int CreateIndexwith2Paths(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLHANDLE hstmt1; /* statement handle */ + SQLVARCHAR xmldata[3000]; + char stmt1[1000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex4 on company(doc)" + "GENERATE KEY USING XMLPATTERN '//@id' " + "AS SQL VARCHAR(25)"; + + SQLCHAR *xquerystmt = (SQLCHAR *)"XQUERY for $i in db2-fn:xmlcolumn" + "('COMPANY.DOC')/company/emp[@id='31201'] " + "return $i/name"; + SQLCHAR *xquerystmt1 = (SQLCHAR *)"XQUERY for $i in db2-fn:xmlcolumn" + "('COMPANY.DOC')/company/emp/dept[@id='K55']" + " return $i/name "; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO PERFORM INDEX WHEN 2 PATHS ARE QUALIFIED BY XMLPATTERN.\n"); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt1); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* example query using above index */ + cliRC = SQLExecDirect(hstmt, xquerystmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("----------------------------------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + cliRC = SQLExecDirect(hstmt1, xquerystmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt1, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("----------------------------------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + } + + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + return rc; + +} + +int CreateIndexWithNamespace(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + char stmt1[1000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex5 on company(doc)" + "GENERATE KEY USING XMLPATTERN 'declare default " + "element namespace \"http://www.mycompany.com/\";" + "declare namespace m=\"http://www.mycompanyname.com/\";" + " /company/emp/@m:id' AS SQL VARCHAR(30)"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO CREATE INDEX WITH NAMESPACE.\n"); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} + +int CreateIndexWithDifferentTypes(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex6 on company(doc)" + "GENERATE KEY USING XMLPATTERN '/companyt/emp/@id'" + " AS SQL VARCHAR(10)"; + + SQLCHAR *stmt1 = (SQLCHAR *)"CREATE INDEX empindex7 on company(doc)" + "GENERATE KEY USING XMLPATTERN '/companyt/emp/@id'" + " AS SQL DOUBLE"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO CREATE INDEX WITH DIFFERENT DATA TYPES.\n"); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + cliRC = SQLExecDirect(hstmt, stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +int CreateIndexToUseAnding(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + char stmt1[1000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex8 on company(doc)" + " GENERATE KEY USING XMLPATTERN '/company/emp/" + "name/last' AS SQL VARCHAR(100)"; + SQLCHAR *stmt2 = (SQLCHAR *)"CREATE INDEX deptindex on company(doc)" + " GENERATE KEY USING XMLPATTERN '/company/emp/" + "dept/text()' AS SQL VARCHAR(30) "; + + SQLCHAR *xquerystmt = (SQLCHAR *)"XQUERY for $i in db2-fn:xmlcolumn" + "('COMPANY.DOC')/company/emp[name/last='Murphy'" + " and dept/text()='Sales'] return $i/name"; + + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLFreeHandle\n"); + printf(" CREATE INDEX TO USE JOINS.\n"); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + cliRC = SQLExecDirect(hstmt, stmt2, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* example query using above index */ + cliRC = SQLExecDirect(hstmt, xquerystmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("----------------------------------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} + +int CreateIndexToUseAndingOrOring(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + char stmt1[1000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex9 on company(doc)" + "GENERATE KEY USING XMLPATTERN '/company/emp/" + "@salary' AS SQL DOUBLE"; + + + SQLCHAR *stmt2 = (SQLCHAR *)"CREATE INDEX empindex10 on company(doc)" + " GENERATE KEY USING XMLPATTERN '/company/emp/dept'" + " AS SQL VARCHAR(25) "; + + SQLCHAR *stmt3 = (SQLCHAR *)"CREATE INDEX empindex11 on company(doc)" + "GENERATE KEY USING XMLPATTERN '/company/emp/name/" + "last' AS SQL VARCHAR(25) "; + + SQLCHAR *xquerystmt = (SQLCHAR *)"XQUERY for $i in db2-fn:xmlcolumn" + "('COMPANY.DOC')/company/emp[@salary > 50000" + " and dept = 'Finance'] /name [last = 'Brown'] " + "return $i/last"; + + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO CREATE INDEX TO USE ANDING OR ORING.\n"); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + cliRC = SQLExecDirect(hstmt, stmt2, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + + cliRC = SQLExecDirect(hstmt, stmt3, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* example query using above index */ + cliRC = SQLExecDirect(hstmt, xquerystmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("-----------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} + +int CreateIndexWithDateType(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + char stmt1[1000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex12 on company(doc)" + "GENERATE KEY USING XMLPATTERN '/company/emp/@DOB'" + " as SQL DATE"; + + SQLCHAR *xquerystmt = (SQLCHAR *)"XQUERY for $i in db2-fn:xmlcolumn" + "('COMPANY.DOC')/company/emp[@DOB < '11-11-78']" + " return $i/name"; + + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO CREATE INDEX WITH DATE DATA TYPE.\n"); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* example query using above index */ + cliRC = SQLExecDirect(hstmt, xquerystmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("---------------------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} + +int CreateIndexWithCommentNode(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + char stmt1[1000]; + + SQLCHAR *stmt = (SQLCHAR *)"CREATE INDEX empindex13 on company(doc)" + "GENERATE KEY USING XMLPATTERN '/company//comment()'" + " AS SQL VARCHAR HASHED"; + + SQLCHAR *xquerystmt = (SQLCHAR *)"XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + "/company/emp[comment()=' good '] return $i/name"; + + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO CREATE INDEX ON COMMENT NODE.\n"); + + printf("\n Transactions enabled.\n"); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* create unique index */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* example query using above index */ + cliRC = SQLExecDirect(hstmt, xquerystmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("-----------------------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} diff --git a/xml/cli/xmlinsert.c b/xml/cli/xmlinsert.c new file mode 100644 index 0000000..02309d4 --- /dev/null +++ b/xml/cli/xmlinsert.c @@ -0,0 +1,798 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlinsert.c +** +** SAMPLE: This sample demonstrates different ways of inserting a XML document +** into a column of XML data type. +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLPrepare -- Prepare a Statement +** SQLExecute -- Execute a Statement +** SQLFreeHandle -- Free Handle Resources +** +** OUTPUT FILE: xmlinsert.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilcli.h" /* header file for CLI sample code */ + +/* Declare Global Variables to be used across functions */ +int length; +int rc = 0; +char blobdata[500]; +char clobdata[500]; +char xmldata[500]; +char invalidxmldata[500]; +char invaliddata[500]; + +int CreateTables(SQLHANDLE); +int InsertXMLtype(SQLHANDLE); +int InsertBLOBtypeExplictParsing(SQLHANDLE); +int InsertBLOBtypeImplicitParsing(SQLHANDLE); +int InsertInvalidXMLdoc(SQLHANDLE); +int InsertfromXMLcolumn(SQLHANDLE); +int InsertfromVARCHARcolumn(SQLHANDLE); +int InsertfromVARCHARcolumnImplicitParsing(SQLHANDLE); +int InsertusingXMLCAST(SQLHANDLE); +int InsertDocUsingXMLfunctions(SQLHANDLE); +int InsertInvalidDocUsingXMLVALIDATE(SQLHANDLE); +int InsertusingXMLVALIDATE(SQLHANDLE); +int DropTables(SQLHANDLE); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + SQLHANDLE hstmt; + SQLCHAR stmt[500] = {0}; + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + strcpy(xmldata, "" + " Plastic Casing " + "
Blue Color
" + " 2.89 " + " 0.23 "); + + /* invalid xml data will not have the closing tags for */ + /* description and product */ + strcpy(invalidxmldata, xmldata); + + strcat(xmldata, "
"); + strcpy(blobdata, xmldata); + strcpy(clobdata, xmldata); + strcpy(invaliddata, " Not as per schema "); + + length = strlen(xmldata); + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF); + if (rc != 0) + { + return rc; + } + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* Call function to create Tables */ + rc = CreateTables(hdbc); + + /* Insert using variable of type XML */ + rc = InsertXMLtype(hdbc); + + /* Insert using variable of type BLOB with Explicit Parsing */ + rc = InsertBLOBtypeExplictParsing(hdbc); + + /* Insert using variable of type BLOB with Implicit Parsing */ + rc = InsertBLOBtypeImplicitParsing(hdbc); + + /* Insert using an INVALID XML document structure */ + rc = InsertInvalidXMLdoc(hdbc); + + /* Insert when source is from another column of type XML */ + rc = InsertfromXMLcolumn(hdbc); + + /* Insert when source is from another column of type VARCHAR */ + rc = InsertfromVARCHARcolumn(hdbc); + + /* Insert when source is a XML document from a column */ + /* of type VARCHAR, Using Implicit Parsing */ + rc = InsertfromVARCHARcolumnImplicitParsing(hdbc); + + /* Insert when source is a simple type, using XMLCAST */ + rc = InsertusingXMLCAST(hdbc); + + /* Insert document created using XML Functions */ + rc = InsertDocUsingXMLfunctions(hdbc); + + /* Inserting INVALID XML document using XMLVALIDATE */ + rc = InsertInvalidDocUsingXMLVALIDATE(hdbc); + + /* Insert using XMLVALIDATE */ + rc = InsertusingXMLVALIDATE(hdbc); + + /* Call function to Drop tables */ + rc = DropTables(hdbc); + + /* Rollback transaction */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* free the statement handles */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* terminate the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; +} /* end main */ + +/* Function to Create tables */ +int CreateTables(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + strcpy(stmt, "CREATE TABLE vartable (id INT," + " desc VARCHAR(200), comment VARCHAR(25))"); + + /* directly execute the statement */ + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(11111, \' Neeraj " + " Gaurav \', " + "\'Final Year\')"); + + /* Execute the statement */ + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(22222, '" + " Plastic Casing " + "
Green Color
" + " 7.89 " + " 6.23 " + "
', " + "'Last Product')"); + + /* Execute the statement */ + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(33333, \' Neeraj " + " Gaurav \', " + "\'Final Year\')"); + + /* Execute the statement */ + rc = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* CreateTables */ + +/* InsertXMLtype */ +int InsertXMLtype(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT on */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* inserting when source is from host variable of type XML */ + printf("\n Performing Insert when source is a variable of Type XML \n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "VALUES (8956, ?)"); + printf(" Statement Executing : %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind Paramenter to the Insert statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_BINARY, + SQL_XML, + length, + 0, + &xmldata, + length, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertXMLtype */ + +/* InsertBLOBtypeExplictParsing */ +int InsertBLOBtypeExplictParsing(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Performing Insert with BLOB type using Explicit Parsing\n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "VALUES (323, XMLPARSE(DOCUMENT CAST(? as BLOB(1K))))"); + printf(" Statement Executing: %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind Paramenter to the Insert statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_BINARY, + SQL_BLOB, + length, + 0, + &blobdata, + length, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertBLOBtypeExplictParsing */ + +/* InsertBLOBtypeImplicitParsing */ +int InsertBLOBtypeImplicitParsing(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Performing Insert with BLOB type using Implicit Parsing\n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "VALUES(231, CAST( ? as BLOB(1K)))"); + printf(" Statement executing : %s\n", stmt); + + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind Paramenter to the Insert statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_BINARY, + SQL_BLOB, + length, + 0, + &blobdata, + length, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertBLOBtypeImplicitParsing */ + +/* InsertInvalidXMLdoc */ +int InsertInvalidXMLdoc(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Performing Insert using an INVALID XML document\n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "VALUES(674, ?)"); + printf(" Statement executing : %s\n", stmt); + printf(" This Insert should fail as the XML document is INVALID\n"); + + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind Paramenter to the Insert statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_CHAR, + 500, + 0, + &invalidxmldata, + 500, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + EX_STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertInvalidXMLdoc */ + +/* InsertfromXMLcolumn */ +int InsertfromXMLcolumn(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[700]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* validate an XML document when target is from another column of type XML */ + /* add a number to POID to avoid unique constraint conflict */ + printf("\n Perform Insert by selecting XML doc from another column\n"); + strcpy(stmt, "INSERT INTO purchaseorder(poid, porder) " + "(SELECT poid+5, XMLVALIDATE(porder ACCORDING TO XMLSCHEMA ID PRODUCT) " + "FROM purchaseorder WHERE poid = 674)"); + printf(" Statement Executing : %s\n", stmt); + + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertfromXMLcolumn */ + +/* InsertfromVARCHARcolumn */ +int InsertfromVARCHARcolumn(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Insert when source is a XML document from a column of type VARCHAR\n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "(SELECT id, XMLPARSE( DOCUMENT desc) FROM vartable WHERE " + "id = 11111)"); + printf(" Statement Executing : %s\n", stmt); + + /* execute the statement */ + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertfromVARCHARcolumn */ + +/* InsertfromVARCHARcolumnImplicitParsing */ +int InsertfromVARCHARcolumnImplicitParsing(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* insert when source is a XML document from a column */ + /* of type VARCHAR, Using Implicit Parsing */ + printf(" Insert when source is a XML document from a column of type VARCHAR, Using Implicit Parsing\n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "(SELECT id, desc FROM vartable WHERE " + "id = 22222)"); + printf(" Statement Executing : %s\n", stmt); + + /* execute the statement */ + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertfromVARCHARcolumnImplicitParsing */ + +/* InsertusingXMLCAST */ +int InsertusingXMLCAST(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Performing Insert using a simple type\n"); + printf(" Using XMLCAST to typecast to XML\n"); + + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "VALUES(125, XMLCAST(? as XML))"); + printf("\n Insert statement executing : %s\n", stmt); + + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind Paramenter to the Insert statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_CHAR, + 500, + 0, + &xmldata, + 500, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertusingXMLCAST */ + +/* InsertDocUsingXMLfunctions */ +int InsertDocUsingXMLfunctions(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* use XML Functions to create a XML document */ + /* insert this document into the table */ + printf(" Use XML Functions to create a XML document\n"); + printf(" Insert this document into the table \n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder)" + "(SELECT id, XMLDOCUMENT( XMLELEMENT( NAME \"PORDER\"," + " XMLELEMENT( NAME \"ID\", XMLATTRIBUTES( v.id as PRODID))," + " XMLELEMENT( NAME \"DESC\", v.comment)))" + " FROM vartable AS v WHERE ID = 33333)"); + + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertDocUsingXMLfunctions */ + +/* InsertInvalidDocUsingXMLVALIDATE */ +int InsertInvalidDocUsingXMLVALIDATE(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Perform Insert using XMLVALIDATE with INVALID xml document\n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "VALUES( 320, XMLVALIDATE(? ACCORDING TO XMLSCHEMA ID PRODUCT))"); + printf(" Statement Executing : %s\n", stmt); + + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind Paramenter to the Insert statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_BINARY, + SQL_CHAR, + 500, + 0, + &invaliddata, + 500, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + EX_STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertInvalidDocUsingXMLVALIDATE */ + +/* InsertusingXMLVALIDATE */ +int InsertusingXMLVALIDATE(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Perform Insert using XMLVALIDATE\n"); + strcpy(stmt, "INSERT INTO purchaseorder (poid, porder) " + "VALUES( 320, XMLVALIDATE(? ACCORDING TO XMLSCHEMA ID PRODUCT))"); + printf(" Statement Executing : %s\n", stmt); + + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind Paramenter to the Insert statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_BINARY, + SQL_CHAR, + 500, + 0, + &xmldata, + 500, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* InsertusingXMLVALIDATE */ + +/* Function to Drop tables */ +int DropTables(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + strcpy(stmt, "DROP TABLE VARTABLE"); + + /* execute the statement */ + rc = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* DropTables */ diff --git a/xml/cli/xmlread.c b/xml/cli/xmlread.c new file mode 100644 index 0000000..14e1b27 --- /dev/null +++ b/xml/cli/xmlread.c @@ -0,0 +1,246 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlread.c +** +** SAMPLE: This sample demonstrates to read XML data from a table. +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLExecute -- Execute a Statement +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLPrepare -- Prepare a Statement +** +** EXTERNAL DEPENDENCIES: +** Ensure that the stored procedures called from this program have +** been built and cataloged with the database. +** +** OUTPUT FILE: xmlread.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilcli.h" /* header file for CLI sample code */ + +int ReadPurchaseOrder(SQLHANDLE); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + + printf("PERFORMING SELECT FROM RELATIONAL TABLES\n"); + rc = ReadPurchaseOrder(hdbc); + + /* rollback any changes to the database made by this sample */ + printf("\nRoll back the transaction.\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* terminate the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; +} /* end main */ + + +/* Read data*/ +int ReadPurchaseOrder(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLCHAR stmt[500] = {0}; + SQLINTEGER CID; /* variable to be bound to the CID column */ + SQLINTEGER PID; /* variable to be bound to the POID column */ + + struct + { + SQLINTEGER ind; + SQLVARCHAR val[11]; + } + OrderDate; /* variable to be bound to the OrderDate column */ + + struct + { + SQLINTEGER ind; + SQLVARCHAR val[30]; + } + Status; /* variable to be bound to the Status column */ + + struct + { + SQLINTEGER ind; + SQLVARCHAR val[200]; + } + Comment; /* Variable to be bound to the Comment column */ + + struct + { + SQLINTEGER ind; + SQLVARCHAR val[2000]; + } + POrder; /* Variable to be bound to the Porder column */ + + + + printf("Execute the Select statement\n"); + + strcpy((char *)stmt, "SELECT POID, CUSTID, STATUS, PORDER, " + "COMMENTS, ORDERDATE FROM PURCHASEORDER " + "ORDER BY CUSTID,POID"); + printf("%s\n", stmt); + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column POID to variable PID*/ + cliRC = SQLBindCol(hstmt, 1, SQL_C_LONG, &PID, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column CID to variable CID */ + cliRC = SQLBindCol(hstmt, 2, SQL_C_LONG, &CID, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column STATUS to variable Status*/ + cliRC = SQLBindCol(hstmt, 3, SQL_C_CHAR, &Status.val, 30, &Status.ind); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column PORDER to variable POrder*/ + cliRC = SQLBindCol(hstmt, 4, SQL_C_CHAR, &POrder.val, 3000, &POrder.ind); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column COMMENT to variable Comment*/ + cliRC = SQLBindCol(hstmt, 5, SQL_C_CHAR, &Comment.val, 200, &Comment.ind); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column ORDERDATE to variable OrderDate*/ + cliRC = SQLBindCol(hstmt, 6, SQL_C_CHAR, &OrderDate.val, 11, &OrderDate.ind); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + + /* fetch result returned from Select statement*/ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("\n***** NEXT ROW ***** \n\n"); + printf(" CUSTOMER ID : %d\n", CID); + printf(" PURCHASE ORDER NO : %d\n", PID); + if (Status.ind >= 0) + { + printf(" STATUS : %s\n", Status.val); + } + else + { + printf(" STATUS : NULL\n"); + } + if (OrderDate.ind >=0) + { + printf(" ORDER DATE : %s\n", OrderDate.val); + } + else + { + printf(" ORDER DATE : NULL\n"); + } + if (Comment.ind >=0) + { + printf(" COMMENT : %s\n", Comment.val); + } + else + { + printf(" COMMENT : NULL\n"); + } + if (POrder.ind >=0) + { + printf(" PURCHASE ORDER : %s\n", POrder.val); + } + else + { + printf(" PURCHASE ORDER : NULL\n"); + } + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handles */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* end ReadPurchaseOrder */ diff --git a/xml/cli/xmltotable.c b/xml/cli/xmltotable.c new file mode 100644 index 0000000..aa42a3c --- /dev/null +++ b/xml/cli/xmltotable.c @@ -0,0 +1,461 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmltotable.c +** +** SAMPLE USAGE SCENARIO:Purchase order XML document contains detailed +** information about all the orders. It will also have the detail of the +** customer with each order. +** +** PROBLEM: The document has some redundant information as customer info +** and product info is repeated in each order for example +** Customer info is repeated for each order from same customer. +** Product info will be repeated for each order of same product from different customers. +** +** SOLUTION: The sample database has tables with both relational and XML data to remove +** this redundant information. These relational tables will be used to store +** the customer info and product info in the relational table having XML data +** and id value. Purchase order will be stored in another table and it will +** reference the customerId and productId to refer the customer and product +** info respectively. +** +** To achieve the above goal this sample will shred the data for purchase order XML +** document and insert it into the tables. +** +** The sample will follow the following steps +** +** 1. Get the relevant data in XML format from the purchase order XML document (use XMLQuery) +** 2. Shred the XML doc into the relational table. (Use XMLTable) +** 3. Select the relevant data from the table and insert into the target relational table. +** +** EXTERNAL DEPENDENCIES: +** For successful precompilation, the sample database must exist +** (see DB2's db2sampl command). +** XML Document purchaseorder.xml must exist in the same directory as of this sample +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLExecDirect -- Execute a Statement Directly +** SQLFreeHandle -- Free Handle Resources +** SQLPrepare -- Prepare Statement +** SQLBindCol -- Bind Out a Column to a Variable +** SQLFetch -- Fetch a Column +** SQLBindParameter -- Bind in a Parameter +** +** XML FUNCTIONS USED: +** XMLCOLUMN +** XMLELEMENT +** XMLTABLE +** XMLDOCUMENT +** XMLATTRIBTES +** XMLCONCAT +** XQUERY +** +** OUTPUT FILE: xmltotable.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ + +int shred_PO(SQLHANDLE hdbc); +int displaycontent(SQLHANDLE hdbc); +int cleanUp(SQLHANDLE hdbc); + +int main(int argc, char *argv[]) +{ + int rc = 0; + SQLRETURN cliRC = SQL_SUCCESS; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE WILL SHOW HOW TO STORE THE DATA IN RELATIONAL TABLE FROM XML DOCUMENT"); + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + + /* call the shred_PO function to store the data in relational table */ + shred_PO(hdbc); + + /* Display the contents */ + displaycontent(hdbc); + + /* Clean up the data inserted */ + cleanUp(hdbc); + + /* terminate the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + return rc; +}/*main*/ + +int displaycontent(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; + SQLCHAR *stmt; + sqlint32 cid; + SQLVARCHAR xmldata[1000]; + + /* allocate a statement handles */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + stmt = (SQLCHAR *) "SELECT cid, info FROM CUSTOMER ORDER BY cid"; + + printf("\n%s\n",stmt); + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + cliRC = SQLBindCol(hstmt, 1, SQL_C_LONG, &cid, 4, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + cliRC = SQLBindCol(hstmt, 2, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("CID = %d \n INFO= %s \n\n",cid, xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* allocate a statement handles */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + stmt = (SQLCHAR *) "SELECT poid,porder FROM purchaseorder ORDER BY poid"; + printf("\n%s\n",stmt); + + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + cliRC = SQLBindCol(hstmt, 1, SQL_C_LONG, &cid, 4, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + cliRC = SQLBindCol(hstmt, 2, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("POID = %d \n PORDER= %s \n\n",cid, xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + + /* Free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + +} /* displaycontent */ + +int cleanUp(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; + SQLCHAR *stmt; + + /* allocate a statement handles */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + stmt = (SQLCHAR *) "DELETE FROM CUSTOMER WHERE CID IN (10,11)"; + printf("\n%s\n",stmt); + + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + stmt = (SQLCHAR *) "DELETE FROM PURCHASEORDER WHERE POID IN (110,111)"; + printf("\n%s\n",stmt); + + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); +} /* cleanUp */ + +int shred_PO(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + int num_record_customer=0; + int num_record_po=0; + SQLCHAR *data=(SQLCHAR *) "purchaseorder.xml"; /* file name with XML data */ + SQLHANDLE hstmt1; /* statement handle */ + SQLHANDLE hstmt2; /* statement handle */ + SQLVARCHAR xmldata[3000]; + SQLCHAR cursorName[20]; + SQLUINTEGER fileOption = SQL_FILE_READ; + SQLSMALLINT cursorLen; + SQLCHAR *stmt1; + SQLCHAR *stmt2; + SQLCHAR *stmt; + FILE *testfile; + /* allocate a statement handles */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt1); + DBC_HANDLE_CHECK(hdbc, cliRC); + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt2); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* execute the create statement to create PO table */ + stmt= (SQLCHAR *) "CREATE TABLE PO(id INT GENERATED ALWAYS AS IDENTITY,purchaseorder XML)"; + cliRC = SQLExecDirect(hstmt1, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* insert the XML document in PO table */ + stmt=(SQLCHAR *) "insert into PO(purchaseorder) values(cast(? as XML))"; + cliRC = SQLPrepare(hstmt1, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* bind the file "purchaseorder.xml" to the XML parameter */ + /* C data type should be one of SQL_BLOB, SQL_CLOB or SQL_DBCLOB while binding file to a parameter */ + testfile = fopen("purchaseorder.xml" , "r" ); + if ( testfile == NULL ) + { + printf("fopen() error.\n"); + printf("Error accessing file: purchaseorder.xml \n"); + exit(0); + } + + cliRC = SQLBindFileToParam(hstmt1, + 1, + SQL_BLOB, + data, + NULL, + &fileOption, + 17, + NULL); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + cliRC=SQLExecute(hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* run the XQuery to find out the purchaseorder with status shipped */ + stmt= (SQLCHAR *) "db2-fn:xmlcolumn(" + "'PO.PURCHASEORDER')/PurchaseOrders/PurchaseOrder[@Status='shipped']"; + printf(" Run the following XQuery to find out all the purchaseorder with status shipped...\n"); + printf("db2-fn:xmlcolumn('"); + printf(" PO.PURCHASEORDER')/PurchaseOrders/PurchaseOrder[@Status='shipped']\n\n"); + + /* set the statement handle attribute SQL_ATTR_XQUERY_STATEMENT to + indicate that statement is XQuery statement. This is equivalent to prefixing the Xquery + expression with XQUERY keyword */ + cliRC=SQLSetStmtAttr(hstmt1, SQL_ATTR_XQUERY_STATEMENT, (SQLPOINTER) SQL_TRUE, 0); + + /* directly execute the XQUERY statement */ + cliRC = SQLExecDirect(hstmt1, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* reset the statement handle attribute SQL_ATTR_XQUERY_STATEMENT to false + so that statement handle can be used to run subsequent SQL statements */ + cliRC=SQLSetStmtAttr(hstmt1, SQL_ATTR_XQUERY_STATEMENT, (SQLPOINTER) SQL_FALSE, 0); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* bind the first column to a variable of type SQLVARCHAR + XML column can be bound to any of the following C data type + SQL_C_CHAR, SQL_C_WCHAR, SQL_C_DBCHAR, SQL_C_BINARY. Binding the data + to SQL_C_CHAR, SQL_C_WCHAR will convert the XML value to the application + character codepage. This may result in a loss of data if any characters in + the source data cannot be represented. SQL_C_BINARY will be recommended in + such cases to avoid any codepage issues */ + cliRC= SQLBindCol(hstmt1,1,SQL_C_CHAR,&xmldata,1000,NULL); + + /* fetch the first row */ + cliRC = SQLFetch(hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + + /* insert into the customer table */ + /* XMLTable function will be used to create a table from XML document */ + /* select the data from the table and insert it into the customer table */ + stmt1 = (SQLCHAR *)"INSERT INTO customer(CID,info,history)" + " SELECT T.CustID,xmldocument(" + " XMLELEMENT(NAME \"customerinfo\",XMLATTRIBUTES (T.CustID as \"Cid\")," + " XMLCONCAT(XMLELEMENT(NAME \"name\", T.Name ),T.Addr," + " XMLELEMENT(NAME \"phone\", XMLATTRIBUTES(T.Type as \"type\"), T.Phone)" + " ))), xmldocument(T.History)" + " FROM XMLTABLE( '$d/PurchaseOrder' PASSING cast(? as XML) AS \"d\"" + " COLUMNS CustID BIGINT PATH '@CustId'," + " Addr XML PATH './Address'," + " Name VARCHAR(20) PATH './name'," + " Country VARCHAR(20) PATH './Address/@country'," + " Phone VARCHAR(20) PATH './phone'," + " Type VARCHAR(20) PATH './phone/@type'," + " History XML PATH './History') as T" + " WHERE T.CustID NOT IN (SELECT CID FROM customer)"; + + + stmt2 = (SQLCHAR *) "INSERT INTO purchaseOrder(poid, orderdate, custid,status, porder, comments)" + " SELECT poid, orderdate, custid, status,xmldocument(XMLELEMENT(NAME \"PurchaseOrder\"," + " XMLATTRIBUTES(T.Poid as \"PoNum\", T.OrderDate as \"OrderDate\"," + " T.Status as \"Status\")," + "T.itemlist)), comment" + " FROM XMLTable ('$d/PurchaseOrder' PASSING cast(? as XML) as \"d\"" + " COLUMNS poid BIGINT PATH '@PoNum'," + " orderdate date PATH '@OrderDate'," + " CustID BIGINT PATH '@CustId'," + " status varchar(10) PATH '@Status'," + " itemlist XML PATH './itemlist'," + " comment varchar(1024) PATH './comments') as T"; + + + + printf("Insert into customer table using following insert statement.....\n\n"); + printf("%s", stmt1); + printf("Insert into purchaseorder using the following insert statement.....\n\n"); + printf("%s\n", stmt2); + + /* iterate for all the rows, insert the data into the relational table */ + while(cliRC != SQL_NO_DATA_FOUND) + { + /* insert into the customer table */ + /* XMLTable function will be used to create a table from XML document */ + /* select the data from the table and insert it into the customer table */ + printf("Inserting into customer table ....\n"); + + cliRC = SQLPrepare(hstmt2, stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt2, hdbc, cliRC); + + /* bind the parameter SQL type will be SQL_XML */ + cliRC = SQLBindParameter(hstmt2, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 0, + 0, + &xmldata, + 1000, + NULL); + STMT_HANDLE_CHECK(hstmt2, hdbc, cliRC); + cliRC=SQLExecute(hstmt2); + STMT_HANDLE_CHECK(hstmt2, hdbc, cliRC); + num_record_customer++; + + /* insert into he purchaseorder table */ + printf("Inserting into purchaseorder table ....\n"); + cliRC = SQLPrepare(hstmt2, stmt2, SQL_NTS); + STMT_HANDLE_CHECK(hstmt2, hdbc, cliRC); + + /* bind the XML parameter, SQL type will be SQL_XML, C type SQL_C_CHAR */ + cliRC = SQLBindParameter(hstmt2, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 0, + 0, + &xmldata, + 1000, + NULL); + STMT_HANDLE_CHECK(hstmt2, hdbc, cliRC); + cliRC=SQLExecute(hstmt2); + STMT_HANDLE_CHECK(hstmt2, hdbc, cliRC); + num_record_po++; + cliRC = SQLFetch(hstmt1); + } /* While loop */ + + /* close the cursor */ + cliRC = SQLCloseCursor(hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* drop the table PO */ + stmt=(SQLCHAR *) "DROP TABLE PO"; + cliRC = SQLExecDirect(hstmt1, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt2); + STMT_HANDLE_CHECK(hstmt2, hdbc, cliRC); + printf("\nNumber of record inserted into customer table = %d\n",num_record_customer); + printf("Number of record inserted into purchaseorder table = %d\n",num_record_po); + +}/* PO_shred */ diff --git a/xml/cli/xmludfs.c b/xml/cli/xmludfs.c new file mode 100644 index 0000000..980a4bb --- /dev/null +++ b/xml/cli/xmludfs.c @@ -0,0 +1,938 @@ +/*************************************************************************** +** (c) Copyright IBM Corp. 2008 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SAMPLE FILE NAME: xmludfs.c +** +** PURPOSE: The purpose of this sample is to show extended support of XML for +** sourced UDF and SQL bodied UDF in serial and DPF environment +** for DB2 Cobra. +** +** USAGE SCENARIO: The scenario is for a Book Store that has two types of +** customers, retail customers and corporate customers. Corporate +** customers do bulk purchases of books for their company libraries. +** The Book Store also maintains list of �registered customers� +** who are frequent buyers from the store and have registered +** themselves with the store. The store has a DBA, sales clerk and a +** manager for maintaining the database and to run queries on different +** tables to view the book sales. +** +** The store manager frequently queries various tables to get +** information such as contact numbers of different departments, +** location details, location manager details, employee details +** in order to perform various business functions like promoting +** employees, analysing sales, giving awards and bonus to employees +** based on their sales. +** +** The manager is frustrated writing the same queries every time to +** get the information and observes performance degradation as well. +** So he decides to create a user-defined function and a stored +** procedure for each of his requirements. + +** +** PREREQUISITE: NONE +** +** EXECUTION: bldapp xmludfs +** xmludfs +** +** INPUTS: NONE +** +** OUTPUTS: Successfull execution of all UDFs and stored procedures. +** +** OUTPUT FILE: xmludfs.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** CREATE TABLE +** INSERT +** DROP +** +** SQL/XML FUNCTIONS USED: +** XMLPARSE +** XMLQUERY +** XMLEXISTS +** +***************************************************************************** +** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +***************************************************************************** +** +** SAMPLE DESCRIPTION +** +***************************************************************************** +** 1. UDF Scalar function which takes an XML variable as input the parameter +** and returns XML value as output. +** +** 2. UDF Table function which takes an XML variable as input the parameter +** and returns table with XML values as output. +** +** 3. Sourced UDF which takes an XML variable as the input parameter +** and returns XML value as output. +** +** 4. SQL bodied UDF which takes an XML variable as the input parameter +** and returns a table with XML values as output. This UDF +** internally calls a stored procedure which takes an XML variable +** as the input parameter and returns an XML value as output. +************************************************************************ +** +** INCLUDE ALL HEADER FILES +** +****************************************************************************/ +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handles */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\n This sample shows how to pass XML type variables"); + printf(" as input parameters, return type or local "); + printf(" variables in SQL bodied UDFs\n\n"); + + /* initialize the application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + + rc = SetUpTables(hdbc); + rc = ScalarUDF(hdbc); + rc = TableUDF(hdbc); + rc = SourcedUDF(hdbc); + rc = InvokeSpFromUDF(hdbc); + rc = CleanUpTables(hdbc); + + + /* terminate the application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; +} + +int SetUpTables(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLCHAR *stmt = 0; + + printf("---------------------------------\n"); + printf("Setting up tables for the sample\n"); + printf("---------------------------------\n"); + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CLI FUNCTIONS\n"); + printf(" SQLSetConnectAttr\n"); + printf(" SQLAllocHandle\n"); + printf(" SQLExecDirect\n"); + printf(" SQLEndTran\n"); + printf(" SQLFreeHandle\n"); + printf("TO USE XML TYPE IN UDFs :\n"); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + stmt = (SQLCHAR *)"CREATE TABLE sales_department(dept_id CHAR(10), " + " dept_info XML)"; + printf("\n%s\n\n", stmt); + + /* execute create table statement directly */ + printf("create the table called dept\n"); + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + stmt = (SQLCHAR *)"CREATE TABLE sales_employee (emp_id INTEGER, " + "total_sales INTEGER, emp_details XML)"; + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + printf("\n%s\n\n", stmt); + + stmt = (SQLCHAR *)"CREATE TABLE performance_bonus_employees(bonus_info XML)"; + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + printf("\n%s\n\n", stmt); + + stmt = (SQLCHAR *)"INSERT INTO sales_employee VALUES (5001, 40000, XMLPARSE(document " + "'" + "Lethar Kessy" + "
" + "555 M G Road" + "Bangalore" + "Karnataka" + "India" + "411004" + "
" + "" + "9435344354" + "" + "DS02" + "7" + "40000" + "25500" + "Sr. Manager" + "regular" + "Harry " + "
'))"; + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + stmt = (SQLCHAR *) "INSERT INTO sales_employee VALUES (5002, 50000, XMLPARSE(document " + "'" + "Mathias Jessy" + "
" + "Indra Nagar Road No. 5" + "Bangalore" + "Karnataka" + "India" + "411004" + "
" + "" + "9438884354" + "" + "DS02" + "6" + "50000" + "22500" + "Manager" + "regular" + "Harry" + "
'))"; + + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + stmt = (SQLCHAR *)"INSERT INTO sales_employee VALUES (5003, 40000, XMLPARSE(document " + "'" + "Mohan Kumar" + "
" + "Vijay Nagar Road No. 5" + "Bangalore" + "Karnataka" + "India" + "411004" + "
" + "" + "9438881234" + "" + "DS02" + "5" + "40000" + "15500" + "Associate Manager" + "regular" + "Harry" + "
'))"; + + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + stmt = (SQLCHAR *) "INSERT INTO sales_department VALUES ('DS02', XMLPARSE(document " + "'" + "sales" + "" + "Harry Thomas" + "" + "9732432423" + "" + "" + "
" + "Bannerghatta" + "Bangalore" + "Karnataka" + "India" + "560012" + "
" + "" + "080-23464879" + "080-56890728" + "080-45282976" + "" + "
'))"; + + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + stmt = (SQLCHAR *) "COMMIT"; + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\n Rolling back the transaction...\n"); + + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +/*----------------------------------------------------------------------- +-- 1. UDF Scalar function which takes an XML variable as input parameter +-- and returns an XML value as output. +-------------------------------------------------------------------------*/ + +int ScalarUDF(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLCHAR *stmt = 0; + struct + { + SQLINTEGER ind; + SQLVARCHAR data[1000]; + }xmldata; + + printf("---------------------------------\n"); + printf("Create a scalar function 'getDeptContactNumbers' which "); + printf("returns a list of department phone numbers\n"); + printf("---------------------------------\n"); + + stmt = "CREATE FUNCTION getDeptContactNumbers(dept_info_p XML) " + "RETURNS XML " + "LANGUAGE SQL " + "SPECIFIC contactNumbers " + "NO EXTERNAL ACTION " + "BEGIN ATOMIC " + "RETURN XMLQuery('document {{" + "$dep/department/phone}}' " + "PASSING dept_info_p as \"dep\"); " + "END"; + printf("\n%s\n\n", stmt); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("--------------------------------------------------\n"); + printf("Call scalar UDF 'getDeptContactNumbers' to get contact"); + printf(" numbers of the department \"DS02\"\n\n"); + printf("--------------------------------------------------\n"); + + stmt = (SQLCHAR *) "SELECT getDeptContactNumbers(sales_department.dept_info) " + "FROM sales_department WHERE dept_id = 'DS02'"; + printf("\n%s\n\n", stmt); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column POID to variable PID*/ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata.data, 3000, &xmldata.ind); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch result returned from Select statement*/ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + while (cliRC != SQL_NO_DATA_FOUND) + { + if(xmldata.ind > 0) + { + printf("\n%s\n\n", xmldata.data); + } + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + printf("\n Rolling back the transaction...\n"); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +/*------------------------------------------------------------------------ +-- 2. UDF Table function which takes an XML variable as input parameter +-- and returns a table with XML values as output. +--------------------------------------------------------------------------*/ + +int TableUDF(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLCHAR *stmt = 0; + SQLINTEGER emp_id; + SQLINTEGER skill_level; + SQLINTEGER salary; + SQLVARCHAR name[50]; + struct + { + SQLINTEGER ind; + SQLVARCHAR data[1000]; + }xmldata; + + printf("---------------------------------\n"); + printf("The store opens new branches in different parts of the city. "); + printf("The book store manager wants to promote senior managers and associate "); + printf("managers and designate them to manage these new branches. He wants to "); + printf("update the skill level and salaries of all the promoted managers in the"); + printf("sales_employee table. He asks the DBA to create a table function for "); + printf("this requirement. The DBA creates the 'updatePromotedEmployeesInfo' "); + printf("table function. This function updates the skill level and salaries of"); + printf("the promoted managers in sales_employee table and returns details of "); + printf("all the managers who got promoted. \n"); + printf("---------------------------------\n"); + + stmt = "CREATE FUNCTION updatePromotedEmployeesInfo(emp_id_p INTEGER) " + "RETURNS TABLE (name VARCHAR(50), emp_id integer, skill_level integer, " + " salary double, address XML) " + "LANGUAGE SQL " + "MODIFIES SQL DATA " + "SPECIFIC func1 " + "BEGIN ATOMIC " + "UPDATE sales_employee SET emp_details = XMLQuery('transform " + " copy $emp_info := $emp " + " modify if ($emp_info/employee[skill_level = 7 and " + " designation = \"Sr. Manager\"]) " + "then " + "( " + " do replace value of $emp_info/employee/skill_level with 8, " + " do replace value of $emp_info/employee/salary with " + " $emp_info/employee/salary * 9.5 " + ") " + "else if ($emp_info/employee[skill_level = 6 and " + " designation = \"Manager\"]) " + "then " + "( " + "do replace value of $emp_info/employee/skill_level with 7, " + "do replace value of $emp_info/employee/salary with " + " $emp_info/employee/salary * 7.5 " + ") " + "else if ($emp_info/employee[skill_level = 5 and " + "designation = \"Associate Manager\"]) " + "then " + "( " + "do replace value of $emp_info/employee/skill_level with 6, " + "do replace value of $emp_info/employee/salary with " + "$emp_info/employee/salary * 5.5 " + ") " + "else () " + "return $emp_info' PASSING emp_details as \"emp\")" + "WHERE emp_id = emp_id_p;" + "RETURN SELECT X.* " + "FROM sales_employee, XMLTABLE('$e_info/employee' PASSING " + "emp_details as \"e_info\" " + " COLUMNS " + "name VARCHAR(50) PATH 'name', " + "emp_id integer PATH '@id', " + "skill_level integer path 'skill_level', " + "salary double path 'salary', " + "addr XML path 'address') AS X WHERE sales_employee.emp_id = emp_id_p; " + "END"; + + + printf("%s\n\n", stmt); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("---------------------------------------------------------\n"); + printf("Call the 'updatePromotedEmployeesInfo' table function to "); + printf("update the details of promoted employees in 'sales_employee' table "); + printf("---------------------------------------------------------\n"); + + + stmt = "SELECT A.* FROM sales_employee AS E, " + "table(updatePromotedEmployeesInfo(E.emp_id)) AS A"; + printf("%s\n\n", stmt); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column info to variable xmldata*/ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &name, 50, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column info to variable xmldata*/ + cliRC = SQLBindCol(hstmt, 2, SQL_C_LONG, &emp_id, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column info to variable xmldata*/ + cliRC = SQLBindCol(hstmt, 3, SQL_C_LONG, &skill_level, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column info to variable xmldata*/ + cliRC = SQLBindCol(hstmt, 4, SQL_C_LONG, &salary, 0, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column info to variable xmldata*/ + cliRC = SQLBindCol(hstmt, 5, SQL_C_CHAR, &xmldata.data, 2000, &xmldata.ind); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + + /* fetch result returned from Select statement*/ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("\n\n%s %d %d %d", name, emp_id, skill_level, salary); + if(xmldata.ind > 0) + { + printf("\n%s\n\n", xmldata.data); + } + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + printf("\n Rolling back the transaction...\n"); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +/*-------------------------------------------------------------------------- +-- 3. Sourced UDF which takes an XML variable as the input parameter +-- and returns an XML value as output. +--------------------------------------------------------------------------*/ + +int SourcedUDF(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLCHAR *stmt = 0; + struct + { + SQLINTEGER ind; + SQLVARCHAR data[1000]; + }xmldata; + + printf("---------------------------------\n"); + printf("The store manager would like to get a particular dept manager "); + printf("name and his contact numbers. The DBA then creates a "); + printf("'getManagerDetails' UDF to get a particular department manager "); + printf("name and manager contact details. "); + printf("---------------------------------\n"); + + stmt = (SQLCHAR *)"CREATE FUNCTION getManagerDetails(dept_info_p XML, dept_p VARCHAR(5)) " + "RETURNS XML " + "LANGUAGE SQL " + "SPECIFIC getManagerDetails " + "BEGIN ATOMIC " + "RETURN XMLQuery('$info/department[name=$dept_name]/manager' " + "PASSING dept_info_p as \"info\", dept_p as \"dept_name\"); " + "END"; + printf("%s\n\n", stmt); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("Create a sourced UDF 'getManagerInfo' based on "); + printf("'getManagerDetails' user defined function \n\n"); + + stmt = "CREATE FUNCTION getManagerInfo(XML, CHAR(10))" + "RETURNS XML " + "SOURCE getManagerDetails(XML, VARCHAR(5)) "; + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + printf("%s\n\n", stmt); + + printf("Call the sourced UDF 'getManagerInfo' to get "); + printf("'sales' department manager details"); + + stmt = "SELECT getManagerInfo(sales_department.dept_info, 'sales') " + " FROM sales_department WHERE dept_id='DS02'"; + printf("%s\n\n", stmt); + + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column POID to variable PID*/ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata.data, 3000, &xmldata.ind); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch result returned from Select statement*/ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + while (cliRC != SQL_NO_DATA_FOUND) + { + if(xmldata.ind > 0) + { + printf("\n%s\n\n", xmldata.data); + } + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + printf("\n Rolling back the transaction...\n"); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +/*----------------------------------------------------------------------- +-- 4. SQL bodied UDF which takes an XML variable as the input parameter +-- and returns a table with XML values as output. This UDF +-- calls a stored procedure which takes an XML variable +-- as the input parameter and returns an XML value as output. +------------------------------------------------------------------------*/ +int InvokeSpFromUDF(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLCHAR *stmt = 0; + struct + { + SQLINTEGER ind; + SQLVARCHAR data[1000]; + }xmldata; + + printf("---------------------------------\n"); + printf("Create a function which calculates an employee gift cheque "); + printf("amount and adds this value as a new element into the "); + printf("employee information document"); + printf("---------------------------------\n"); + + stmt = "CREATE PROCEDURE calculateGiftChequeAmount(" + " INOUT emp_info_p XML, " + "IN emp_name_p VARCHAR(20)) " + "LANGUAGE SQL " + "MODIFIES SQL DATA " + "SPECIFIC customer_award " + "BEGIN " + "DECLARE emp_bonus_info_v XML; " + "IF XMLEXISTS('$e_info/employee[name = $emp1]' " + "PASSING emp_info_p as \"e_info\"," + "emp_name_p as \"emp1\")" + "THEN " + "SET emp_bonus_info_v = XMLQuery('copy $bonus := $info " + "modify " + "do insert {" + " $bonus/employee/salary * 0.50 + 25000} " + " into $bonus/employee " + "return $bonus' PASSING emp_info_p as \"info\"); " + "END IF; " + "SET emp_info_p = emp_bonus_info_v; " + "END "; + printf("%s\n\n", stmt); + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("-----------------------------------------------------\n"); + printf("Some employees who got customer appreciation awards "); + printf("and whose total sales are greater than expected sales "); + printf("were given gift cheques by the store. The DBA creates "); + printf("'calculatePerformanceBonus' function to calculate "); + printf("employee performance bonus along with customer gift "); + printf("cheque amount and update the employee information "); + printf("in sales_employee table. "); + printf("-----------------------------------------------------\n"); + + stmt = "CREATE FUNCTION calculatePerformanceBonus(sales_info_p XML) " + "RETURNS table(info XML) " + "LANGUAGE SQL " + "SPECIFIC awardedemployees " + "MODIFIES SQL DATA " + "BEGIN ATOMIC " + "DECLARE awarded_emp_info_v XML; " + "DECLARE emp_name VARCHAR(20); " + "DECLARE min_sales_v INTEGER; " + "DECLARE avg_sales_v INTEGER; " + "SET min_sales_v = XMLCAST(XMLQuery('$info/sales_per_annum/min_sales' " + "PASSING sales_info_p as \"info\") AS INTEGER); " + "SET avg_sales_v = XMLCAST(XMLQuery('$info/sales_per_annum/avg_sales' " + "PASSING sales_info_p as \"info\") AS INTEGER); " + "FOR_LOOP: FOR EACH_ROW AS " + "SELECT XMLCAST(XMLQuery('$info/employee/name' PASSING awarded_emp_info_v " + "as \"info\") AS VARCHAR(20)) as name, " + "XMLQuery('copy $e_info := $inf " + "modify " + "do insert {$e_info/employee/salary " + "* 0.25 + 5000} " + " into $e_info/employee " + "return $e_info' PASSING emp_details as \"inf\") " + "as info " + "FROM sales_employee " + "WHERE total_sales between min_sales_v and avg_sales_v " + "DO " + "SET awarded_emp_info_v = EACH_ROW.info; " + "SET emp_name = EACH_ROW.name; " + "CALL calculateGiftChequeAmount(awarded_emp_info_v, emp_name); " + "INSERT INTO performance_bonus_employees " + "VALUES (EACH_ROW.info); " + "END FOR; " + "RETURN SELECT * FROM performance_bonus_employees; " + "END " ; + + printf("%s\n\n", stmt); + + /* execute create table statement directly */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("Call the table function 'calculatePerformanceBonus' "); + printf("to get the information of all the employees who got gift "); + printf("cheques and performance bonus."); + + stmt = "SELECT * FROM table(calculatePerformanceBonus(XMLPARSE(document " + "' " + "80000 " + "70000 " + "35000 " + "')))"; + printf("%s\n\n", stmt); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column POID to variable PID*/ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata.data, 3000, &xmldata.ind); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch result returned from Select statement*/ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + while (cliRC != SQL_NO_DATA_FOUND) + { + if(xmldata.ind > 0) + { + printf("\n%s\n\n", xmldata.data); + } + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + printf("\n Rolling back the transaction...\n"); + + /* end the transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} + +int CleanUpTables(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLCHAR *stmt = 0; + char clean[200]; + + + /* set AUTOCOMMIT OFF */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("cleaning up.... \n"); + + strcpy(clean,"DROP TABLE sales_department"); + printf("%s \n",clean); + rc = SQLExecDirect(hstmt, (SQLCHAR *)clean, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + strcpy(clean,"DROP TABLE sales_employee"); + printf("%s \n",clean); + rc = SQLExecDirect(hstmt, (SQLCHAR *)clean, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + strcpy(clean,"DROP TABLE performance_bonus_employees"); + printf("%s \n",clean); + rc = SQLExecDirect(hstmt, (SQLCHAR *)clean, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + strcpy(clean, "COMMIT"); + printf("%s \n",clean); + rc = SQLExecDirect(hstmt, (SQLCHAR *)clean, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + /* Free the allocated handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + return 1; + +} diff --git a/xml/cli/xmlupdel.c b/xml/cli/xmlupdel.c new file mode 100644 index 0000000..8ddb8a1 --- /dev/null +++ b/xml/cli/xmlupdel.c @@ -0,0 +1,708 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xmlupdel.c +** +** SAMPLE: This sample demonstrates updation and deletion of XML data +** from tables. +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLExecute -- Execute a Statement +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLNumResultCols -- Get Number of Result Columns +** SQLPrepare -- Prepare a Statement +** +** OUTPUT FILE: xmlupdel.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "utilcli.h" /* header file for CLI sample code */ + +/* Global Variables */ +int length; +char blobdata[500]; +char clobdata[500]; +char xmldata[500]; + +int CreateTables(SQLHANDLE); +int updateusingXMLtype(SQLHANDLE); +int updateusingBLOB(SQLHANDLE); +int updateusingBLOBimplicit(SQLHANDLE); +int updateusingVARCHARimpllicit(SQLHANDLE); +int updateusingVARCHARcolumn(SQLHANDLE); +int updateusingVARCHARcolumnimplicit(SQLHANDLE); +int updateusingVARCHARvalidate(SQLHANDLE); +int updateusingSELECTvalidate(SQLHANDLE); +int deleteXMLdoc(SQLHANDLE); +int DropTables(SQLHANDLE); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + SQLHANDLE hstmt; + SQLCHAR stmt[500] = {0}; + SQLINTEGER CID; /* variable to be bound to the CID column */ + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* Create a XML document that will be used to INSERT in the table */ + strcpy(xmldata, "" + " Plastic Casing " + "
Blue Color
" + " 2.89 " + " 0.23 " + "
"); + + strcpy(clobdata, xmldata); + strcpy(blobdata, xmldata); + length = strlen(xmldata) + 1; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* Call function to create Tables */ + rc = CreateTables(hdbc); + + printf(" SET THE CURRENT IMPLICT REGISTER\n"); + strcpy((char *)stmt, "SET CURRENT IMPLICIT XMLPARSE OPTION = PRESERVE WHITESPACE"); + + rc = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* perform update using variable of type XML */ + rc = updateusingXMLtype(hdbc); + + /* perform update using host variable of type BLOB */ + rc = updateusingBLOB(hdbc); + + /* update using variable of type BLOB, use Implicit Parsing */ + rc = updateusingBLOBimplicit(hdbc); + + /* update using variable of type VARCHAR */ + rc = updateusingVARCHARimpllicit(hdbc); + + /* update using another column of VARCHAR */ + rc = updateusingVARCHARcolumn(hdbc); + + /* update using another column of VARCHAR, implicit parsing */ + rc = updateusingVARCHARcolumnimplicit(hdbc); + + /* update using VARCHAR data and XMLVALIDATE */ + rc = updateusingVARCHARvalidate(hdbc); + + /* update using XML document returned by SELECT */ + rc = updateusingSELECTvalidate(hdbc); + + /* delete XML document from table */ + rc = deleteXMLdoc(hdbc); + + /* Call function to Drop tables */ + rc = DropTables(hdbc); + + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* free the statement handles */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* terminate the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; +} /* end main */ + +/* Function to Create tables */ +int CreateTables(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_ON, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + strcpy(stmt, "CREATE TABLE vartable (id INT," + " desc VARCHAR(200), comment VARCHAR(25))"); + + /* directly execute the statement */ + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(11111, \' Neeraj " + " Gaurav \', " + "\'Final Year\')"); + + /* Execute the statement */ + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(22222, '" + " Plastic Casing " + "
Green Color
" + " 7.89 " + " 6.23 " + "
', " + "'Last Product')"); + + /* Execute the statement */ + cliRC = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + strcpy(stmt, "INSERT INTO vartable VALUES " + "(33333, \' Neeraj " + " Gaurav \', " + "\'Final Year\')"); + + /* Execute the statement */ + rc = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Inserting a row in PurchaseOrder */ + strcpy(stmt, "INSERT INTO PURCHASEORDER (POID, PORDER) " + "VALUES (1232, ' 876 ')"); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* CreateTables */ + +/* updateusingXMLtype */ +int updateusingXMLtype(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Perform Update on the XML column using a variable of type XML\n"); + printf(" Bind uisng SQL_XML\n"); + strcpy(stmt, "UPDATE purchaseorder SET porder = " + "? WHERE poid = 1232"); + + printf(" Statement Executed : %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind Paramenter to the Update statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + length, + 0, + &xmldata, + length, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* updateusingXMLtype */ + +/* updateusingBLOB */ +int updateusingBLOB(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Performing update on the XML column of the table\n"); + printf(" Binding with data of type BLOB and EXPICIT PARSING\n"); + + strcpy(stmt, "UPDATE purchaseorder SET porder = " + "XMLPARSE(DOCUMENT CAST(? AS BLOB(1K))) WHERE poid = 1232"); + printf(" Statement Executed : %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind Paramenter to the Update statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_BINARY, + SQL_BLOB, + length, + 0, + &blobdata, + length, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* updateusingBLOB */ + +/* updateusingBLOBimplicit */ +int updateusingBLOBimplicit(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Perform Update on the XML column of the table\n"); + printf(" Binding with data of type BLOB and IMPLICT PARSING\n"); + + strcpy(stmt, "UPDATE purchaseorder SET porder = " + "? WHERE poid = 1232"); + printf(" Statement Executed : %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind Paramenter to the Update statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_BINARY, + SQL_BLOB, + length, + 0, + &blobdata, + length, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* updateusingBLOBimplicit */ + +/* updateusingVARCHARimpllicit */ +int updateusingVARCHARimpllicit(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Perform UPDATE on the XML column using VARCHAR and IMPLICIT PARSING\n"); + strcpy(stmt, "UPDATE purchaseorder SET porder = ' 123 '" + " WHERE poid = 1232"); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* updateusingVARCHARimpllicit */ + +/* updateusingVARCHARcolumn */ +int updateusingVARCHARcolumn(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* UPDATE the xml column using another column of varchar */ + printf(" UPDATE XML column from another column of type VARCHAR\n"); + strcpy(stmt, "UPDATE purchaseorder SET porder = (SELECT XMLPARSE( DOCUMENT desc PRESERVE WHITESPACE) " + " FROM vartable WHERE id = 11111)" + " WHERE poid = 1232"); + printf(" Statement Executing : %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* updateusingVARCHARcolumn */ + +/* updateusingVARCHARcolumnimplicit */ +int updateusingVARCHARcolumnimplicit(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* update when source is a XML document from a column */ + /* of type VARCHAR, Using Implicit Parsing */ + printf(" Upate when source is a XML document from a column of type VARCHAR, Using Implicit Parsing\n"); + strcpy(stmt, "UPDATE purchaseorder SET porder = " + "(SELECT desc FROM vartable WHERE id = 33333)" + " WHERE poid = 1232"); + printf(" Statement Executing : %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* updateusingVARCHARcolumnimplicit */ + +/* updateusingVARCHARvalidate */ +int updateusingVARCHARvalidate(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Perform update on the XML column using VARCHAR, also VALIDATE\n"); + strcpy(stmt, "UPDATE purchaseorder SET porder = " + "XMLVALIDATE (? ACCORDING TO XMLSCHEMA ID PRODUCT)" + " WHERE poid = 1232"); + printf(" Statement Executing : %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind Paramenter to the Update statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_CHAR, + length, + 0, + &xmldata, + length, + NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* updateusingVARCHARvalidate */ + +/* updateusingSELECTvalidate */ +int updateusingSELECTvalidate(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_OFF, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" UPDATE using XML document returned by select using XMLVALIDATE\n"); + strcpy(stmt, " UPDATE purchaseorder SET porder = (SELECT " + " XMLVALIDATE( XMLPARSE( DOCUMENT desc) ACCORDING TO XMLSCHEMA ID product)" + " FROM vartable WHERE id = 22222) WHERE poid = 1232"); + printf(" Statement Executing : %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* updateusingSELECTvalidate */ + +/* deleteXMLdoc */ +int deleteXMLdoc(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_ON, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" Delete porder for the XML DOC that have PID = 80\n"); + strcpy(stmt, "DELETE FROM purchaseorder WHERE " + "XMLEXISTS('$p/product[@pid=\"80\"]' " + "PASSING BY REF purchaseorder.porder AS \"p\")"); + printf(" Statement Executing : %s\n", stmt); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* deleteXMLdoc */ + +/* Function to Drop tables */ +int DropTables(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + char stmt[500]; + SQLHANDLE hstmt; /* statement handle */ + + /* set AUTOCOMMIT on */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_ON, + SQL_NTS); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + strcpy(stmt, "DROP TABLE VARTABLE"); + + /* Execute the statement */ + rc = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Cleaup PurchaseOrder table */ + strcpy(stmt, " DELETE FROM purchaseorder POID = 1232"); + + /* Execute the statement */ + rc = SQLExecDirect(hstmt, (SQLCHAR *)stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* DropTables */ + diff --git a/xml/cli/xsupdate.c b/xml/cli/xsupdate.c new file mode 100644 index 0000000..8c8fa12 --- /dev/null +++ b/xml/cli/xsupdate.c @@ -0,0 +1,406 @@ +/*************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +** ************************************************************************* +** +** SAMPLE FILE NAME: xsupdate.c +** +** PURPOSE: To demonstrate how to update an existing XML schema with +** a new schema that is compatible with the original schema +** +** USAGE SCENARIO: A store manager maintains product details in an XML +** document that conforms to an XML schema. The product +** details are: Name, SKU and Price. The store manager +** wants to add a product description for each of the +** products along with the existing product details. +** +** PREREQUISITE: The original schema and the new schema should be +** present in the same directory as the sample. +** Copy prod.xsd, newprod.xsd from directory +** /xml/data to the working directory. +** +** EXECUTION: i) bldapp xsupdate ( build and compile the sample) +** ii) xsupdate ( run the sample) +** +** INPUTS: NONE +** +** OUTPUTS: Updated schema and successful insertion of the XML documents +** with the new product descriptions. +** +** OUTPUT FILE: xsupdate.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** CREATE +** INSERT +** DROP +** +** SQL PROCEDURES USED: +** XSR_REGISTER +** XSR_COMPLETE +** XSR_UPDATE +** +** SQL/XML FUNCTIONS USED: +** XMLVALIDATE +** XMLPARSE +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLConnect -- Connect to a Data Source +** SQLDisconnect -- Disconnect from a Data Source +** SQLEndTran -- End Transactions of a Connection +** SQLExecDirect -- Execute a Statement Directly +** SQLFreeHandle -- Free Handle Resources +** +** ************************************************************************* +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +** ************************************************************************* +** +** SAMPLE DESCRIPTION +** +** ************************************************************************* +** 1. Register the original schema with product details:Name, SKU and Price. +** 2. Register the new schema containing the product description element +** along with the existing product details. +** 3. Call the XSR_UPDATE stored procedure to update the original schema. +** 4. Insert an XML document containing the product description elements. +** *************************************************************************/ + +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ + +// function to register an XML schema +int registerxmlschema(SQLHANDLE hdbc, + char p_rschema[129], + char p_name[129], + char p_schemalocation[1001], + unsigned char filename[1000], + SQLSMALLINT filenameLength, + SQLUINTEGER fileoptions, + int shred); + +// function to update an XML schema +int updatexmlschema(SQLHANDLE hdbc, + char p_rschemaOld[129], + char p_nameOld[129], + char p_rschemaNew[129], + char p_nameNew[129], + int dropnew); + +// function to drop the objects created +int cleanup(SQLHANDLE hdbc); + +int main(int argc, char *argv[]) +{ + SQLRETURN rc = SQL_SUCCESS; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + SQLHANDLE hstmt; /* statement handle */ + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + SQLCHAR *stmt = (SQLCHAR *) "CREATE TABLE store.products(id INT GENERATED ALWAYS AS IDENTITY,details XML)"; + char p_rschema[129]; /* variables used in register schema */ + char p_name[129]; + char p_schemalocation[1001]; + unsigned char filename[1000]; + SQLSMALLINT filenameLength; + SQLUINTEGER fileoptions = SQL_FILE_READ; + int shred = 0; + char p_rschemaOld[129]; /* variables used in update schema */ + char p_nameOld[129]; + char p_rschemaNew[129]; + char p_nameNew[129]; + int dropnew = 1; + char insstmt[2500]; + + /**************************************************************************** + ** SETUP + ** **************************************************************************/ + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nThis sample will show \n 1. How to register an XML schema to the database \n"); + printf(" 2. How to insert an XML document validating against the registered schema \n"); + printf(" 3. How to update an XML schema with a compatible schema \n"); + + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + + printf("\nCreating the table products \n\n"); + /* allocate the statement handle */ + rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + /* execute create table statement */ + rc = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + /**************************************************************************** + ** 1. Register the original schema with product details: Name, SKU and Price. + ** *************************************************************************/ + + /* register the schema STORE.PROD */ + printf("Registering the schema STORE.PROD\n"); + strcpy(p_rschema,"STORE"); + strcpy(p_name,"PROD"); + strcpy(p_schemalocation,"www.prod.com/prod.xsd"); + strcpy((char *)filename,"prod.xsd"); + filenameLength = strlen((char *)filename); + /* call the function to register the schema */ + registerxmlschema(hdbc,p_rschema,p_name,p_schemalocation,filename,filenameLength,fileoptions,shred); + + /* Insert an XML document into the products table validating + against the schema STORE.PROD */ + printf("Insert XML document validating against the schema STORE.PROD \n\n"); + strcpy(insstmt, "INSERT INTO store.products(details) VALUES(XMLVALIDATE( XMLPARSE( DOCUMENT ' Ice Scraper, Windshield 4 inch stores 999 Ice Scraper, Windshield 8 inch stores 1999 Ice Scraper, Windshield 5 inch stores 1299 ') ACCORDING TO XMLSCHEMA ID STORE.PROD))"); + /* Execute the statement */ + rc = SQLExecDirect(hstmt, (SQLCHAR *)insstmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + /***************************************************************************** + ** 2. Register the new schema containing the product description element + ** along with the existing product details. + *****************************************************************************/ + + /* register the schema STORE.NEWPROD */ + printf("Registering the schema STORE.NEWPROD\n"); + + strcpy(p_rschema,"STORE"); + strcpy(p_name,"NEWPROD" ); + strcpy(p_schemalocation,"www.newprod.com/newprod.xsd"); + strcpy((char *)filename,"newprod.xsd"); + filenameLength = strlen((char *)filename); + /* call the function to register the schema */ + registerxmlschema(hdbc,p_rschema,p_name,p_schemalocation,filename,filenameLength,fileoptions,shred); + + /**************************************************************************** + ** 3. Call the XSR_UPDATE stored procedure to update the original schema. + *****************************************************************************/ + + /* Update schema STORE.PROD with STORE.NEWPROD */ + strcpy(p_rschemaOld,"STORE"); + strcpy(p_nameOld,"PROD"); + strcpy(p_rschemaNew,"STORE"); + strcpy(p_nameNew,"NEWPROD"); + /* call the function to update the schema */ + updatexmlschema(hdbc,p_rschemaOld,p_nameOld,p_rschemaNew,p_nameNew,dropnew); + + /**************************************************************************** + ** 4. Insert an XML document containing the product description elements. + *****************************************************************************/ + + /* Insert an XML document into the products table validating + against the updated schema STORE.PROD */ + strcpy(insstmt, "INSERT INTO store.products(details) VALUES(XMLVALIDATE( XMLPARSE( DOCUMENT ' Ice Scraper, Windshield 4 inch stores 999 A new prod Ice Scraper, Windshield 8 inch stores 1999 A new prod Ice Scraper, Windshield 5 inch stores 1299 ') ACCORDING TO XMLSCHEMA ID STORE.PROD))"); + /* Execute the statement */ + rc = SQLExecDirect(hstmt, (SQLCHAR *)insstmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + /* Drop the objects created by calling the function cleanup */ + cleanup(hdbc); + + /* Free the allocated handles */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + /* terminate the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + return rc; +} + +/* Function to register an XML schema */ +int registerxmlschema(SQLHANDLE hdbc, + char p_rschema[129], + char p_name[129], + char p_schemalocation[1001], + unsigned char filename[1000], + SQLSMALLINT filenameLength, + SQLUINTEGER fileoptions, + int shred) +{ + int rc = 0; + SQLHANDLE hstproc=SQL_NULL_HANDLE ; + char storedproc[100] ; + SQLINTEGER blob_indicator = 0 ; + SQLINTEGER name_ind = 0 ; + + name_ind = strlen(p_name); + + /* Register the XML schema */ + /* ****************** */ + rc = SQLAllocHandle(SQL_HANDLE_STMT , hdbc , &hstproc ); + strcpy(storedproc,"CALL SYSPROC.XSR_REGISTER(?,?,?,?,NULL)"); + rc = SQLPrepare(hstproc,(SQLCHAR *)storedproc,SQL_NTS); + /* bind variables to the parameters */ + rc = SQLBindParameter(hstproc,1,SQL_PARAM_INPUT,SQL_C_CHAR, + SQL_VARCHAR,128,0,(SQLPOINTER)p_rschema, + strlen(p_rschema),NULL); + rc = SQLBindParameter(hstproc,2,SQL_PARAM_INPUT_OUTPUT,SQL_C_CHAR, + SQL_VARCHAR,128,0,(SQLPOINTER)p_name, + (strlen(p_name)+1),&name_ind); + rc = SQLBindParameter(hstproc,3,SQL_PARAM_INPUT,SQL_C_CHAR, + SQL_VARCHAR,1000,0,(SQLPOINTER)p_schemalocation, + strlen(p_schemalocation),NULL); + rc = SQLBindFileToParam(hstproc,4,SQL_BLOB, + filename,&filenameLength,&fileoptions, + strlen((char *)filename),&blob_indicator); + printf("Registering the XML Schema... \n"); + rc = SQLExecute(hstproc); + STMT_HANDLE_CHECK(hstproc, hdbc, rc); + printf("Registered XML Schema successfully \n"); + + /* Complete the XML schema */ + /* ****************** */ + SQLFreeHandle( SQL_HANDLE_STMT , hstproc ); + rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstproc); + strcpy(storedproc,"CALL SYSPROC.XSR_COMPLETE(?,?,NULL,?)"); + rc = SQLPrepare(hstproc,(SQLCHAR *)storedproc,SQL_NTS); + /* bind variables to the parameters */ + rc = SQLBindParameter(hstproc,1,SQL_PARAM_INPUT,SQL_C_CHAR, + SQL_VARCHAR,128,0,(SQLPOINTER)p_rschema, + strlen(p_rschema),NULL); + rc = SQLBindParameter(hstproc,2,SQL_PARAM_INPUT,SQL_C_CHAR, + SQL_VARCHAR,128,0,(SQLPOINTER)p_name, + strlen(p_name),NULL); + rc = SQLBindParameter(hstproc,3,SQL_PARAM_INPUT,SQL_C_LONG, + SQL_INTEGER,0,0,(SQLPOINTER)&shred,0,NULL); + printf("completing the XML Schema... \n"); + rc = SQLExecute(hstproc); + STMT_HANDLE_CHECK(hstproc, hdbc, rc); + printf("Completed XML Schema successfully \n\n"); + + /* Free the allocated handles */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstproc); + STMT_HANDLE_CHECK(hstproc, hdbc, rc); + +return 1; +} // registerxmlschema + +/* function to update an XML schema */ +int updatexmlschema(SQLHANDLE hdbc, + char p_rschemaOld[129], + char p_nameOld[129], + char p_rschemaNew[129], + char p_nameNew[129], int dropnew) +{ + + int rc = 0; + SQLHANDLE hstproc = SQL_NULL_HANDLE ; + char storedproc[100] ; + SQLINTEGER name_ind1 = 0 ; + SQLINTEGER name_ind2 = 0 ; + + name_ind1 = strlen(p_nameOld); + name_ind2 = strlen(p_nameNew); + + /* Allocate the handle */ + rc = SQLAllocHandle(SQL_HANDLE_STMT , hdbc , &hstproc ); + + printf("Updating the schema... \n"); + strcpy(storedproc,"CALL SYSPROC.XSR_UPDATE(?,?,?,?,?)"); + rc = SQLPrepare(hstproc,(SQLCHAR *)storedproc,SQL_NTS); + /* Bind the variables to the parameters */ + rc = SQLBindParameter(hstproc,1,SQL_PARAM_INPUT,SQL_C_CHAR, + SQL_VARCHAR,128,0,(SQLPOINTER)p_rschemaOld, + strlen(p_rschemaOld),NULL); + rc = SQLBindParameter(hstproc,2,SQL_PARAM_INPUT_OUTPUT,SQL_C_CHAR, + SQL_VARCHAR,128,0,(SQLPOINTER)p_nameOld, + sizeof(p_nameOld),&name_ind1); + rc = SQLBindParameter(hstproc,3,SQL_PARAM_INPUT,SQL_C_CHAR, + SQL_VARCHAR,128,0,(SQLPOINTER)p_rschemaNew, + strlen(p_rschemaNew),NULL); + rc = SQLBindParameter(hstproc,4,SQL_PARAM_INPUT_OUTPUT,SQL_C_CHAR, + SQL_VARCHAR,128,0,(SQLPOINTER)p_nameNew, + sizeof(p_nameNew),&name_ind2); + rc = SQLBindParameter(hstproc,5,SQL_PARAM_INPUT,SQL_C_LONG, + SQL_INTEGER,0,0,(SQLPOINTER)&dropnew,0,NULL); + + /* this stored procedure will update the original schema with the new schema + if the new schema is compatible with the original one. + the last parameter is set to a non zero value to drop the schema used to + update the original schema, if it is set to zero then the new schema will + continue to reside in XSR. */ + rc = SQLExecute(hstproc); + STMT_HANDLE_CHECK(hstproc, hdbc, rc); + printf("Schema updated successfully \n\n"); + + /* Free the allocated handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstproc); + STMT_HANDLE_CHECK(hstproc, hdbc, rc); + +return 1; +} // updatexmlschema + +/* function to drop the created objects */ +int cleanup(SQLHANDLE hdbc) +{ + int rc = 0; + SQLHANDLE hstmt=SQL_NULL_HANDLE ; + char clean[200]; + + /* Allocate the handle */ + rc = SQLAllocHandle(SQL_HANDLE_STMT , hdbc , &hstmt ); + + printf("cleaning up.... \n"); + + strcpy(clean,"DROP TABLE store.products"); + printf("%s \n",clean); + /* Execute the statement */ + rc = SQLExecDirect(hstmt, (SQLCHAR *)clean, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + strcpy(clean,"DROP XSROBJECT STORE.PROD"); + printf("%s \n",clean); + rc = SQLExecDirect(hstmt, (SQLCHAR *)clean, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + + /* Free the allocated handle */ + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, rc); + +return 1; +} // cleanup diff --git a/xml/clp/README b/xml/clp/README new file mode 100644 index 0000000..80e782f --- /dev/null +++ b/xml/clp/README @@ -0,0 +1,283 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for Command Line Processor XML Samples +* +* The "/sqllib/samples/xml/clp" directory on Unix and +* "\sqllib\samples\xml\clp" directory on Windows +* contains this README file. +* where is the location of DB2 9.7 on your +* hard drive. +* The default location for is +* C:\Program Files\IBM on Windows, +* $HOME on Unix. +* +* This README describes how to run CLP XML sample code for DB2 9.7. The +* DB2 9.7 sample code for CLP XML is located in the following directory: +* \sqllib\samples\xml\clp for Windows and +* /sqllib/samples/xml/clp for Unix +* +* It is recommended that you copy the sample files from this directory +* to a working directory prior to building the sample programs. +* The sample program directories are typically read-only on most +* platforms and some samples produce output files that require write +* perimssions on the directory. +* +* WARNING: +* 1. Some of these samples may change your database or database manager +* configuration. Execute the samples against a test database +* only, such as SAMPLE database. +* +****************************************************************************** +* +* Prepare your DB2 sample development environment for Windows/Unix +* +* 1) Copy the files in \sqllib\samples\xml\clp\* for Windows +* and $HOME/sqllib/samples/xml/clp/* for Unix to a working directory +* and ensure that directory has write permission. +* +* 2) On Windows platform, all samples should be run and built in DB2 +* Command Window. +* The DB2 command window is needed to execute the db2 specific commands. +* You can follow the step below to open DB2 command window. +* From the Start Menu click Start --> Programs --> IBM DB2 --> +* --> Command Line Tools --> Command Window. +* +* 3) Start the database manager with the following command: +* db2start +* +* 4) Create the sample database with the following command: +* db2sampl -xml +* +* 5) Connect to the sample database with the following command: +* db2 connect to sample +* +* 6) To build stored procedures and User defined functions, +* ensure that you have write permission on the +* \sqllib\function directory on Windows and +* /sqllib/function directory on Unix. +* +* 7) Change directory (CD) to the directory containing the files +* copied in step 1. +* +****************************************************************************** +* +* *** Executing CLP Samples *** +* +* Use following command to execute CLP samples: +* db2 -vf -t +* -- Name of the Command Line Processor file (including +* the extension). +* +* NOTE : +* +* 1. Some of the samples might need one or more data files at runtime. +* some of the samples may also need setup script to be run before +* running the sample.See the specific sample descriptions in +* "File Descriptions" section for more details. +* +* 2. Refer to the "File Descriptions" section in this README for +* information on specific samples and any special considerations +* relevant for each. The HEADER sections of these samples also provide +* further details on each sample. +* +****************************************************************************** +* +* Common file Descriptions +* +* The following are the common files for Command Line Processor samples. +* For more information on these files, refer to the program source files. +* +******************************************************************************* +* +* Common files +* +* README - this file +* +****************************************************************************** +* +* sample descriptions +* +* The following are the Command Line Processor sample files included with DB2. +* For more information on these files, refer to program source files. +* +****************************************************************************** +* +* COMMAND LINE PROCESSOR XML Sample File Descriptions +* +* xmlschema.db2 - How to register an XML schema to a database. +* How to use this registered schema to validate an XML +* value before inserting into a table. +* PREREQUISITE: copy product.xsd, order.xsd, +* customer.xsd, header.xsd Schema files, order.xml XML +* document from xml/data directory to working +* directory +* +* xmltotable.db2 - How to insert the data from XML document to a +* relational table using XML Constructor function and +* SQL/XML functions. +* +* reltoxmldoc.db2 - How to create XML object from data stored in +* relational tables using various SQL/XML Constructor +* functions. The XML object is created using stored +* procedure. +* PREREQUISITE: This sample uses a stored procedure. +* Stored procedure should be registered before running +* the sample. Follow the step given in the header of +* the sammple for more details.Run the cleanup.db2 +* and setupscript.db2 scripts before running this +* simple.Run the cleanupscript.db2 script to cleanup +* the database objects after running the sample. +* These scripts can be found in xml/data directory. +* +* reltoxmltype.db2 - How to create XML object from data stored in +* relational tables using various SQL/XML Constructor +* functions. +* PREREQUISITE: Run the script setupscript.db2 before +* running this simple. Run the cleanupscript.db2 script +* to cleanup the database objects after running the +* sample. These scripts can be found in xml/data +* directory. +* +* xmldecomposition.db2 - How to decompose data stored in a XML file and +* insert those into relational tables with constraints. +* PREREQUISITE: run the script setupfordecomposition.db2 +* before running the sample. Run the script +* cleanupfordecomposition.db2 after running the sample +* to cleanup the object created for the samples. These +* scripts can be found in xml/data directory. This +* sample require bookdetails.xsd, booksreturned.xsd, bookdetails.xml, +* booksreturned.del, booksreturned1.xml, booksreturned2.xml, +* booksreturned3.xml files at run time. Copy these files to your +* working directory before running the sample. These files can +* be found in xml/data directory. +* +* recxmldecomp.db2 - How to register a recursive XML schema to the XSR and +* enable the same for decomposition. +* PREREQUISITE: The instance document and the annotated +* schema should exist in the same directory as the sample. +* Copy recemp.xml, recemp.xsd from directory +* /sqllib/samples/xml/data in UNIX and +* \sqllib\samples\xml\data in Windows to the +* working directory. +* +* xmlload.db2 - How to load XML data into an XML column using +* LOAD command. +* PREREQUISITE:The data files and XML documents must exist +* in the same directory as the sample. Copy loaddata1.del +* and loaddata2.del from directory xml/data in UNIX and +* xml\data in Windows to the working directory. +* Create a new directory "xmldatadir" in the working directory +* and copy loadfile1.xml and loadfile2.xml from directory +* xml/data in UNIX and xml\data in Windows to the newly +* created xmldatadir directory. +* +* lobstoxml.db2 - How to move LOB data into an XML column using +* IMPORT and EXPORT commands. +* PREREQUISITE: create a directory lobdatadir in +* present working directory to store the data files +* created during the execution of the sample. +* +* impexpxml.db2 - How to move table data of XML datatype using IMPORT +* and EXPORT commands. +* PREREQUISITE: copy xmldata.del in present working +* directory. xmldata.del can be found in xml/data +* directory create a directory xmldatadir in present +* working directory and copy the file xmlfiles.001.xml +* to this directory. +* +* xmldb2batch.db2 - How to perform 'db2batch' with XML datatype +* PREREQUISITE: Make sure that xmldb2batch_in.sql file +* is there in working directory. This file can be found +* in xml/clp directory. +* +* xmldb2look.db2 - How to perform 'db2look' for XML datatype. +* +* xmlrunstats.db2 - How to perform runstats on a table having XML +* columns. +* +* simple_xmlproc.db2 - How to use XML type parameters in stored procedures. +* +* xmlindex.db2 - How to create index on an XML column. +* +* xmlconst.db2 - How to put constraints on an XML column. +* NOTE : This sample demonstrate the how to enforce the +* constraints on an XML value. There are some statement +* in the samples which are expected to fail because of +* constraint violation so The sql error SQL803N, +* SQL20305N and SQL20306N are expected. +* +* xsupdate.db2 - How to update an XML schema with a compatible schema. +* PREREQUISITE: The original schema and the new schema +* should be present in the same directory as the sample. +* Copy prod.xsd, newprod.xsd from directory +* /xml/data to the working directory. +* +* xmltrig.db2 - How to automate validation for XML documents while +* insertion or updation using XML triggers. +* PREREQUISITE: boots.xsd schema must be copied +* from /xml/data to the current +* working directory from where the sample will +* be executed. +* +* xmlintegrate.db2 - How to use XMLROW and XMLGROUP functions to publish +* relational information as XML. +* To show XMLQuery default passing mechanism. +* To show default column specification for XMLTABLE. +* +* xmlxslt.db2 - How to convert XML document from one form to another +* using XSL stylesheets. +* +* xmlcheckconstraint.db2 +* - How to create check constraint on XML column validating +* XML document against single or multiple schemas. +* PREREQUISITE: boots.xsd and musicplayer.xsd schemas +* must be copied from /xml/data to the +* current working directory from where the sample will +* be executed. +* +* xrpart.db2 - How to create table with XML columns in partitioned +* environment. How a table can be altered to ATTACH, +* DETACH and ADD partitions. +* +* xmlindgtt.db2 - The sample demonstrates the support for XML in +* Declare global temporary table (DGTT). +* +* xmlpartition.db2 - The sample demonstrates the use of XML in +* partitioned database environment, MDC and +* partitioned tables. +* +* xmldbafn.db2 - How to use the following DBA functions to get +* inline properties of XML documents or LOBs. +* 1. ADMIN_IS_INLINED +* 2. ADMIN_EST_INLINE_LENGTH +* +* xmlmdc.db2 - How to create an MDC table with XML column and how +* faster insert and faster delete options are supported +* on MDC tables having XML columns. +* +* xmlolic.db2 - How to run a REORG INDEX and REORG INDEXES ALL commands +* with ALLOW WRITE ACCESS option on a regular table and +* on a partitioned table. +* +* xmludfs.db2 - How XML data type is supported in scalar UDFs, sourced +* UDFs and SQL bodied UDFs +******************************************************************************* diff --git a/xml/clp/impexpxml.db2 b/xml/clp/impexpxml.db2 new file mode 100644 index 0000000..ec92702 --- /dev/null +++ b/xml/clp/impexpxml.db2 @@ -0,0 +1,89 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: impexpxml.db2 +-- +-- SAMPLE: How to use IMPORT and EXPORT with new options for XML data +-- +-- PREREQUISITES: +-- 1. Copy xmldata.del to the Present Working Directory (PWD) +-- 2. Create a directory "xmldatadir" in PWD and copy "xmlfiles.001.xml" +-- to the "xmldatadir" directory +-- +-- SQL STATEMENT USED: +-- CREATE TABLE +-- INSERT INTO +-- SELECT +-- DROP TABLE +-- IMPORT +-- EXPORT +-- TERMINATE +-- +-- OUTPUT FILE: impexpxml.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample; + +-- create a table CUSTOMER_XML with XML an column to import the data +CREATE TABLE customer_xml(Cid INT, Info XML); + +-- import the data to the table using XMLVALIDATE USING XDS clause +IMPORT FROM xmldata.del OF DEL XML FROM xmldatadir + MODIFIED BY XMLCHAR + XMLVALIDATE using XDS DEFAULT customer + IGNORE (supplier) MAP((product,customer)) + INSERT INTO customer_xml; + +-- select the data from the table to show that data is inserted successfully +SELECT * FROM customer_xml ORDER BY cid; + +-- delete the inserted data from CUSTOMER_XML +DELETE FROM customer_xml; + +-- import the data to the table using XMLVALIDATE USING SCHEMA clause +IMPORT FROM xmldata.del OF DEL XML FROM xmldatadir + MODIFIED BY XMLCHAR + XMLVALIDATE using SCHEMA customer + INSERT INTO customer_xml; + +-- Select the data from the table to show that data is inserted successfully +SELECT * FROM customer_xml ORDER BY cid; + +-- Export the data back using XMLSAVESCHEMA option +EXPORT TO xmldata_exp.del OF DEL XML TO xmldatadir XMLFILE xmlfiles_exp + MODIFIED BY XMLCHAR XMLINSEPFILES XMLSAVESCHEMA + SELECT * FROM customer_xml; + +-- drop the table CUSTOMER_XML +DROP TABLE customer_xml; + +CONNECT RESET; + diff --git a/xml/clp/lobstoxml.db2 b/xml/clp/lobstoxml.db2 new file mode 100644 index 0000000..87f5edf --- /dev/null +++ b/xml/clp/lobstoxml.db2 @@ -0,0 +1,85 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: lobstoxml.db2 +-- +-- SAMPLE: How to move LOB data into an XML column using IMPORT and EXPORT commands +-- +-- PREREQUSITES: +-- Create a directory "lobdatadir" in the present working dirctory +-- +-- SQL STATEMENT USED: +-- CREATE TABLE +-- INSERT INTO +-- SELECT +-- DROP TABLE +-- IMPORT +-- EXPORT +-- TERMINATE +-- +-- OUTPUT FILE: lobstoxml.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample; + +-- create the table CUSTOMER_LOB with one LOB column "Info" +CREATE TABLE customer_lob(Cid INT, Info CLOB(50K)); + +-- populate the table CUSTOMER_LOB with multiple rows of data +INSERT INTO customer_lob VALUES(1001,'Manoj Sardana1596 BaselineAuroraOntarioN8X-7F8905-555-7258416-555-2937905-555-8743613-555-3278'); + +INSERT INTO customer_lob VALUES(1002,'Padma Kota1596 BaselineAuroraOntarioN8X-7F8905-555-7258416-555-2937905-555-8743613-555-3278'); + +INSERT INTO customer_lob VALUES(1003,'Sanjay Kumar1596 BaselineAuroraOntarioN8X-7F8905-555-7258416-555-2937905-555-8743613-555-3278'); + +-- export the data from table CUSTOMER_LOB into lobdata.del with LOB data in seperate files +EXPORT TO lobdata.del OF DEL LOBS TO lobdatadir LOBFILE lobfiles + MODIFIED BY LOBSINSEPFILES SELECT * FROM customer_lob; + +-- create the table CUSTOMER with an XML column "Info" instead of LOB type +CREATE TABLE customer_xml(Cid INT, Info XML); + +-- import data from the lobdata.del and insert into the XML column of table CUSTOMER_XML +IMPORT FROM lobdata.del OF DEL LOBS FROM lobdatadir + MODIFIED BY XMLCHAR + XMLVALIDATE USING SCHEMA customer + INSERT INTO customer_xml; + +-- Select the data from the table CUSTOMER_XML to show that data is inserted successfully +SELECT * FROM customer_xml ORDER BY cid; + +-- drop the tables +DROP TABLE customer_xml; +DROP TABLE customer_lob; + +CONNECT RESET; + + diff --git a/xml/clp/recxmldecomp.db2 b/xml/clp/recxmldecomp.db2 new file mode 100644 index 0000000..f702053 --- /dev/null +++ b/xml/clp/recxmldecomp.db2 @@ -0,0 +1,123 @@ +--/************************************************************************* +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************* +-- +-- SAMPLE FILE NAME: recxmldecomp.db2 +-- +-- PURPOSE: How to register a recursive XML schema to the XSR and +-- enable the same for decomposition. +-- +-- USER SCENARIO: The existing PurchaseOrder schema in the Sample database is +-- enhanced to have new Employee tables to process the purchase orders. +-- We have Recursive Schema for Employee data management, an employee +-- can be a manager and himself reporting to another employee. The XML document +-- contains the employee information along with department details which needs +-- to be stored in relational tables for easy retrieval of data. +-- +-- +-- PREREQUISITE: +-- The instance document and the annotated schema should exist in the same +-- directory as the sample. Copy recemp.xml, recemp.xsd from directory +-- /sqllib/samples/xml/data in UNIX and +-- \sqllib\samples\xml\data in Windows to the working directory. +-- +-- EXECUTION: db2 -tvf recxmldecomp.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Decomposition of XML document according to the annotations +-- in recursive schema. +-- +-- OUTPUT FILE: recxmldecomp.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- REGISTER XMLSCHEMA +-- COMPLETE XMLSCHEMA +-- DECOMPOSE XML DOCUMENT +-- CREATE +-- SELECT +-- DROP +-- +-- ************************************************************************* +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- ************************************************************************* +-- +-- SAMPLE DESCRIPTION +-- +-- ************************************************************************* +-- 1. Register the annotated XML schema. +-- 2. Decompose the XML document using the registered XML schema. +-- 3. Select data from the relational tables to see decomposed data. +-- *************************************************************************/ + +-- /************************************************************************* +-- SETUP +-- **************************************************************************/ + +-- connect to the database sample +CONNECT TO SAMPLE; + +-- create the table to store the decomposed data +CREATE TABLE xdb.poemployee (empid VARCHAR(20), deptid VARCHAR(20), members XML); + +-- /************************************************************************* +-- 1. Register the annotated XML schema. +-- *************************************************************************/ + +-- register the schema document +REGISTER XMLSCHEMA 'http://porder.com/employee.xsd' FROM 'recemp.xsd' AS xdb.employee; + +-- complete schema registration +COMPLETE XMLSCHEMA xdb.employee ENABLE DECOMPOSITION; + +-- check catalog tables for information regarding registered schema. +SELECT status, decomposition, decomposition_version + FROM SYSIBM.SYSXSROBJECTS + where XSROBJECTNAME = 'EMPLOYEE'; + +-- /************************************************************************* +-- 2. Decompose the XML document using the registered XML schema. +-- *************************************************************************/ + +-- decompose the XML document +DECOMPOSE XML DOCUMENT recemp.xml XMLSCHEMA xdb.employee VALIDATE; + +-- /************************************************************************* +-- 3. Select data from the relational tables to see decomposed data. +-- *************************************************************************/ + +-- check Decomposition result +SELECT * FROM xdb.poemployee ORDER BY empid; + +-- /************************************************************************* +-- CLEANUP +-- **************************************************************************/ + +-- drop the created objects +DROP XSROBJECT xdb.employee; +DROP TABLE xdb.poemployee ; + +-- Reset connection +CONNECT RESET; diff --git a/xml/clp/reltoxmldoc.db2 b/xml/clp/reltoxmldoc.db2 new file mode 100644 index 0000000..c58269f --- /dev/null +++ b/xml/clp/reltoxmldoc.db2 @@ -0,0 +1,70 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: reltoxmldoc.db2 +-- +-- SAMPLE: Purchase order database uses relational tables to store the orders of +-- different customers. This data can be returned as an XML object to the +-- application. The XML object can be created using the XML constructor +-- functions on the server side. +-- To achieve this, the user can +-- 1. Create a stored procedure to implement the logic to create the XML +-- object using XML constructor functions. +-- 2. Register the above stored procedure to the database. +-- 3. Call the procedure whenever all the PO data is needed instead of using complex joins. +-- +-- PREREQUISITE: +-- The relational tables that store the purchase order data will have to +-- be created before this sample is executed. For this the file +-- setupscript.db2 will have to be run using the command +-- db2 -tvf setupscript.db2 +-- The stored procedure will have to be registered before this sample is executed. +-- The command to register the stored procedure is +-- db2 -td@ -f reltoxmlproc.db2 +-- +-- SQL STATEMENT USED: +-- SELECT +-- CALL +-- CONNECT RESET +-- +-- OUTPUT FILE: reltoxmldoc.out (available in the online documentation) +----------------------------------------------------------------------------- + +-- CONNECT TO DATABSE + CONNECT TO sample; + +-- Select purchase order data from the relational tables. + SELECT po.CustID, po.PoNum, po.OrderDate, po.Status, + count(l.ProdID) as Items, sum(p.Price) as total, + po.Comment, c.Name, c.Street, c.City, c.Province, c.PostalCode + FROM PurchaseOrder_relational as po, CustomerInfo_relational as c, + Lineitem_relational as l, Products_relational as p + WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID + GROUP BY po.PoNum,po.CustID,po.OrderDate,po.Status,c.Name,c.Street,c.City,c.Province, + c.PostalCode,po.Comment + ORDER BY po.CustID,po.OrderDate; + +-- Call the stored procedure. This stored procedure will convert all the relational +-- purchase order data into an well formed XML document. Thus all the relational data is +-- stored in the XML document. + CALL reltoxmlproc(); + +-- Reset Database connection + CONNECT RESET; diff --git a/xml/clp/reltoxmlproc.db2 b/xml/clp/reltoxmlproc.db2 new file mode 100644 index 0000000..50846a3 --- /dev/null +++ b/xml/clp/reltoxmlproc.db2 @@ -0,0 +1,79 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: reltoxmlproc.db2 +-- +-- SAMPLE: This stored procedure uses the constructor functions to create an XML +-- document with all the purchase order details. The input to the constructor +-- function will be the relational data stored in the tables. The final +-- output of the constructor functions will be a well formed XML document having +-- all the purchase orders. The stored procedure will return the purchase order +-- XML document back to the application. +-- +-- This stored procedure will be called by samples +-- a)reltoxmldoc.db2 +-- b)reltoxmldoc.sqc +-- +-- SQL STATEMENTS USED: +-- CREATE PROCEDURE +-- OPEN +-- +-- OUTPUT FILE: NA +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CONNECT TO SAMPLE@ +CREATE PROCEDURE reltoxmlproc() +RESULT SETS 1 +LANGUAGE SQL +BEGIN +DECLARE C1 CURSOR WITH RETURN FOR +SELECT po.PoNum, po.CustID, po.OrderDate, XMLCONCAT( XMLPI(NAME "pi", 'MESSAGE("valid, well-formed d +ocument")'), +XMLELEMENT (NAME "PurchaseOrder", XMLNAMESPACES( 'http://www.example.org' AS "e"), +XMLATTRIBUTES (po.CustID as "CustID", po.PoNum as "PoNum", po.OrderDate as "OrderDate", po.Status as "Status" ), + XMLELEMENT (NAME "CustomerAddress", XMLCONCAT( + XMLELEMENT (NAME "e.Name", c.Name ), + XMLELEMENT (NAME "e.Street", c.Street ), + XMLELEMENT (NAME "e.City", c.City ), + XMLELEMENT (NAME "e.Province", c.Province ), + XMLELEMENT (NAME "e.PostalCode", c.PostalCode ) ) ), + XMLELEMENT (NAME "ItemList" , +XMLELEMENT (NAME "Item", +XMLELEMENT (NAME "PartId", l.ProdID ), +XMLELEMENT (NAME "Description", p.Description ), +XMLELEMENT (NAME "Quantity", l.Quantity ), +XMLELEMENT (NAME "Price", p.Price ) , +XMLCOMMENT(po.comment) ) ) ) ) +FROM PurchaseOrder_Relational as Po, CustomerInfo_Relational AS c, Lineitem_Relational AS l, Products_Relational AS p +WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID +ORDER BY po.PoNum; +OPEN C1; +END@ + diff --git a/xml/clp/reltoxmltype.db2 b/xml/clp/reltoxmltype.db2 new file mode 100644 index 0000000..40a2725 --- /dev/null +++ b/xml/clp/reltoxmltype.db2 @@ -0,0 +1,105 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: reltoxmltype.db2 +-- +-- SAMPLE: Purchase order database uses relational tables to store the orders of +-- different customers. This data can be returned as an XML object to the +-- application. The XML object can be created using the XML constructor +-- functions on the server side. +-- To achieve this, the user can +-- 1. Create new tables having XML columns. (Done in setup script) +-- 2. Change the relational data to XML type using constructor functions. +-- 3. Insert the data in XML columns. +-- 4. Use the query to select all PO data. +-- +-- PREREQUISITE: +-- The relational tables that store the purchase order data will have to +-- be created before this sample is executed. For this the file +-- setupscript.db2 will have to be run using the command +-- db2 -tvf setupscript.db2 +-- Please make sure that you run the cleanup script after running the +-- sample using following command +-- db2 -tvf cleanupscript.db2 +-- +-- SAMPLE EXECUTION +-- After successfull execution of the script, this sample can be executed using +-- db2 -tvf reltoxmltype.db2 +-- +-- SQL STATEMENT USED: +-- CREATE +-- SELECT +-- INSERT +-- +-- OUTPUT FILE: reltoxmltype.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- CONNECT TO DATABASE + CONNECT TO sample; + +-- Insert data from the relational table into the XML tables. + INSERT INTO Customerinfo_New (Custid, Address) + (SELECT Custid, + XMLDOCUMENT( + XMLELEMENT(NAME "Address", + XMLELEMENT(NAME "Name", c.Name), + XMLELEMENT(NAME "Street", c.Street), + XMLELEMENT(NAME "City", c.City), + XMLELEMENT(NAME "Province", c.Province), + XMLELEMENT(NAME "PostalCode", c.PostalCode))) + FROM CustomerInfo_relational AS C); + +-- Insert data from the relational table into the XML tables. + INSERT INTO purchaseorder_new(PoNum, OrderDate, CustID, Status, LineItems) + (SELECT Po.PoNum, OrderDate, CustID, Status, + XMLDOCUMENT( + XMLELEMENT(NAME "itemlist", + XMLELEMENT(NAME "PartID", l.ProdID), + XMLELEMENT(NAME "Description", p.Description ), + XMLELEMENT(NAME "Quantity", l.Quantity), + XMLELEMENT(NAME "Price", p.Price))) + FROM purchaseorder_relational AS po, lineitem_relational AS l, + products_relational AS P + WHERE l.PoNum=po.PoNum AND l.ProdID=P.ProdID); + +-- Select the Purchase order. + SELECT po.PoNum, po.CustId, po.OrderDate, + XMLELEMENT(NAME "PurchaseOrder", + XMLATTRIBUTES(po.CustID AS "CustID", po.PoNum AS "PoNum", + po.OrderDate AS "OrderDate", po.Status AS "Status")), + XMLELEMENT(NAME "Address", c.Address), + XMLELEMENT(NAME "lineitems", po.LineItems) + FROM PurchaseOrder_new AS po, CustomerInfo_new AS c + WHERE po.custid = c.custid + ORDER BY po.custID; + +-- Disconnect from the database + CONNECT RESET; + diff --git a/xml/clp/simple_xmlproc.db2 b/xml/clp/simple_xmlproc.db2 new file mode 100644 index 0000000..8b9bf97 --- /dev/null +++ b/xml/clp/simple_xmlproc.db2 @@ -0,0 +1,135 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: simple_xmlproc.db2 +-- +-- SAMPLE: How to use XML type parameters in a SQL stored procedure. +-- +-- DESCRIPTION: +-- This procedure will take Customer Information ( of type XML) as input , +-- finds whether the customer with Cid in Customer Information exists in the +-- customer table , if not this will insert the customer info with that cid +-- into the customer table, and find out all the customers from the same city +-- of this customer and returns to the caller in XML format. +-- +-- SQL STATEMENTS USED: +-- CREATE PROCEDURE +-- DROP PROCEDURE +-- PREPARE +-- OPEN +-- FETCH +-- INSERT +-- SELECT +-- +-- To run this script from the CLP,issue the command +-- "db2 -td@ -vf simple_xmlproc.db2" +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- turn off the Auto-commit option +UPDATE COMMAND OPTIONS USING c OFF@ + +-- connect to the database +CONNECT TO sample@ + +-- drop the procedure Simple_XML_Proc_SQL if exists +DROP PROCEDURE Simple_XML_Proc_SQL@ + +-- create the procedure Simple_XML_Proc_SQL with XML type parameters. +CREATE PROCEDURE Simple_XML_Proc_SQL(IN inXML XML, OUT Location XML) +SPECIFIC Simple_XML_Proc_SQL +LANGUAGE SQL +BEGIN + DECLARE SQLCODE INTEGER; + DECLARE CustInfo XML; + DECLARE count INTEGER DEFAULT 0; + DECLARE city VARCHAR(100); + DECLARE custid BIGINT; + DECLARE stmt_text VARCHAR (1024); + DECLARE stmt STATEMENT; + DECLARE cur1 CURSOR WITH RETURN FOR stmt; + +-- set the parameter inXML to CustInfo + SET CustInfo = inXML; + +-- use XML function XMLEXISTS to verify whether customer with +-- Cid exists or not .... + SELECT COUNT(*) INTO count FROM customer WHERE + XMLEXISTS('$info/customerinfo[@Cid=$id]' PASSING CustInfo AS "info", cid as "id"); + +-- if doesn't exists insert into customer table with that customer id + IF (count < 1) + THEN + SELECT XMLCAST( XMLQUERY('$info/customerinfo/@Cid' passing CustInfo as "info") as BIGINT) INTO + custid FROM SYSIBM.SYSDUMMY1; + INSERT INTO customer(Cid, Info) VALUES(custid, CustInfo); + END IF; + +-- get the city of the customer into an application variable +-- using XMLQUERY + SET city = XMLCAST(XMLQUERY('$info/customerinfo//city' passing CustInfo as "info") as VARCHAR(100)); + +-- get location of the customer + SET Location = XMLQUERY('let $city := $info/customerinfo//city, + $prov := $info/customerinfo//prov-state + return {$city, $prov}' + passing CustInfo as "info"); + +-- find out all the customers from that location + SET stmt_text = 'XQUERY for $cust in + db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo/addr[city= "' || city ||'"] + order by xs:double($cust/../@Cid) + return {$cust/../@Cid}{$cust/../name}'; + PREPARE stmt FROM stmt_text; + OPEN cur1; + +-- end of the procedure +END@ + +-- calling the procedure with necessary options +call Simple_XML_Proc_SQL(xmlparse(document ' + + Kathy Smith + + 25 EastCreek + Markham + Ontario + N9C-3T6 + + 905-566-7258 + ' PRESERVE WHITESPACE),?)@ + +-- rollback the work to keep database consistent +ROLLBACK@ + +-- turn on the Auto-commit option +UPDATE COMMAND OPTIONS USING c ON@ + +CONNECT RESET@ + diff --git a/xml/clp/xmlcheckconstraint.db2 b/xml/clp/xmlcheckconstraint.db2 new file mode 100644 index 0000000..9dba870 --- /dev/null +++ b/xml/clp/xmlcheckconstraint.db2 @@ -0,0 +1,354 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: xmlcheckconstraint.db2 +-- +-- PURPOSE: The purpose of this sample is to show how to use check constraints +-- on XML column. +-- +-- USAGE SCENARIO: Super market maintains different stores for different +-- products like music players, boots, headphones. Each store sells one +-- type of product, as they would want to have separate accounting or +-- billing for their products. Super market application maintains a +-- separate table data for each product to make his work easy.Whenever +-- a customer purchases some product an entry is made in the corresponding +-- table restricting the table to a particular product entry. +-- Because there are multiple tables and if the manager wants to frequently +-- view data from multiple tables, he creates a view on top of these product +-- tables with required columns. Also, when a customer purchases 2 or +-- more products, inserting data from view has made his job easy. +-- Some times when he wants to get the customer address details, he uses +-- "customer" table from sample database to get only valid data using +-- IS VALIDATED predicate. In XML case, users can insert data into tables +-- through views. But if the user wants to select data, as indexes are +-- created on XML documents on base tables and not on views, it would be +-- best to make use of indexes on base tables rather than using +-- select on views. +-- +-- PREREQUISITE: SAMPLE database should exist before running this sample. +-- +-- On Unix: copy boots.xsd file from /sqllib +-- /samples/xml/data directory to current directory. +-- copy musicplayer.xsd file from /sqllib +-- /samples/xml/data directory to current directory. +-- On Windows: copy boots.xsd file from \sqllib\samples\ +-- xml\data directory to current directory +-- copy musicplayer.xsd file from \sqllib\ +-- samples\xml\data directory to current directory +-- +-- EXECUTION: db2 -tvf xmlcheckconstraint.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Displays tables with inserted documents. +-- One of the insert statements will fail when check constraint +-- is violated. +-- +-- OUTPUT FILE: xmlcheckconstraint.out (available in online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- CREATE VIEW +-- REGISTER XMLSCHEMA +-- COMPLETE XMLSCHEMA +-- INSERT +-- SELECT +-- DROP +-- +-- SQL/XML FUNCTIONS USED: +-- XMLVALIDATE +-- XMLPARSE +-- +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- +-- +-- SAMPLE DESCRIPTION +-- +----------------------------------------------------------------------------- +-- 1. Register XML schemas +-- +-- 2. Create tables with check constraint on XML column and insert data into +-- tables. +-- +-- 3. Show partitioning of tables by schema. +-- +-- 4. Show usage of IS VALIDATED and IS NOT VALIDATED predicates. +-- +-- 5. Shows insert statement failure when check constraint is violated. +-- +-- 6. Show check constraint and view dependency on schema. +-- +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- +-- SETUP +-- +----------------------------------------------------------------------------- + +-- Connect to SAMPLE database +CONNECT TO SAMPLE; + +----------------------------------------------------------------------------- +-- 1. Register XML schemas +----------------------------------------------------------------------------- + +-- Register XML schema "musicplayer" +REGISTER XMLSCHEMA http://posample1.org FROM musicplayer.xsd as musicplayer; +COMPLETE XMLSCHEMA musicplayer; + +-- Register XML schema "boots" +REGISTER XMLSCHEMA http://posample1.org FROM boots.xsd as boots; +COMPLETE XMLSCHEMA boots; + +----------------------------------------------------------------------------- +-- 2. Create tables with check constraint on XML column and insert data into +-- tables. +----------------------------------------------------------------------------- + +-- Create table "item" +CREATE TABLE item(custid int, xmldoc XML constraint valid_check + CHECK(xmldoc IS VALIDATED ACCORDING TO XMLSCHEMA IN (ID musicplayer, + ID boots))); + +-- Insert into table "item" +INSERT INTO item +VALUES(100, xmlvalidate(xmlparse(document + ' + + samsung + 200 watts + 5 + 3 + 2 + 400.00 + + ') ACCORDING TO XMLSCHEMA ID musicplayer)); + +INSERT INTO item +VALUES (100, XMLVALIDATE(XMLPARSE(document + ' + + adidas + 7 + 10 + 299.9 + + ') ACCORDING TO XMLSCHEMA ID boots)); + +-- Create table "musicplayer" +CREATE TABLE musicplayer (custid int, + xmldoc XML constraint valid_check1 + CHECK(xmldoc IS VALIDATED ACCORDING TO XMLSCHEMA ID musicplayer)); + +-- Insert values into "musicplayer" table. +INSERT INTO musicplayer +VALUES(100, xmlvalidate(xmlparse(document + ' + + sony + 100 watts + 5 + 3 + 4 + 200.00 + + ') ACCORDING TO XMLSCHEMA ID musicplayer)); + +-- Create table "boots" +CREATE TABLE boots (custid int, + xmldoc XML constraint valid_check2 + CHECK(xmldoc IS VALIDATED ACCORDING TO XMLSCHEMA ID boots)); + +-- Insert values into "boots" table +INSERT INTO boots +VALUES (100, XMLVALIDATE(XMLPARSE(document + ' + + nike + 7 + 10 + 99.9 + + ') ACCORDING TO XMLSCHEMA ID boots)); + +---------------------------------------------------------------------------- +-- 3. Show partitioning of tables by schema +---------------------------------------------------------------------------- + +-- Create view "view_purchases" +CREATE VIEW view_purchases(custid, xmldoc) AS +(SELECT * FROM musicplayer UNION ALL SELECT * FROM boots); + +-- Insert values into view "view_purchases" +INSERT INTO view_purchases +VALUES (1001,xmlvalidate(xmlparse(document + ' + + philips + 1000 watts + 2 + 5 + 4 + 1200.00 + ') ACCORDING TO XMLSCHEMA ID musicplayer)); + +-- Insert one more row in view "view_purchases" +INSERT INTO view_purchases +VALUES (1002, XMLVALIDATE(XMLPARSE(document + ' + + adidas + 10 + 2 + 199.9 + + ') ACCORDING TO XMLSCHEMA ID boots)); + +-- Display contents of "musicplayer" table +SELECT * FROM musicplayer ORDER BY custid; + +-- Display contents of "boots" table +SELECT * FROM boots ORDER BY custid; + +--------------------------------------------------------------------------- +-- 4. Show usage of IS VALIDATED and IS NOT VALIDATED predicates +--------------------------------------------------------------------------- + +-- Get customer addresses from "customer" table for the customers who +-- purchased boots or musicplayers +SELECT custid, info +FROM customer C, view_purchases V +WHERE V.custid = C.Cid AND info IS VALIDATED ORDER BY custid; + +-- Create table "temp_table" +CREATE TABLE temp_table (custid int, xmldoc XML); + +-- Insert values into "temp_table" +INSERT INTO temp_table +VALUES(1003, + ' + + Red Tape + 6 + 2 + 1199.9 + + '); + +-- Insert values into "temp_table" +INSERT INTO temp_table +VALUES(1004, XMLVALIDATE(XMLPARSE(document + ' + + Liberty + 6 + 2 + 900.90 + + ') ACCORDING TO XMLSCHEMA ID boots)); + +-- Create view "temp_table_details" +CREATE VIEW temp_table_details AS +(SELECT * FROM temp_table WHERE xmldoc IS NOT VALIDATED); + +-- Display contents of "temp_table_details" view +SELECT * FROM temp_table_details; + +------------------------------------------------------------------------ +-- 5. Shows insert statement failure when check constraint is violated +------------------------------------------------------------------------ + +-- Insert values into "musicplayer" table will fail as the XML document +-- is being validated against wrong schema. +INSERT INTO musicplayer +VALUES (1005, XMLVALIDATE(XMLPARSE(document + ' + + Red Tape + 6 + 2 + 1199.9 + + ') ACCORDING TO XMLSCHEMA ID boots)); + +------------------------------------------------------------------------- +-- 6. Show check constraint and view dependency on schema +------------------------------------------------------------------------- + +-- Drop "boots" schema +DROP XSROBJECT boots; + +-- Insert into "boots" table will succeed even without any validation +INSERT INTO boots +VALUES (1006, + ' + + Red Tape + 6 + 2 + 1199.9 + + '); + +-- Insert into view "view_purchases" will succeed without any validation +INSERT INTO view_purchases +VALUES (1007, + ' + philips + 1000 watts + 2 + 5 + 4 + 1200.00 + '); + +---------------------------------------------------------------------------- +-- +-- CLEANUP +-- +---------------------------------------------------------------------------- +DROP VIEW view_purchases; +DROP VIEW temp_table_details; +DROP TABLE musicplayer; +DROP TABLE boots; +DROP TABLE temp_table; +DROP XSROBJECT musicplayer; +DROP TABLE item; diff --git a/xml/clp/xmlconst.db2 b/xml/clp/xmlconst.db2 new file mode 100644 index 0000000..a6d7b06 --- /dev/null +++ b/xml/clp/xmlconst.db2 @@ -0,0 +1,161 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xmlconst.db2 +-- +-- SAMPLE: How to create UNIQUE index on XML columns +-- +-- SQL STATEMENTS USED: +-- CREATE INDEX +-- DROP INDEX +-- TERMINATE +-- +-- OUTPUT FILE: xmlconst.out (available in the online documentation) +-- +-- NOTE: Primary key, unique constraint, or unique index are not supported +-- for XML column in the Database Partitioning Feature available with +-- DB2 Enterprise Server Edition for Linux, UNIX, and Windows. +-- +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample; + +-- create table "company" +CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML); + +-- create index with unique constraint +CREATE UNIQUE INDEX empindex on company(doc) GENERATE KEY + USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE; + +-- insert row1 into table +INSERT INTO company values (1, 'doc1', xmlparse + (document ' + + Laura Brown + Finance')); + +-- insert row2 into table.This insert fails as UNIQUE voilation of id=31201 +INSERT INTO company values (1, 'doc1', xmlparse + (document ' + + Laura Brown + Finance')); +-- drop index +DROP INDEX "EMPINDEX"; + +-- drop table +DROP TABLE "COMPANY"; + +-- create table +CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML); + +-- create index using UNIQUE constraint +CREATE UNIQUE INDEX empindex on company(doc) GENERATE + KEY USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE; + +-- insert row into table. No index entry is inserted because "ABCDE" cannot +-- cast to double data type. +INSERT INTO company values (1, 'doc1', xmlparse + (document ' + + Laura Brown + Finance')); + +-- insert row2 into table.This insert succeeds because no index entry is +-- inserted since "ABCDE" cannot be cast to DOUBLE datat type. +INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura + Brown + Finance ')); + +-- drop index +DROP INDEX "EMPINDEX"; + +-- drop table +DROP table "COMPANY"; + +-- create table +CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML); + +-- create index with Varchar constraint +CREATE UNIQUE INDEX empindex1 on company(doc) + GENERATE KEY USING XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(4); + +-- insert row into table.Insert statement succeeds because length if "312" < 4 +INSERT INTO company values (1, 'doc1', xmlparse + (document 'Laura + Brown + Finance')); + +-- insert row2 into table.Insert statement fails because the length of +-- "31202" > 4 +INSERT INTO company values (1, 'doc1', xmlparse + (document 'Laura + Brown + Finance')); + +-- drop index +DROP INDEX "EMPINDEX1"; + +-- drop table + DROP TABLE "COMPANY"; + +-- create table company +CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML); + +-- insert row into table +INSERT INTO company values (1, 'doc1', xmlparse + (document 'Laura + Brown + Finance')); + +-- insert row2 into table +INSERT INTO company values (1, 'doc1', xmlparse + (document 'Laura + Brown + Finance')); + +-- create index with Varchar constraint fails because the +-- length of "31202" > 4 +CREATE UNIQUE INDEX empindex1 on company(doc) + GENERATE KEY USING XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(4); + +-- drop index +DROP index "EMPINDEX1"; + +--drop table +DROP table "COMPANY"; diff --git a/xml/clp/xmldb2batch.db2 b/xml/clp/xmldb2batch.db2 new file mode 100644 index 0000000..bb6fc14 --- /dev/null +++ b/xml/clp/xmldb2batch.db2 @@ -0,0 +1,52 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xmldb2batch.db2 +-- +-- SAMPLE: How to perform db2batch with a new datatype XML +-- +-- PREREQUISITE: Copy "xmldb2batch_in.sql" to the current working directory. +-- +-- SYSTEM COMMANDS USED: +-- DB2BATCH +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- This sample will use a flat file called xmldb2batch_in.sql as input file + +-- Invoke db2batch from command line with the following options: + +-- -d Database against which SQL statements are to be applied "SAMPLE" +-- -f Name of an input file containing SQL statements "xmldb2batch_in.sql" +-- -s Provides a summary table for each query or block of queries, +-- containing elapsed time, CPU times, the rows fetched, and the rows printed +-- -w To set maximum result set column width "400" +-- -r An output file that will contain the query results. "xmldb2batch_out.sql" + +!db2batch -d sample -f xmldb2batch_in.sql -w 400 -s on -r xmldb2batch_out.sql; diff --git a/xml/clp/xmldb2batch_in.sql b/xml/clp/xmldb2batch_in.sql new file mode 100644 index 0000000..4fd4307 --- /dev/null +++ b/xml/clp/xmldb2batch_in.sql @@ -0,0 +1,16 @@ +-- This file contains a set of SQL statements which operate on +-- the Customer information which is of XML data type. + +-- Pure SQL query that lists the information about Customers whose ids are in 1000,1002 and 2000 +SELECT Info FROM Customer WHERE Cid IN(1000,1002,2000); + +-- SQL Query with XPath that lists the information about a customer whose id is 1000 +SELECT Info FROM Customer WHERE XMLEXISTS('$info/*:customerinfo[@Cid = 1000]' PASSING BY REF Customer.Info AS "info"); + +-- XQUERY statement that lists the cities of the customers from Info column +XQUERY for $col in db2-fn:xmlcolumn("CUSTOMER.INFO") return $col//*:city; + +-- Pure SQL mixed with XQUERY statement that lists work phone number of customers from Info column +SELECT XMLSERIALIZE( content xmlquery('declare namespace po = "http://podemo.org"; for $i in $info/*:customerinfo for $p in $i/*:phone where $p/@type = "work" return {$i/*:name}{$p}'PASSING BY REF Info AS "info" RETURNING SEQUENCE) AS varchar(1000)) FROM Customer; + + diff --git a/xml/clp/xmldb2look.db2 b/xml/clp/xmldb2look.db2 new file mode 100644 index 0000000..3ca0d3b --- /dev/null +++ b/xml/clp/xmldb2look.db2 @@ -0,0 +1,77 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xmldb2look.db2 +-- +-- SAMPLE: How to perform db2look for XML datatype +-- +-- PREREQUISITES: +-- Create a directory "tempdir" in the current working directory. +-- A schema WALID, created by user NEWTON must exist. +-- +-- SQL STATEMENT USED: +-- CONNECT +-- TERMINATE +-- +-- SYSTEM COMMANDS USED: +-- DB2LOOK +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample; + +-- Generate DDL statements needed to recreate the objects in database SAMPLE +-- and Exports XSR objects into 'tempdir' directory. +-- The db2look output is sent to file xmldb2look_out1.sql +!db2look -d sample -e -xs -xdir tempdir -o xmldb2look_out1.sql; + +-- Generate the DDL statements needed to recreate the objects +-- created by user NEWTON in database SAMPLE +-- and Exports XSR objects into 'tempdir' directory +-- The db2look output is sent to file xmldb2look_out2.sql +!db2look -d sample -e -xs -xdir tempdir -u NEWTON -o xmldb2look_out2.sql; + +-- Generate the DDL statements needed to recreate the objects +-- that have schema WALID, created by user NEWTON, in database SAMPLE +-- and Exports XSR objects into 'tempdir' directory. +-- The db2look output is sent to file xmldb2look_out3.sql +!db2look -d sample -e -xs -xdir tempdir -u NEWTON -z WALID -o xmldb2look_out3.sql; + +-- Generate the DDL statements needed to recreate the objects +-- created by all users in the database SAMPLE +-- and Exports XSR objects into 'tempdir' directory. +-- The db2look output is sent to file xmldb2look_out4.sql +!db2look -d sample -e -xs -xdir tempdir -a -o xmldb2look_out4.sql; + +-- disconnect from the database +CONNECT RESET; + +TERMINATE; + diff --git a/xml/clp/xmldbafn.db2 b/xml/clp/xmldbafn.db2 new file mode 100644 index 0000000..b9891c9 --- /dev/null +++ b/xml/clp/xmldbafn.db2 @@ -0,0 +1,220 @@ +--/************************************************************************* +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************* +-- +-- SAMPLE FILE NAME: xmldbafn.db2 +-- +-- PURPOSE: To show how to use the following DBA functions to get +-- inline properties of XML documents or LOBs. +-- 1. ADMIN_IS_INLINED: Evaluates whether data (XML, LOB) is +-- inlined in a row. +-- 2. ADMIN_EST_INLINE_LENGTH: Evaluates the estimated +-- inline length of a column in order to inline the +-- data (XML, LOB) in a row. +-- +-- USAGE SCENARIO: The scenario is for a Book Store that has two types +-- of customers, retail customers and corporate customers. +-- Corporate customers do bulk purchases of books for their +-- company libraries. The store has a DBA for maintaining +-- the database, the store�s manager runs queries on different +-- tables to view the book sales. +-- +-- The store manager notifies the DBA that the queries +-- for the employee and contact details tables are running +-- very slowly. Because both the employee and contact details +-- tables were created with the �INLINE� option on XML column +-- for faster retrieval, the DBA decides to investigate the reason +-- for the performance issues. The DBA uses the ADMIN_IS_INLINED +-- function to determine if all the XML documents are +-- inlined. For the XML documents that are not inlined, the +-- DBA uses the ADMIN_EST_INLINE_LENGTH function to get the +-- maximum inline length required for the table. The DBA then +-- increases the inline length of the XML column to make the +-- documents inline. +-- +-- This sample creates the employee_inline and contact_details +-- tables and shows how to use the new DBA functions to get +-- the inline statistics of XML documents or LOBs. This +-- sample also shows how to increase query performance by +-- inlining documents or LOBs that are not already inlined. + +-- +-- PREREQUISITE: NONE +-- +-- EXECUTION: db2 -tvf xmldbafn.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Successful usage of XML DBA functions. +-- +-- OUTPUT FILE: xmldbafn.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE +-- INSERT +-- SELECT +-- ALTER +-- UPDATE +-- DROP +-- +-- XML DBA FUNCTIONS USED: +-- ADMIN_IS_INLINED +-- ADMIN_EST_INLINE_LENGTH +-- +-- ************************************************************************* +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- ************************************************************************* +-- +-- SAMPLE DESCRIPTION +-- +-- ************************************************************************* +-- This sample will demonstrate the following features +-- 1. Inlining XML documents +-- 2. Inlining CLOB data +-- *************************************************************************/ + +-- /************************************************************************* +-- Connection setup +-- **************************************************************************/ + +-- connect to the database +CONNECT TO sample; + + +--/************************************************************************ +-- Setting up tables for the sample +-- ************************************************************************/ + +-- Create table 'employee_inline' to contain the employee information. +-- The XML column in this table is created with inline length 450 based on +-- initial document's size in the table. +CREATE TABLE employee_inline (emp_ID INT NOT NULL PRIMARY KEY, + emp_details XML INLINE LENGTH 450); + +-- Insert employee details into employee_inline table +INSERT INTO employee_inline + VALUES(101, XMLPARSE(document ' + Sowmya + contractor + QA + software engineer + 20000 + ' preserve whitespace)); + +INSERT INTO employee_inline + VALUES(102, XMLPARSE(document ' + Rahul + regular + QA + software engineer + 50000 + 10-10-1934 + female + 10-20-1955 + +
+ Nagole + Chennai + Tamil Nadu +
+
+
' preserve whitespace)); + +-- Create 'contact_details' table with INLINE length 120 ON CLOB column +-- based on initial document's size in the table +CREATE TABLE contact_details (emp_ID INT, address CLOB(1K) INLINE LENGTH 120); + +-- Insert contact details of employees into contact_details table +INSERT INTO contact_details + VALUES (101, 'indra nagar,Hyderabad,AP-500050,040-32432433' ); + +INSERT INTO contact_details + VALUES (102, 'Address: street: Nagole road, 11-1234-201-405, + City:Chennai,T-nagar,4th crossa,17th line, + State:Tamil Nadu,India - 400040. + Phone:044-7643534, 044-23452345, + Mobile: 09999988888'); + +-- /************************************************************************* +-- 1. Inlining XML documents +-- *************************************************************************/ + +-- DBA checks how many documents are inlined in +-- employee_inlined table with the following query. +SELECT emp_ID, ADMIN_IS_INLINED(emp_details) as IS_INLINED + FROM employee_inline; + +-- From the output of the above query, DBA gets to know that all the documents +-- are not inlined. So, the DBA uses the ADMIN_EST_INLINE_LENGTH function to +-- calculate maximum inline length of XML documents in XML column of +-- employee_inline table +SELECT MAX(ADMIN_EST_INLINE_LENGTH(emp_details)) AS MAX_INLINE_LENGTH + FROM employee_inline; + +-- From the output of the above query, the DBA gets to know that maximum +-- estimated inline length is 780. So he alters the employee_inline table +-- with this estimated inline length of 780 for emp_details column. +-- NOTE: Once after increasing the inline length, it cannot reduced. +ALTER TABLE employee_inline ALTER COLUMN emp_details + SET INLINE LENGTH 780; + +-- DBA updates the emp_details column to inline documents with new inline length +UPDATE employee_inline SET emp_details=emp_details; + +-- DBA uses the following query to determine if all the documents are inlined +SELECT emp_ID, ADMIN_IS_INLINED(emp_details) as IS_INLINED + FROM employee_inline; + +-- /************************************************************************* +-- 2. Inlining CLOB data +-- *************************************************************************/ +-- The DBA calls the ADMIN_IS_INLINED function to +-- determine which CLOB data in the contact_details table are inlined. +SELECT emp_ID, ADMIN_IS_INLINED(address) as IS_INLINED + FROM contact_details; + +-- From the output of the above query, DBA gets to know that all the CLOB +-- data is not inlined. So, he uses the ADMIN_EST_INLINE_LENGTH function to +-- calculate maximum estimated inline length for CLOB column +-- NOTE: Once after increasing the inline length, it cannot reduced. +SELECT MAX(ADMIN_EST_INLINE_LENGTH(address)) AS EST_INLINE_LENGTH + FROM contact_details; + +-- From this output of the above query, the DBA learns that the maximum +-- estimated inline length required for the address column is 190. +-- The DBA then alters the contact_details table with this estimated +-- inline length for the address column. +ALTER TABLE contact_details ALTER address SET INLINE LENGTH 190; + +-- Update address value to get the address details inlined +UPDATE contact_details set address = address; + +-- DBA uses the following query to determine if all the +-- documents are inlined +SELECT emp_ID, ADMIN_IS_INLINED(address) AS IS_INLINED + FROM contact_details; + +-- Drop the tables +DROP TABLE employee_inline; +DROP TABLE contact_details; + +CONNECT RESET; diff --git a/xml/clp/xmldecomposition.db2 b/xml/clp/xmldecomposition.db2 new file mode 100644 index 0000000..9fcce59 --- /dev/null +++ b/xml/clp/xmldecomposition.db2 @@ -0,0 +1,241 @@ +--/************************************************************************* +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************* +-- +-- SAMPLE FILE NAME: xmldecomposition.db2 +-- +-- PURPOSE: To demonstrate annotated XML schema decomposition +-- +-- USER SCENARIO: +-- A bookstore has books for sale and the descriptive information about +-- each book is stored as an XML document. The store owner needs to store +-- these details in different relational tables with referential +-- constraints for easy retreival of data. +-- The Bookstore that has two types of customers, retail customers and +-- corporate customers. Corporate customers do bulk purchases of books +-- for their company libraries. The store has a DBA for maintaining +-- the database, the store manager runs queries on different tables +-- to view the book sales. The information about books returned by +-- customers due to damage or due to exchange with some other book +-- is stored as xml document in books_returned table. At the end of +-- the day a batch process decomposes these XML documents to update +-- the books available status with the latest information. The batch +-- process uses the DECOMPOSE XML DOCUMENTS command to decompose +-- binary or XML column data into relational tables. +-- +-- SOLUTION: +-- The store manager must have an annotated schema based on which the XML data +-- can be decomposed. Once a valid annotated schema for the instance document +-- is ready, it needs to be registered with the XML schema repository with +-- the decomposition option enabled. Also, the tables in which the data will be +-- decomposed must exist before the schema is registered. The user can +-- decompose the instance documents and store the data in the relational +-- tables using annotated XML Decomposition. +-- +-- +-- PREREQUISITE: +-- The instance documents and the annotated schema must exist in the same +-- directory as the sample. +-- Copy bookdetails.xsd, booksreturned.xsd, bookdetails.xml, +-- booksreturned.del, booksreturned1.xml, booksreturned2.xml, booksreturned3.xml, +-- setupfordecomposition.db2 and cleanupfordecomposition.db2 from directory +-- /sqllib/samples/xml/data in UNIX and +-- \sqllib\samples\xml\data in Windows to the working directory. +-- +-- EXECUTION: i) db2 -tvf setupfordecomposition.db2 (setup script +-- to create the required tables and populate them) +-- ii) db2 -tvf xmldecomposition.db2 (execute the sample) +-- iii) db2 -tvf cleanupfordecomposition.db2 (clean up +-- script to drop all the objects created) +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Decomposition of XML documents according to the dependencies +-- specified in the annotated XML schema. +-- +-- OUTPUT FILE: xmldecomposition.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- REGISTER XMLSCHEMA +-- COMPLETE XMLSCHEMA +-- DECOMPOSE XML DOCUMENT +-- DECOMPOSE XML DOCUMENTS IN +-- CREATE +-- SELECT +-- DROP +-- +-- ************************************************************************* +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- ************************************************************************* +-- +-- SAMPLE DESCRIPTION +-- +-- ************************************************************************* +-- 1. Register the annotated XML schemas. +-- 2. Decompose a single XML document using the registered XML schema. +-- 3. Decompose XML documents using the registered XML schema from +-- 3.1. An XML column. +-- 3.2. A BLOB column. +-- 4. Decompose XML documents from an XML column resulted by +-- 4.1. Join operation +-- 4.2. Union operation +-- *************************************************************************/ + +-- /************************************************************************* +-- SETUP -- execute setupfordecomposition.db2 +-- **************************************************************************/ + +-- setupfordecomposition.db2 will create required tables and populate them. + +-- Connect to the SAMPLE database +CONNECT TO sample; + +-- /************************************************************************* +-- 1. Register the annotated XML schemas. +-- *************************************************************************/ + +-- Register the XML schemas containing annotations +REGISTER XMLSCHEMA 'http://book.com/bookdetails.xsd' + FROM 'bookdetails.xsd' AS xdb.bookdetails; +REGISTER XMLSCHEMA 'http://book.com/booksreturned.xsd' + FROM 'booksreturned.xsd' AS xdb.booksreturned; + +-- Complete XML schema registration +COMPLETE XMLSCHEMA xdb.bookdetails ENABLE DECOMPOSITION; +COMPLETE XMLSCHEMA xdb.booksreturned ENABLE DECOMPOSITION; + +-- Check catalog tables for information regarding the newly registered schemas. +SELECT status, decomposition, decomposition_version + FROM SYSIBM.SYSXSROBJECTS + where XSROBJECTNAME IN ('BOOKDETAILS', 'BOOKSRETURNED'); + +-- /************************************************************************* +-- 2. Decompose a single XML document using the registered XML schema. +-- *************************************************************************/ + +-- Decompose a single XML document +DECOMPOSE XML DOCUMENT bookdetails.xml + XMLSCHEMA xdb.bookdetails + VALIDATE; + +-- check the results of the decomposition +SELECT * FROM admin.book_author WHERE authid=532; +SELECT * FROM xdb.books_avail; +SELECT isbn,chptnum,SUBSTR(chpttitle,1,15),SUBSTR(chptcontent,1,25) FROM xdb.book_contents; + +-- cleanup the data from relational tables to see +-- decomposed data. +DELETE FROM xdb.books_avail; + +-- /************************************************************************* +-- 3.1. Decompose XML documents from an XML column. +-- *************************************************************************/ + +-- Decompose XML documents +DECOMPOSE XML DOCUMENTS IN + SELECT customerID, booksreturned FROM xdb.books_returned + XMLSCHEMA xdb.booksreturned VALIDATE + MESSAGES errorreport.xml; + +-- check the results of the decomposition +SELECT * FROM xdb.books_avail; + +-- cleanup the data from relational tables to see +-- decomposed data. +DELETE FROM xdb.books_avail; + +-- /************************************************************************* +-- 3.2. Decompose XML documents from a BLOB column. +-- *************************************************************************/ + +-- Decompose XML documents +DECOMPOSE XML DOCUMENTS IN + SELECT supplierID, booksinfo from xdb.books_received_BLOB + XMLSCHEMA xdb.booksreturned VALIDATE + MESSAGES errorreport.xml; + +-- check the results of the decomposition +SELECT * FROM xdb.books_avail; + +-- cleanup the data from relational tables to see +-- decomposed data. +DELETE FROM xdb.books_avail; + +-- /************************************************************************* +-- 4.1. Decompose XML documents from an XML column resulted by Join operation. +-- *************************************************************************/ + +DECOMPOSE XML DOCUMENTS IN + SELECT id, data FROM( + SELECT br.customerID as id, br.booksreturned AS info + FROM xdb.books_returned as br,xdb.books_received as bc + WHERE XMLEXISTS('$bi/books/book[@isbn] = $bid/books/book[@isbn]' + PASSING br.booksreturned as "bi", + bc.booksinfo as "bid")) AS temp(id,data) + XMLSCHEMA xdb.booksreturned VALIDATE + CONTINUE_ON_ERROR + MESSAGES errorreport.xml; + +-- check the results of the decomposition +SELECT * FROM xdb.books_avail; + +-- cleanup the data from relational tables to see +-- decomposed data. +DELETE FROM xdb.books_avail; + +-- /************************************************************************* +-- 4.2. Decompose XML documents from an XML column resulted by Union operation. +-- *************************************************************************/ + +DECOMPOSE XML DOCUMENTS IN + SELECT id, data FROM( + SELECT customerID as cid, booksreturned AS info + FROM xdb.books_returned + WHERE XMLEXISTS('$bk/books/book[author="Carl"]' + PASSING booksreturned AS "bk") + UNION ALL + SELECT supplierID as sid, booksinfo AS books + FROM xdb.books_received + WHERE XMLEXISTS('$br/books/book[author="Carl"]' + PASSING booksinfo AS "br")) AS temp(id,data) + XMLSCHEMA xdb.booksreturned VALIDATE + CONTINUE_ON_ERROR + MESSAGES errorreport.xml; + +-- check the results of the decomposition +SELECT * FROM xdb.books_avail; + +-- cleanup the data from relational tables to see +-- decomposed data. +DELETE FROM xdb.books_avail; + +-- /************************************************************************* +-- CLEANUP -- execute cleanupfordecomposition.db2 +-- **************************************************************************/ + +-- Commit the work and reset the connection +COMMIT; +CONNECT RESET; + diff --git a/xml/clp/xmlindex.db2 b/xml/clp/xmlindex.db2 new file mode 100644 index 0000000..8af1edf --- /dev/null +++ b/xml/clp/xmlindex.db2 @@ -0,0 +1,169 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xmlindex.db2 +-- +-- SAMPLE: How to create an index on XML columns in different ways +-- +-- SQL STATEMENTS USED: +-- CREATE INDEX +-- DROP INDEX +-- TERMINATE +-- +-- OUTPUT FILE: xmlindex.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- +-- connect to sample +CONNECT TO sample; + +-- create TABLE called company +CREATE TABLE company(ID int, docname VARCHAR(20), doc XML); + +-- insert row1 into TABLE +INSERT INTO company values(1, 'doc1', xmlparse + (document ' + LauraBrown + Finance + ')); + +-- insert row2 into TABLE +INSERT INTO company values(2, 'doc2', xmlparse + (document ' + ChrisMurphy + Marketing + NicoleMurphy + Sales')); + + +-- create index on an attribute +CREATE INDEX empindex1 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@*' AS SQL VARCHAR(15) ; + +-- example query using above index +XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')/company/emp + [@id='42366'] return $i/name; + +-- create index with self or descendent forward axis +CREATE INDEX empindex2 on company(doc) GENERATE KEY USING + XMLPATTERN '//@salary' AS SQL DOUBLE; + +-- example query using above index +XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')/company/emp + [@salary > 35000] return {$i/@salary} ; + +-- create index on a text node +CREATE INDEX empindex3 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/dept/text()' AS SQL VARCHAR(30); +-- example query using above index +XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')/company/ + emp[dept/text()='Finance' or dept/text()='Marketing'] return $i/name; + + +-- create index when 2 paths are qualified by an xml pattern +CREATE INDEX empindex4 on company(doc) GENERATE KEY USING + XMLPATTERN '//@id' AS SQL VARCHAR(25); +-- example query using above index +XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')/company/ + emp[@id='31201'] return $i/name; +XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')/company/emp/ + dept[@id='K55'] return $i/name; + +-- create index with namespace +CREATE index empindex5 on company(doc) GENERATE KEY USING + XMLPATTERN 'declare default element namespace + "http://www.mycompany.com/";declare namespace + m="http://www.mycompanyname.com/";/company/emp/@m:id' + AS SQL VARCHAR(30); + +-- create indexes with same XMLPATTERN but with different data types +CREATE INDEX empindex6 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(10); +CREATE INDEX empindex7 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@id' AS SQL DOUBLE; + + +-- create index to use in joins (Anding) +CREATE INDEX empindex8 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/name/last' AS SQL VARCHAR(100); +CREATE INDEX deptindex on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/dept/text()' AS SQL VARCHAR(30); + +-- example query using above index +XQuery for $i in db2-fn:xmlcolumn('COMPANY.DOC')/company + /emp[name/last='Murphy' and dept/text()='Sales']return $i/name/last; + +-- create indexes to use in joins ( Anding or Oring ) +CREATE INDEX empindex9 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@salary' AS SQL DOUBLE; +CREATE INDEX empindex10 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/dept' AS SQL VARCHAR(25); +CREATE INDEX empindex11 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/name/last' AS SQL VARCHAR(25); +-- example query which will use all the above 3 index (Anding and Oring) +XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')/company/emp[xs:integer(@salary) > 50000 and dept="Finance"]/name[last="Brown"] + return $i/last; + +-- create index with Date Data type +CREATE INDEX empindex12 on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@DOB' as SQL DATE; + +-- example query which uses above index +XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')/company/emp + [@DOB < '11-11-78'] return $i/name; + +-- create index on comment node +CREATE INDEX empindex13 on company(doc) GENERATE KEY USING + XMLPATTERN '/company//comment()' AS SQL VARCHAR HASHED; +-- example query which uses above query +XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')/company/emp[comment() + =' good ']return $i/name; + +-- drop indexes +DROP index "EMPINDEX1"; +DROP index "EMPINDEX2"; +DROP index "EMPINDEX3"; +DROP index "EMPINDEX4"; +DROP index "EMPINDEX5"; +DROP index "EMPINDEX6"; +DROP index "EMPINDEX7"; +DROP index "EMPINDEX8"; +DROP index "DEPTINDEX"; +drop index "EMPINDEX9"; +drop index "EMPINDEX10"; +drop index "EMPINDEX11"; +DROP index "EMPINDEX12"; +DROP index "EMPINDEX13"; + +-- drop the TABLE +DROP TABLE "COMPANY"; + + diff --git a/xml/clp/xmlindgtt.db2 b/xml/clp/xmlindgtt.db2 new file mode 100644 index 0000000..c27e45c --- /dev/null +++ b/xml/clp/xmlindgtt.db2 @@ -0,0 +1,277 @@ +------------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +------------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xmlindgtt.db2 +-- +-- SAMPLE: +-- The sample demonstrates the support for XML in Declare global +-- temporary table (DGTT). +-- +-- PREREQUISITE: +-- 1)Sample database is setup on the machine. +-- +-- Note: Use following command to execute the sample: +-- db2 -td@ -vf xmlindgtt.db2 +-- +-- USAGE SCENARIO: +-- The Scenario is for a Book Store that has two types of customers; +-- retail customers and corporate customers. These customers can either +-- purchase the books online or from the book store. +-- +-- When an online transaction is made by the customers, the store +-- tracks all the orders placed by the customer in a transaction such as +-- adding a book to the cart, deleting a book from the cart or updating +-- the details about the items in the cart. The order details of each book +-- including 'name', 'quantity', and 'price' is stored as an XML document. +-- To store these intermediate transaction details, the store uses a +-- temporary table (DGTT). +-- +-- At the end of the transaction, the orders for different books placed by +-- the customer in a transaction are collected from the temporary table and +-- stored in a static table 'purchase_orders' as a single entity, an XML +-- document. +-- +-- At the end of the day, the store will access the records in the +-- 'purchase_orders' table and deliver those products whose status is +-- 'Unshipped'. +-- +-- SQL STATEMENTS USED: +-- 1) DECLARE GLOBAL TEMPORARY TABLE +-- 2) INSERT INTO TempTable VALUES ('') +-- 3) CREATE INDEX +-- 4) UPDATE TempTable SET XMLColumn = ... +-- 5) DELETE FROM TempTable WHERE XMLEXIST ... +-- 6) DROP +-- +------------------------------------------------------------------------------- + +-- Connect to sample database + +CONNECT TO sample@ + + +-- The book store decides to create a table which is partitioned for every +-- quarter to store the orders placed by the customer. Each partition will +-- be placed in a separate table space. Four table spaces ('Tbspace1', +-- 'Tbspace2', 'Tbspace3' and 'Tbspace4') are created to contain relational +-- data from the new 'purchase_orders' table. Four table spaces ('Ltbspace1', +-- 'Ltbspace2', 'Ltbspace3' and 'Ltbspace4') are created to contain long +-- data from the new 'purchase_orders' table. + +CREATE BUFFERPOOL common_Buffer IMMEDIATE SIZE 1000 AUTOMATIC PAGESIZE 4K@ + +CREATE TABLESPACE Tbspace1 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont1' 2000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Tbspace2 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont2' 2000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Tbspace3 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont3' 2000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Tbspace4 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont4' 2000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ + + +-- The purchase order information is an XML document. To store XML data, a +-- large tablespace will be used. Hence, four large table spaces are created +-- to store XML data for these partitions. + +CREATE TABLESPACE Ltbspace1 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lcont1' 2000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Ltbspace2 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lcont2' 2000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Ltbspace3 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lcont3' 2000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Ltbspace4 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lcont4' 2000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ + + +-- When an online transaction is made, all the orders placed by the customer +-- in the transaction are placed in a temporary table. A user temporary table +-- space is created to contain this temporary table. + +CREATE USER TEMPORARY TABLESPACE temp_tbsp@ + + +-- Create 'purchase_orders' table partitioned by 'orderDate' for every quarter. +-- Data for this table will be stored in tablespaces created above ('Tbspace1' +-- ,'Tbspace2','Tbspace3','Tbspace4'). Long data will be stored in large +-- tablespaces created above ('Ltbspace1', 'Ltbspace2', 'Ltbspace3', 'Ltbspace4'). + +CREATE TABLE purchase_orders ( id INT NOT NULL, + status VARCHAR(10), + orderDate DATE, + customerID INT, + pOrder XML) + PARTITION BY RANGE (orderDate) + (STARTING FROM '2009-01-01' ENDING '2009-03-31' IN Tbspace1 LONG IN Ltbspace1, + ENDING '2009-06-30' IN Tbspace2 LONG IN Ltbspace2, + ENDING '2009-09-30' IN Tbspace3 LONG IN Ltbspace3, + ENDING '2009-12-31' IN Tbspace4 LONG IN Ltbspace4)@ + + +-- Create a temporary table (DGTT) to store the intermediate information about +-- the orders placed by the customer in a transaction. + +DECLARE GLOBAL TEMPORARY TABLE pOrderInter(id INT, + orderDate DATE, + customerID INT, + prodID INT, + partPOrder XML) + ON COMMIT DELETE ROWS IN temp_tbsp@ + + +-- Create an index on the items purchased by the customer. This will help +-- retrieve details about the purchase order faster. + +CREATE INDEX SESSION.nIndex ON SESSION.pOrderInter(partPOrder) + GENERATE KEY USING XMLPATTERN '/Book/name' AS SQL VARCHAR(60)@ + + +-- A customer makes an online transaction, were he places order for three +-- books, by adding the three books to the cart. The details about these +-- books added to the cart are inserted into the temporary table +-- 'pOrderInter'. Customer updates the quantity of the magazine 'The week' +-- which he had already added to the cart and decides to remove a book +-- 'Crisis' from the cart. The update and delete from the cart by the +-- customer is reflected in the DGTT. +-- These CRUD operations are placed in a ATOMIC block. ATOMIC block ensures +-- that, if an error occurs in the compound statement, all SQL statements +-- in the compound statement will be rolled back, and any SQL statements +-- in the compound statement are not processed. + +UPDATE COMMAND OPTIONS USING c OFF@ + +BEGIN ATOMIC + + INSERT INTO SESSION.pOrderInter VALUES (3000,'2009-01-10',1900,100, + ' + 100 + DB2 understanding security + 1 + 49.99 + '); + + INSERT INTO SESSION.pOrderInter VALUES (3000,'2009-01-10',1900,2002, + ' + 2002 + Crisis + 1 + 9.99 + '); + + INSERT INTO SESSION.pOrderInter VALUES (3000,'2009-01-10',1900,1001, + ' + 1001 + The week + 3 + 2.99 + '); + + UPDATE SESSION.pOrderInter SET partPOrder = + xmlquery('transform + copy $po := $order + modify do replace value of $po/Book/quantity with "4" + return $po' + PASSING partPOrder AS "order") WHERE + XMLEXISTS ('$p/Book[partid=100]' PASSING partPOrder AS "p"); + + DELETE FROM SESSION.pOrderInter + WHERE XMLEXISTS ('$p/Book[partid=2002]' PASSING partPOrder AS "p"); + +END@ + + +-- Once the transaction is complete, the products added to the cart by the +-- customer as in the temporary table 'pOrderInter' are collected and single +-- XML document is inserted into 'purchase_orders' for the transaction. + +SELECT * FROM SESSION.pOrderInter ORDER BY prodID@ + +INSERT INTO purchase_orders + (SELECT p.id, 'Unshipped', p.orderDate, p.customerID, + XMLDOCUMENT( XMLElement(NAME "PurchaseOrder", + XMLAgg( XMLElement(NAME "Books",p.partPOrder OPTION NULL ON NULL) ORDER BY p.prodID) + OPTION NULL ON NULL)) + FROM SESSION.pOrderInter AS p + GROUP BY p.id, p.customerID, p.orderDate)@ + +COMMIT@ + +UPDATE COMMAND OPTIONS USING c ON@ + + +-- At the end of the day, the store delivers the purchase orders whose +-- status='Unshipped' from the 'purchase_orders' table. +-- Once the store delivers these purchase orders, the status is set +-- to 'Shipped' + +SELECT * FROM purchase_orders + WHERE status = 'Unshipped'@ + +UPDATE purchase_orders SET status = 'Shipped' + WHERE status = 'Unshipped'@ + + +-- Clean-Up Script +DROP TABLE purchase_orders@ + +-- DROP TABLESPACE command fails since 'SESSION.pOrderInter@' still exists. +DROP TABLESPACE temp_tbsp@ + +DROP TABLESPACE Tbspace1@ +DROP TABLESPACE Tbspace2@ +DROP TABLESPACE Tbspace3@ +DROP TABLESPACE Tbspace4@ +DROP TABLESPACE Ltbspace1@ +DROP TABLESPACE Ltbspace2@ +DROP TABLESPACE Ltbspace3@ +DROP TABLESPACE Ltbspace4@ + +DROP BUFFERPOOL common_Buffer@ + +-- Close connection to the sample database +CONNECT RESET@ + +-- Connect to sample database +CONNECT TO sample@ + +-- SELECT command fails since closing the connection drops all +-- temporary database objects. +SELECT * FROM SESSION.pOrderInter@ + +-- DROP TABLESPACE command succeeds since closing the connection drops all +-- temporary database objects. +DROP TABLESPACE temp_tbsp@ + +-- Close connection to the sample database +CONNECT RESET@ + + + + + + diff --git a/xml/clp/xmlinsert.db2 b/xml/clp/xmlinsert.db2 new file mode 100644 index 0000000..06a72c8 --- /dev/null +++ b/xml/clp/xmlinsert.db2 @@ -0,0 +1,238 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xmlinsert.db2 +-- +-- SAMPLE: This sample shows how to insert XML documents into a column of +-- XML datatype of a table +-- +-- SQL STATEMENTS USED: +-- SELECT +-- INSERT +-- DELETE +-- DROP +-- +-- XMLPARSE +-- XMLSERIALIZE +-- XMLVALIDATE +-- XMLCAST +-- XMLELEMENT +-- XMLATTRIBUTES +-- +-- OUTPUT FILE: xmlinsert.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to sample +CONNECT TO sample; + +-- create table 'oldcustomer' having an XML column +CREATE TABLE oldcustomer(ocid integer, firstname varchar(15), lastname + varchar(15), addr varchar(300), information XML); + +-- insert XML values into the table 'oldcustomer' table. + +-- insert a row into table +INSERT INTO oldcustomer + VALUES(1007, 'Raghu', 'nandan', ' + karnatakabangalore', + XMLPARSE(document'
24 gulmargbangalore + karnataka
' + preserve whitespace)); + +-- insert a row into table +INSERT INTO oldcustomer + VALUES(1008, 'Rama', 'murthy', ' + karnatakabelgaum', + XMLPARSE(document'
12 gandhimarg + belgaumkarnataka
+
'preserve whitespace)); + +-- insert a row into table +INSERT INTO oldcustomer + VALUES(1009, 'Rahul', 'kumar', 'Rahul25Markham + OntarioN9C-3T6 + 905-555-7258 + ',XMLPARSE(document '
25 Westend + MarkhamOntario +
'preserve whitespace)); + +-- insert a row into table +INSERT INTO oldcustomer + VALUES(1010, 'Sweta', 'Priya', ' + karnatakakolar', + XMLPARSE(document'
56 hillview + kolarkarnataka
+
'preserve whitespace)); + +--------------------------------------------------------------------------- +-- a simple INSERT + +-- display the current contents of the 'customer' table +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1006; + +INSERT INTO customer(cid, info) + VALUES(1006, XMLPARSE(document ' + divya' preserve whitespace)); + +-- display the results after inserting a row +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1006; + +---------------------------------------------------------------------------- +-- insert where the source is 'from another XML column' + +-- display the contents of the 'customer' table +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1007; + +-- display the contents of the 'oldcustomer' table +SELECT ocid, XMLSERIALIZE(information as varchar(600)) + FROM oldcustomer + WHERE ocid = 1007; + +INSERT INTO customer(cid, info) + SELECT ocid, information + FROM oldcustomer p + WHERE p.ocid = 1007; + +-- display the contents after insertion +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1007; + +--------------------------------------------------------------------------- +-- insert where the source is 'from another string column' + +-- display the contents of the 'customer' table +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +-- display the contents of the 'oldcustomer' table +SELECT ocid, XMLSERIALIZE(information as varchar(600)) + FROM oldcustomer + WHERE ocid = 1008; + +INSERT INTO customer(cid, info) + SELECT ocid, XMLPARSE(document addr preserve whitespace) + FROM oldcustomer p + WHERE p.ocid = 1008; + +-- display the contents of the 'customer' table (after insertion) +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +---------------------------------------------------------------------------- +-- insert with validation where source is of type varchar + + +-- display the contents of the 'customer' table +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1009; + +-- display the contents of the 'oldcustomer' table +SELECT ocid, XMLSERIALIZE(information as varchar(600)) + FROM oldcustomer + WHERE ocid = 1009; + +INSERT INTO customer(cid, info) + SELECT ocid, XMLVALIDATE(XMLPARSE(document addr preserve whitespace) + according to XMLSCHEMA id customer) + FROM oldcustomer p + WHERE p.ocid = 1009; + +-- display the contents of the 'customer' table (after insertion) +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1009; + +--------------------------------------------------------------------------- +-- insert where source is 'a XML funtion' + +-- display the contents of the 'customer' table +SELECT cid,XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1010; + +-- display the contents of the 'oldcustomer' table +SELECT ocid,XMLSERIALIZE(information as varchar(600)) + FROM oldcustomer + WHERE ocid = 1010; + +INSERT INTO customer(cid, info) + SELECT ocid, XMLPARSE(document XMLSERIALIZE(content + XMLELEMENT(NAME"oldCustomer", XMLATTRIBUTES(s.ocid, + s.firstname||' '||s.lastname AS "name")) + as varchar(200)) strip whitespace) + FROM oldcustomer s WHERE s.ocid = 1010 ; + +-- display the contents of the 'customer' table (after insertion) +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1010; + +---------------------------------------------------------------------------- + +-- insert where the source is not as per schema +INSERT INTO customer(cid, info) + VALUES(1011, 'arjun'); + +-- insertion will fail in this case + +--------------------------------------------------------------------------- + +-- insert where source is typecast to XML +INSERT INTO customer(cid, info) VALUES(1031, XMLCAST(XMLPARSE(document + '
+ 56 hillviewkolarkarnataka +
' preserve whitespace) as XML)); + +-- display the contents of the 'customer' table (after insertion) +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1031; + +--------------------------------------------------------------------------- + +-- cleanup +DROP TABLE oldcustomer; + +DELETE FROM customer WHERE cid >= 1006; diff --git a/xml/clp/xmlintegrate.db2 b/xml/clp/xmlintegrate.db2 new file mode 100644 index 0000000..f73fd78 --- /dev/null +++ b/xml/clp/xmlintegrate.db2 @@ -0,0 +1,243 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: xmlintegrate.db2 +-- +-- PURPOSE: To show how to use XMLROW and XMLGROUP functions to publish +-- relational information as XML. +-- To show XMLQuery default passing mechanism. +-- To show default column specification for XMLTABLE. +-- +-- USAGE SCENARIO: The super marker manager maintains a database to store +-- all customer's addresses in a relational table called +-- "addr" so that whenever a customer places an order for +-- any item, he can use this "addr" table to deliver the +-- item. As the number of customers grew year after +-- year,there was a need to change the table structure +-- to have one single XML column for address and maintain +-- the data in a new table called "customerinfo_new". +-- +-- PREREQUISITE: NONE +-- +-- EXECUTION: db2 -tvf xmlintegrate.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Shows comparison of XML documents created using different +-- SQLXML functions and using XMLROW, XMLGROUP functions +-- +-- OUTPUT FILE: xmlintegrate.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT +-- SELECT +-- +-- SQL/XML FUNCTIONS USED: +-- XMLROW +-- XMLGROUP +-- XMLDOCUMENT +-- XMLELEMENT +-- XMLCONCAT +-- XMLATTRIBUTES +-- +--------------------------------------------------------------------------- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- +-------------------------------------------------------------------------- +-- +-- SAMPLE DESCRIPTION +-- +-------------------------------------------------------------------------- +-- +-- 1. Shows comparison of publishing XML documents +-- using different SQL/XML functions and XMLROW function. +-- +-- 1.1 Element centric mapping comparison. +-- +-- 1.2 Attribute centric mapping comparison. +-- +-- 2. Shows the comparison of publishing XML documents using +-- different SQL/XML publishing functions and XMLGROUP function +-- +-- 3. Shows XMLQuery default parameter passing mechanism. +-- +-- 4. Shows default column specification for XMLTABLE. +-- +------------------------------------------------------------------------- +-- +------------------------------------------------------------------------- +-- SETUP +------------------------------------------------------------------------- +-- Connect to sample database +CONNECT TO SAMPLE; +-- + +-- Create table "addr" +CREATE TABLE addr (custid int, + name varchar(20), + street varchar(20), + city varchar(10), + province varchar(50), + postalcode BIGINT); + +-- Create table "customerinfo_new" +CREATE TABLE customerinfo_new (custid smallint, address xml); + +------------------------------------------------------------------------- +-- +-- 1. Shows comparison of publishing XML documents using different +-- SQL/XML functions and XMLROW function. +-- +------------------------------------------------------------------------- + +------------------------------------------------------------------------- +-- +-- 1.1 Element centric mapping comparison +-- +------------------------------------------------------------------------- + +-- Insert values into "addr" table +INSERT INTO addr +VALUES(1000, 'madhavi', 'madivala', 'Bangalore', 'karnataka', 560004); + +-- Insert values into "customerinfo_new" table and Create an XML +-- document address with name, street, city, postal code columns +-- in the "addr" table and display it along with custid details +INSERT INTO customerinfo_new (Custid, Address) +SELECT Custid, XMLDOCUMENT( + XMLElement(NAME "row", XMLCONCAT( + XMLElement(NAME "NAME", name OPTION NULL ON NULL), + XMLElement(NAME "STREET", street OPTION NULL ON NULL), + XMLElement(NAME "CITY", city OPTION NULL ON NULL), + XMLElement(NAME "PROVINCE", province OPTION NULL ON NULL), + XMLElement(NAME "POSTALCODE", postalcode OPTION NULL ON NULL)) + OPTION NULL ON NULL ) + ) FROM addr; + +-- Create an XML document using XMLROW function with name, street +-- city, postalcode columns of "addr" table and insert into Address column +-- of "customerinfo_new" table +INSERT INTO customerinfo_new (Custid, Address) +(SELECT Custid, XMLROW(C.name, C.street, C.city, C.province,C.postalcode) + FROM addr C); + +-- Check whether XML document created using SQL/XML publishing functions +-- and the one created with XMLROW are same. +SELECT * FROM customerinfo_new; + +-------------------------------------------------------------------------- +-- +-- 1.2 Attribute centric mapping comparison +-- +-------------------------------------------------------------------------- + +-- Attribute centric mapping using CASE expressions in DB2 9 +SELECT Custid, CASE WHEN C.name is NULL and C.street is NULL + and C.City is NULL and C.province is NULL + and C.postalcode is NULL + THEN CAST(NULL as XML) + ELSE XMLDOCUMENT(XMLElement(name "row", + XMLAttributes(C.name, C.street,C.city, + C.province, C.postalcode))) + END +FROM addr C; + +-- Attribute centric mapping using XMLROW function +SELECT Custid, XMLROW(C.name, C.street, C.city, C.province, + C.postalcode OPTION AS ATTRIBUTES) +FROM addr as C; + +---------------------------------------------------------------------------- +-- +-- 2. Shows the comparison of publishing XML documents using different +-- SQL/XML publishing functions and XMLGROUP function +-- +---------------------------------------------------------------------------- + +-- Get all purchase orders made by a particular customer as one single XML +-- document +SELECT XMLDOCUMENT( + XMLElement(NAME "rowset", + XMLAgg(XMLElement(NAME "row", + XMLElement(NAME "orderdate", p.orderdate OPTION NULL ON NULL), + XMLElement(NAME "porder", p.porder OPTION NULL ON NULL) + OPTION NULL ON NULL)ORDER BY p.orderdate) + OPTION NULL ON NULL)) +FROM purchaseorder p, customer c +WHERE p.custid=c.Cid; + +-- Doing the same as above using XMLGROUP function. +SELECT XMLGroup(p.orderdate, p.porder ORDER BY p.orderdate) +FROM purchaseorder p, customer c +WHERE p.custid=c.Cid; + +---------------------------------------------------------------------------- +-- +-- 3. Shows XMLQuery default parameter passing mechanism +-- +---------------------------------------------------------------------------- + +-- Create employees table +CREATE TABLE employees (empno int, + lastname varchar(20), + firstname varchar(20), + workdept varchar(20), + phoneno varchar(20), + hiredate DATE); + +-- Insert values into employees table. +INSERT INTO employees +VALUES (100, 'latha', 'suma', 'Informix', '5114', '03/01/2006'); + +-- Create an Emp element with 2 attributes lastname and first name, also create +-- elements with employee's department, phone number, hire date and display it. +SELECT empno, XMLQuery(' + {$WORKDEPT} + {$PHONENO} + {$HIREDATE} + ') +FROM employees ORDER BY empno desc; + +----------------------------------------------------------------------------- +-- +-- 4. Shows the default column specification of XMLTABLE +-- +----------------------------------------------------------------------------- + +-- Lists all the customer phone numbers +XQuery for $plist in db2-fn:sqlquery("SELECT X.phone FROM customer, + XMLTABLE('$INFO/customerinfo/phone') AS X(phone)") + order by $plist/@type, $plist/text() + return $plist; +---------------------------------------------------------------------------- +-- +-- CLEANUP +-- +---------------------------------------------------------------------------- +DROP TABLE addr; +DROP TABLE customerinfo_new; +DROP TABLE employees; diff --git a/xml/clp/xmlload.db2 b/xml/clp/xmlload.db2 new file mode 100644 index 0000000..ea326e6 --- /dev/null +++ b/xml/clp/xmlload.db2 @@ -0,0 +1,154 @@ +--/************************************************************************* +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************* +-- +-- SAMPLE FILE NAME: xmlload.db2 +-- +-- PURPOSE: To demonstrate how to load XML content into a table using +-- different options of LOAD command. +-- +-- USAGE SCENARIO: A store manager wants to load bulk of purchase order +-- documents into an XML column of a table. +-- +-- PREREQUISITES: +-- The data files and XML documents must exist in the same +-- directory as the sample. Copy loaddata1.del and loaddata2.del from +-- directory /sqllib/samples/xml/data in UNIX and +-- \sqllib\samples\xml\data in Windows to the working directory. +-- Create a new directory "xmldatadir" in the working directory and copy +-- loadfile1.xml and loadfile2.xml from directory +-- /sqllib/samples/xml/data in UNIX and +-- \sqllib\samples\xml\data in Windows to the newly created +-- xmldatadir directory and to the current working directory. +-- +-- EXECUTION: db2 -tvf xmlload.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Successful loading of XML purchase orders. +-- +-- OUTPUT FILE: xmlload.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- LOAD +-- INSERT +-- CREATE +-- DROP +-- +-- ************************************************************************* +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- ************************************************************************* +-- +-- SAMPLE DESCRIPTION +-- +-- ************************************************************************* +-- 1. LOAD data into the table without any validation clause. +-- 2. LOAD data into the table using XMLVALIDATE USING XDS clause. +-- 3. LOAD data into the table using XMLVALIDATE USING SCHEMA clause. +-- 4. LOAD data into the table from cursor. +-- *************************************************************************/ + +-- /************************************************************************* +-- SETUP +-- **************************************************************************/ + +-- Connect to the sample database +CONNECT TO sample; + +-- Create a table POtable with an XML column "porder" to load XML data +CREATE TABLE POtable(POid INT NOT NULL PRIMARY KEY,porder XML); + +-- ************************************************************************* +-- 1. LOAD data into the table without any validation clause +-- ************************************************************************* + +-- Define loaddata1.del without any schema specifications +-- Load the data from loaddata1.del without validating clause +LOAD FROM loaddata1.del of del MESSAGES loadmsg.txt INSERT into POtable; + +-- select the data from the table to show that data is inserted successfully +SELECT count(*) FROM potable; + +-- ************************************************************************* +-- 2. LOAD data into the table using XMLVALIDATE USING XDS clause +-- ************************************************************************* + +-- Define loaddata2.del with schema attributes +-- Load the data to the table using XMLVALIDATE USING XDS clause +LOAD FROM loaddata2.del OF DEL XML FROM xmldatadir + MODIFIED BY XMLCHAR + XMLVALIDATE USING XDS + DEFAULT porder + IGNORE (customer, supplier) + MAP ( (product,porder)) + MESSAGES loadmsg.txt + INSERT INTO POtable; + +-- select the data from the table to show that data is inserted successfully +SELECT count(*) FROM POtable; + +-- delete the inserted data from POtable +DELETE FROM POtable; + +-- ************************************************************************* +-- 3. LOAD data into the table using XMLVALIDATE USING SCHEMA clause. +-- ************************************************************************* + +-- LOAD the data to the table using XMLVALIDATE USING SCHEMA clause + LOAD FROM loaddata2.del OF DEL XML FROM xmldatadir + MODIFIED BY XMLCHAR + XMLVALIDATE using SCHEMA porder + MESSAGES loadmsg.txt + INSERT INTO POtable; + +-- Select the data from the table to show that data is inserted successfully +SELECT count(*) FROM POtable; + +-- delete the inserted data from POtable +DELETE FROM POtable; + +-- ************************************************************************* +-- 4. LOAD data into the table from cursor. +-- ************************************************************************* + +-- Load the data from cursor +DECLARE C1 CURSOR FOR SELECT count(*)porder FROM PurchaseOrder; +LOAD FROM C1 of CURSOR MESSAGES loadmsg.txt INSERT INTO POtable; + +-- Select the data from the table to show that data is inserted successfully +SELECT count(*) FROM POtable; + +-- /************************************************************************* +-- CLEANUP +-- **************************************************************************/ + +-- delete the inserted data from POtable +DELETE FROM POtable; + +-- drop the table POtable +DROP TABLE POtable; + +CONNECT RESET; +TERMINATE; diff --git a/xml/clp/xmlmdc.db2 b/xml/clp/xmlmdc.db2 new file mode 100644 index 0000000..09bf50d --- /dev/null +++ b/xml/clp/xmlmdc.db2 @@ -0,0 +1,404 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: xmlmdc.db2 +-- +-- PURPOSE: This sample demonstrates the following features +-- 1. XML data type column in MDC tables. +-- 2. Faster insert and faster delete options support in MDC tables +-- having XML columns. +-- +-- USAGE SCENARIO: The scenario is for a Book Store that has two types +-- of customers, retail customers and corporate customers. +-- Corporate customers do bulk purchases of books for their company +-- libraries. The store's DBA maintains the database, +-- the store manager runs queries on different tables to view +-- the book sales. +-- +-- The store expands and opens four more branches +-- in the city, all the books are spread across different branches. +-- The store manager complains to the DBA that queries to get details +-- like availability of a particular book by a particular author +-- in a particular branch are very slow. +-- +-- The DBA decides to improve the query performance by converting a +-- non-MDC table, for books available in different branches of the +-- store, into an MDC table. To further improve the query performace, +-- the DBA decides to create partition on the MDC table based on +-- the published date of the book. By creating an MDC table, the query +-- performance increases and the sales clerk can do faster inserts into +-- this table when he receives books from different suppliers. He can +-- also do faster deletes when he wants to delete a particular type of +-- book due to low sales in a particular branch for that category of +-- book in that location. +-- +-- PREREQUISITE: The SAMPLE database should exist before running this script. +-- +-- EXECUTION: db2 -tvf xmlmdc.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Successful execution of all the queries. +-- +-- OUTPUT FILE: xmlmdc.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT +-- DROP +-- SQL/XML FUNCTIONS USED: +-- XMLEXISTS +-- +----------------------------------------------------------------------------- +-- +-- SAMPLE DESCRIPTION +-- +----------------------------------------------------------------------------- +-- This sample demonstrates : +-- 1. Moving data from a non-MDC table to an MDC table. +-- 2. MDC table with partition. +-- 3. Faster inserts into MDC table containing an XML column. +-- 4. Faster delete on MDC table containing an XML column. +-- 5. Exploiting block indexes and XML indexes in a query. +----------------------------------------------------------------------------- +-- +-- SETUP +-- +----------------------------------------------------------------------------- + +-- Connect to sample +CONNECT TO SAMPLE; + +----------------------------------------------------------------------------- +-- 1. Moving data from a non-MDC table to an MDC table +----------------------------------------------------------------------------- + +-- Create schema testschema +CREATE SCHEMA testschema; + +----------------------------------------------------------------------------- +-- Setting up tables for the sample +----------------------------------------------------------------------------- + +-- Create non-MDC table 'books' +CREATE TABLE testschema.books(book_id VARCHAR(10), publish_date DATE, + category VARCHAR(20), location VARCHAR(20), status VARCHAR(15)); + +-- Insert values into table 'books' +INSERT INTO testschema.books + VALUES ('BK101', '10-01-2008', 'Management', 'Tasman', 'available'); + +INSERT INTO testschema.books + VALUES ('BK102', '01-01-2008', 'Fantasy', 'Cupertino', 'available'); + +INSERT INTO testschema.books + VALUES('BK103', '10-10-2007', 'Fantasy', 'Cupertino', 'ordered'); + +INSERT INTO testschema.books + VALUES ('BK104', '05-02-2007', 'Spiritual', 'Tasman', 'available'); + +-- Create 'books_mdc' table partitioned by 'publish date' and organized +-- by multiple dimensions - category, location and status. +CREATE TABLE testschema.books_mdc(book_id VARCHAR(20), publish_date DATE, category + VARCHAR(20), location VARCHAR(20), status VARCHAR(15), + book_details XML) +DISTRIBUTE BY HASH(book_id) +PARTITION BY RANGE(publish_date) + (STARTING FROM ('01-01-2007') + ENDING ('12-12-2008') EVERY 3 MONTHS) +ORGANIZE BY DIMENSIONS (category, location, status); + +-- Move the book details data from 'books' table and insert +-- them into 'books_mdc' table +INSERT INTO testschema.books_mdc(book_id, publish_date, category, location, status) + SELECT book_id, publish_date, category, location, status FROM testschema.books; + +-- Update the 'books_mdc' table with 'book_details' XML data +UPDATE testschema.books_mdc SET book_details = ' + Communication skills + Peter Sharon + 120 + Wroxa + ' +WHERE book_id='BK101'; + +UPDATE testschema.books_mdc SET book_details = ' + Blue moon + Paul Smith + 100 + Orellier + ' +WHERE book_id='BK102'; + + +UPDATE testschema.books_mdc SET book_details = ' + Paint your house + Roger Martin + 120 + BPBH + ' +WHERE book_id='BK103'; + +UPDATE testschema.books_mdc SET book_details = ' + Ramayan + Eric Mathews + 90 + Tata Ho + ' +WHERE book_id = 'BK104'; + +-- Display the contents of 'books_mdc' table +SELECT book_id, publish_date, category, location, status + FROM testschema.books_mdc; + +-------------------------------------------------------------------------- +-- 2. MDC table with partition +-------------------------------------------------------------------------- +-- When a customer comes to the store 'Tasman' branch and asks for a management +-- book by a particular author 'Peter Sharon', published on 1st October 2008, +-- the following query issued by the sales clerk directly goes to the table +-- partition (October to December) and gets the book details. + +-- This query gets the details of list of 'Management' books +-- available in 'Tasman' branch whose published date is 10-01-2008 +SELECT book_id, publish_date, category, location, status +FROM testschema.books_mdc +WHERE location='Tasman' + and category='Management' + and publish_date='10-01-2008' + and XMLEXISTS ('$b/book_details[author="Peter Sharon"]' + PASSING book_details as "b"); + + +---------------------------------------------------------------------------- +-- 3. Faster inserts into MDC table containing an XML column. +---------------------------------------------------------------------------- +-- The store receives in bulk management books from different +-- suppliers, These books are entered into database by the sales clerk. +-- As all the books to be inserted belong to same dimension +-- (category, location and status), the sales clerk while inserting the +-- book details into the books_mdc table enables the LOCKSIZE BLOCKINSERT +-- option for faster insert on MDC table. He does the following operations. + +-- Enable the LOCKSIZE BLOCKINSERT option for faster insert on MDC table +ALTER TABLE testschema.books_mdc LOCKSIZE BLOCKINSERT; +UPDATE command options using c off; + +-- Insert values into 'books_mdc' table +-- Insert data into block '0' +INSERT INTO testschema.books_mdc + VALUES('BK105', '12-10-2007', 'Management', 'Schaumberg', + 'available',' + How to Sell or Market + Rusty Harold + 450 + Orellier + '); + +INSERT INTO testschema.books_mdc + VALUES('BK106', '03-12-2007', 'Management', 'Schaumberg', + 'available',' + How to become CEO + Booster Hoa + 150 + wroxa + '); + +INSERT INTO testschema.books_mdc + VALUES('BK107', '06-25-2008', 'Management', 'Schaumberg', + 'available',' + Effective Email communication + Sajer Menon + 100 + PHPB + '); +COMMIT; + +-- Insert data into block '1' +INSERT INTO testschema.books_mdc + VALUES('BK108', '04-23-2008', 'Management', 'Cupertino', + 'Not available',' + Presentation skills + Martin Lither + 125 + PHPB + '); + +INSERT INTO testschema.books_mdc + VALUES('BK109', '09-25-2007', 'Management', 'Cupertino', + 'Not available',' + Assertive Skills + Robert Steve + 250 + wroxa + '); + +INSERT INTO testschema.books_mdc + VALUES('BK110', '05-29-2007', 'Management', 'Cupertino', + 'Not available',' + Relationship building + Bunting Mexa + 190 + Tata Ho + '); +COMMIT; + +-- Insert data into block '2' +INSERT INTO testschema.books_mdc + VALUES('BK111', '08-14-2008', 'Management', 'Tasman', + 'available',' + Manage your Time + Pankaj Singh + 125 + Orellier + '); + +INSERT INTO testschema.books_mdc + VALUES('BK112', '07-25-2008', 'Management', 'Tasman', + 'available',' + Be in the Present + Hellen Sinki + 200 + Orellier + '); + +INSERT INTO testschema.books_mdc + VALUES('BK113', '06-23-2008', 'Management', 'Tasman', + 'available', ' + How to become Rich + Booster Hoa + 200 + wroxa + '); +COMMIT; + +-- Insert data into block '3' +INSERT INTO testschema.books_mdc + VALUES('BK114', '08-08-2008', 'Fantasy', 'Schaumberg', + 'available',' + Dream home + Hellen Sinki + 250 + wroxa + '); + +INSERT INTO testschema.books_mdc + VALUES('BK115', '05-12-2008', 'Fantasy', 'Schaumberg', + 'available', ' + Dream world + Hellen Sinki + 100 + wroxa + '); +COMMIT; + +-- Insert data into block '4' +INSERT INTO testschema.books_mdc + VALUES('BK116', '09-10-2007', 'Fantasy', 'Cupertino', + 'Not available',' + Mothers Island + Booster Hoa + 250 + wroxa + '); + +INSERT INTO testschema.books_mdc + VALUES('BK117', '03-11-2007', 'Fantasy', 'Cupertino', + 'Not available',' + The destiny + Marran + 250 + Orellier + '); +COMMIT; + +-- Insert data into block '5' +INSERT INTO testschema.books_mdc + VALUES('BK118', '03-12-2007', 'Spiritual', 'Tasman', + 'available',' + Mahabharat + Narayana Murthy + 250 + PHPB + '); + +INSERT INTO testschema.books_mdc + VALUES('BK119', '09-09-2008', 'Spiritual', 'Tasman', + 'available',' + Bhagavat Gita + Narayana Murthy + 250 + PHPB + '); +COMMIT; + +-- Run Runstats command on MDC table to update statistics in the catalog +-- tables. +RUNSTATS ON TABLE testschema.books_mdc WITH DISTRIBUTION and +DETAILED INDEXES ALL; + +-- Change the locksize to default +ALTER TABLE testschema.books_mdc LOCKSIZE ROW; + +------------------------------------------------------------------------ +-- 4. Faster delete on MDC table containing an XML column. +------------------------------------------------------------------------ +-- During monthly analysis the store manager finds out that the +-- 'Fantasy' category books at 'Cupertino' branch don't have many sales. +-- So he asks the DBA to delete these books from 'Cupertino' branch. +-- As all deletes belong to one particular category, the DBA decides +-- to set the following option to make the delete operation faster. + +-- Set MDC ROLLOUT option to make the delete operation faster. +SET CURRENT MDC ROLLOUT MODE IMMEDIATE; + +-- Delete all 'Fantasy' category books from 'books_mdc' table +DELETE FROM testschema.books_mdc + WHERE category='Fantasy' AND location='Cupertino'; + +-- Note that the data is saved before it is rolled out. + +-------------------------------------------------------------------------- +-- 5. Exploiting block indexes and XML indexes in a query +-------------------------------------------------------------------------- +-- For faster retrieval of data the DBA creates an XML index on the author +-- element of book_details XML document. +CREATE INDEX auth_ind ON testschema.books_mdc(book_details) + GENERATE KEY USING XMLPATTERN '/book_details/author' + AS SQL VARCHAR(20); + +-- Query the table to get all 'Management' books available in the store +-- by author 'Booster Ho'. This query exploits both block index +-- and XML index. +SELECT book_id, publish_date, category, location, status +FROM testschema.books_mdc +WHERE category='Management' + AND status='available' + AND XMLEXISTS('$b/book_details[author="Booster Hoa"]' + PASSING book_details as "b"); + +-------------------------------------------------------------------------- +-- CLEANUP +-------------------------------------------------------------------------- +DROP INDEX auth_ind; +DROP TABLE testschema.books; +DROP TABLE testschema.books_mdc; +DROP SCHEMA testschema RESTRICT; + diff --git a/xml/clp/xmlolic.db2 b/xml/clp/xmlolic.db2 new file mode 100644 index 0000000..e01ea4d --- /dev/null +++ b/xml/clp/xmlolic.db2 @@ -0,0 +1,278 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: xmlolic.db2 +-- +-- PURPOSE: This sample demonstrates +-- 1. How to run REORG INDEX with ALLOW WRITE ACCESS on regular +-- tables with index created on XML column. +-- +-- 2. How to run REORG INDEX with ALLOW WRITE ACCESS on a +-- non-partitioned index created on an XML column in a +-- partitioned table. +-- +-- USAGE SCENARIO: The scenario is for a Book Store that has two types +-- of customers, retail customers and corporate customers. Corporate +-- customers do bulk purchases of books for their company libraries. +-- The store has a DBA for maintaining the database, the store +-- manager runs queries on different tables to view the book sales. +-- The store manager complains to the DBA that query performance is +-- very slow while accessing the data from books_available and +-- books_supplied tables. +-- +-- The DBA decides to improve query performance for the table +-- "books_available" by creating an index on the XML column +-- book_details. After many insert, update, and delete operations, +-- the query performance starts to degrade and the DBA sees that the +-- index has become fragmented and needs to be reorged. With support of the +-- ALLOW WRITE ACCESS clause on the REORG INDEX command and REORG INDEXES +-- command, the DBA reorgs the index online and does not have to worry about +-- blocking other transactions that need to insert, update or delete from +-- the table. +-- +-- PREREQUISITE: The SAMPLE database should exist before running this script. +-- +-- EXECUTION: db2 -tvf xmlolic.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Successful execution of all the queries +-- +-- OUTPUT FILE: xmlolic.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT INTO +-- UPDATE +-- CREATE INDEX +-- REORG INDEX +-- DROP TABLE +-- +-- SQL/XML FUNCTIONS USED: +-- XMLQuery +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +----------------------------------------------------------------------------- +-- +-- SAMPLE DESCRIPTION +-- +----------------------------------------------------------------------------- +-- This sample will demonstrate +-- 1. How to run REORG INDEXES with ALLOW WRITE ACCESS on a regular table +-- with index created on XML column. +-- +-- 2. How to run REORG INDEX with ALLOW WRITE ACCESS on a non-partitioned index +-- created on an XML column in a partitioned table. +----------------------------------------------------------------------------- +-- +-- SETUP +-- +----------------------------------------------------------------------------- + +-- Connect to sample +CONNECT TO SAMPLE; + +----------------------------------------------------------------------------- +-- 1. How to run REORG INDEXES with ALLOW WRITE ACCESS on a regular table +-- with index created on XML column. +----------------------------------------------------------------------------- + +-- Create table 'books_available' +CREATE TABLE books_available (docID INTEGER, book_details XML); + +-- Insert values into 'books_available' table +INSERT INTO books_available + VALUES (10, XMLPARSE(document ' + + Cool + Laura + + 100 + 10 + ' preserve whitespace)); + + +INSERT INTO books_available + VALUES(20, XMLPARSE(document ' + + Cool + Chris + + 200 + 20 + ' preserve whitespace)); + +-- To improve the query performance on the books_available table, +-- the DBA plans to create an XML index. He creates an index on +-- 'author1' element of 'book_details' XML document. +CREATE INDEX nameix ON books_available(book_details) + GENERATE KEY USING XMLPATTERN '/book/author1' as SQL VARCHAR(50); + +-- Create an index on docID column. +CREATE INDEX docIDix ON books_available(docID); + +-- Add a new element 'author2' to 'book_details' document +UPDATE books_available SET book_details = XMLQuery ('copy $bk := $BOOK_DETAILS + modify do + insert document { + Chris + Martin + + } + as last into $bk/book return $bk' ) +WHERE docID = 20; + +-- Replace the value of price element in 'book_details' document +-- with the reduced price +UPDATE books_available SET book_details = XMLQuery('transform + copy $bk := $BOOK_DETAILS + modify + for $pr in $bk/book/price + return do replace value of $pr with $pr * 0.8 + return $bk') +WHERE docID = 10; + +-- Add a new element 'publisher' to 'book_details' document +UPDATE books_available SET book_details = XMLQuery('copy $bk := $BOOK_DETAILS + modify do + insert MDM publishers + as last into $bk/book return $bk') +WHERE docID = 10; + +-- Replace the value of the 'name' element in the 'book_details' document with +-- the new name "DB2 9 DBA for LUW" +UPDATE books_available SET book_details = XMLQuery('copy $bk := $BOOK_DETAILS + modify + for $name in $bk/book/@name + return do replace value of $name with "DB2 9 DBA for LUW" + return $bk') +WHERE docID = 20; + +-- After performing the above insert and update operations the query +-- performance starts to degrade and the DBA sees that the index has +-- become fragmented and needs to be reorged. The DBA decides to +-- reorganize the index pages of the table 'books_available' by +-- running the REORG indexes command. +REORG INDEXES ALL FOR TABLE books_available ALLOW WRITE ACCESS; + +---------------------------------------------------------------------- + -- 2. How to run REORG INDEX with ALLOW WRITE ACCESS on a non-partitioned + -- index created on an XML column in a partitioned table. +---------------------------------------------------------------------- +-- The DBA wants to organize the data pertaining to the book orders in +-- different partitions of the table based on the supplied date. He creates +-- a partitioned table with supplied_date as the partition key. +CREATE TABLE supplied_books (docID int, supplied_date date, book_details xml) + PARTITION BY (supplied_date) + (STARTING '01/01/2008' + ENDING '12/31/2009' + EVERY 3 MONTHS ); + +-- To improve the application performance, DBA creates a +-- non-partitioned index on 'name' attribute of book_details document +CREATE INDEX bname ON supplied_books(book_details) + GENERATE KEY USING XMLPATTERN '/book/@name' as SQL VARCHAR(50) + NOT PARTITIONED; + +-- Insert values into "supplied_books" table +INSERT INTO supplied_books VALUES +( 1, '10/01/2008', XMLPARSE(document ' + + Nimar + Shindey + + 90 + 10 + ' preserve whitespace)); + +INSERT INTO supplied_books VALUES +( 2, '12/04/2008', XMLPARSE(document ' + + Cool + Chris + + 100 + 12 + ' preserve whitespace)); + + +-- Add a new element 'author2' to 'book_details' document +UPDATE supplied_books SET book_details = XMLQuery ('copy $bk := $BOOK_DETAILS + modify do + insert document { + Sherry + Magor + + } + as last into $bk/book return $bk' ) +WHERE docID = 1; + +-- Replace the value of element 'copies_available' with a new value '25' +UPDATE supplied_books SET book_details = XMLQuery('transform + copy $bk := $BOOK_DETAILS + modify + for $cps in $bk/book/copies_available + return do replace value of $cps with 25 + return $bk') +WHERE docID = 2; + +-- Add a new element 'edition' to 'book_details' document +UPDATE supplied_books SET book_details = XMLQuery('copy $bk := $BOOK_DETAILS + modify do + insert 3rd edition + as last into $bk/book return $bk') +WHERE docID = 1; + +-- Replace the value of 'name' element in 'book_details' document with new +-- name "Networking on Linux and Windows" +UPDATE supplied_books SET book_details = XMLQuery('copy $bk := $BOOK_DETAILS + modify + for $name in $bk/book/@name + return do replace value of $name + with "Networking on Linux and Windows" + return $bk') +WHERE docID = 2; + + +-- After performing the above insert and update operations the query +-- performance starts to degrade and the DBA sees that the index has +-- become fragmented and needs to be reorged. The DBA decides to +-- reorganize the index pages of the table 'supplied_books' by +-- running the REORG indexes command. +REORG INDEX bname FOR TABLE supplied_books ALLOW WRITE ACCESS; + +---------------------------------------------------------------------- +-- CLEANUP +---------------------------------------------------------------------- +DROP INDEX docIDix; +DROP INDEX nameix; +DROP INDEX bname; +DROP TABLE supplied_books; +DROP TABLE books_available; + + + + + diff --git a/xml/clp/xmlpartition.db2 b/xml/clp/xmlpartition.db2 new file mode 100644 index 0000000..ca73a4b --- /dev/null +++ b/xml/clp/xmlpartition.db2 @@ -0,0 +1,463 @@ +------------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +------------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xmlpartition.db2 +-- +-- SAMPLE: +-- The sample demonstrates the use of XML in +-- partitioned database environment, MDC and partitioned tables. +-- +-- PREREQUISITE: +-- 1)Sample database is setup on the machine. +-- +-- Note: Use following command to execute the sample: +-- db2 -td@ -vf xmlpartition.db2 +-- +-- +-- USAGE SCENARIO: +-- The Scenario is for an Book Store that has two types of customers, +-- retail customers and corporate customers. Corporate customers do +-- bulk purchases of books for their company libraries. The store has +-- a DBA for maintaining the database; the store manager runs queries +-- on different tables to view the book sales and to deliver the purchase +-- orders. +-- +-- The store manger, to expand his business, opens more branches in +-- different countries. +-- The store manager complains to the DBA about the degrading +-- response time of different queries like: +-- 1) Checks for sales for a particular country every quarter. +-- 2) Checks for sales on different modes of purchase +-- (online OR offline). +-- 3) Retrieve all purchase orders that are to be delivered to the +-- customers. +-- +-- In order to increase the response time of the queries and speed up +-- the process, DBA decides to partition the table 'Purchase_Orders' +-- by 'OrderDate' as range. Because of increasing sales, DBA creates +-- the tables 'Purchase_Order' and 'Customers' in database partitioned +-- environment so that data required for delivering a purchase order +-- like customer and purchase order details from 'Purchase_Orders' and +-- 'Customers' can be fetched quickly. He also organizes the table based +-- on dimensions, country and modeOfPurchase, so that details about the +-- sales for a country / mode of purchase can be fetched quickly. +-- As the year progresses, store DBA ATTACHes a partition the PurchaseOrder +-- table for every quarter to store the huge volume of data. +-- +-- +-- SQL STATEMENTS USED: +-- 1) CREATE TABLE with DISTRIBUTE BY HASH, PARTITION BY RANGE and +-- ORGANIZE BY DIMENSIONS clause. +-- 2) INSERT +-- 3) SELECT +-- 4) ALTER TABLE ... ATTACH +-- 5) CREATE INDEX +-- +------------------------------------------------------------------------------- + +-- Connect to sample database +CONNECT TO sample@ + + +-- For the year 2008, the retail store decides to create a table which is +-- partitioned for every quarter to store the orders placed by the customer. +-- Each partition will be placed in a separate table space. +-- Four table spaces ('Tbspace1', 'Tbspace2', 'Tbspace3' and 'Tbspace4') are +-- created to contain relational data from the new 'purchaseOrder_Details' table. +-- Four table spaces ('Ltbspace1', 'Ltbspace2', 'Ltbspace3' and 'Ltbspace4') are +-- created to contain long data from the new 'purchaseOrder_Details' table. +SET SCHEMA = store@ +CREATE BUFFERPOOL common_Buffer IMMEDIATE SIZE 1000 AUTOMATIC PAGESIZE 4K@ + +CREATE TABLESPACE Tbspace1 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont1' 10000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Tbspace2 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont2' 10000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Tbspace3 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont3' 10000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Tbspace4 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont4' 10000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ + +-- The purchase order information is an XML document. To store XML +-- data, a large tablespace will be used. +-- Therefore four, large table spaces are created to store XML data for these +-- partition. +CREATE TABLESPACE Ltbspace1 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lcont1' 20000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Ltbspace2 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lcont2' 20000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Ltbspace3 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lcont3' 20000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ +CREATE TABLESPACE Ltbspace4 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lcont4' 20000) + PREFETCHSIZE 4K BUFFERPOOL common_Buffer@ + + +-- A tablespace 'Global_IndTbspace' is created to store all +-- the index data. +CREATE TABLESPACE Global_IndTbspace MANAGED BY DATABASE + USING (FILE 'cont_globalInd' 10000)@ + + +-- Create tables 'Customers' and 'Purchase_Orders' which stores information +-- about customers and purchase orders placed by them. +CREATE TABLE Customers (id INT NOT NULL PRIMARY KEY, + name VARCHAR(20), + country VARCHAR(20), + contactNumber VARCHAR(15), + type VARCHAR(15), + address XML) + DISTRIBUTE BY HASH (ID)@ + + + CREATE TABLE Purchase_Orders + (id INT NOT NULL PRIMARY KEY, + status VARCHAR(10), + custID INT REFERENCES Customers(id), + orderDate DATE, + country VARCHAR(20), + modeOfPurchase VARCHAR(10), + pOrder XML, + feedback XML) +DISTRIBUTE BY HASH (ID) + PARTITION BY RANGE (orderDate) + (PART Q1 STARTING FROM '2008-01-01' ENDING '2008-03-31' IN Tbspace1 LONG IN Ltbspace1, + PART Q2 ENDING '2008-06-30' IN Tbspace2 LONG IN Ltbspace2, + PART Q3 ENDING '2008-09-30' IN Tbspace3 LONG IN Ltbspace3, + PART Q4 ENDING '2008-12-31' IN Tbspace4 LONG IN Ltbspace4 ) + ORGANIZE BY DIMENSIONS (country, modeOfPurchase)@ + + +-- Insert data into 'Customers' table +INSERT INTO Customers VALUES (1000,'Joe','Canada','9008788889','Corporate', + '
+ 1805 Back Street + EC3M 4TD + Toronto + Canada +
')@ +INSERT INTO Customers VALUES (1001,'Smith','US','9876721212','Corporate', + '
+ 498 White Street + Los Angeles + US +
')@ +INSERT INTO Customers VALUES (1002,'Bob','US','9876654789','Retail', + '
+ 98th Main Street + 100027 + Chicago + US +
')@ +INSERT INTO Customers VALUES (1003,'Patrick','Canada','9000087634','Retail', + '
+ Chruch Street + Charlottetown + Canada +
')@ +INSERT INTO Customers VALUES (1004,'William','Canada','9098765432','Corporate', + '
+ City Main + Yellowknife + Canada +
')@ +INSERT INTO Customers VALUES (1005,'Sue','India','9980808080','Corporate', + '
+ 98765 + 100027 + Bangalore + India +
')@ + +-- Insert data into 'Purchase_Orders' table + + + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5000,'Shipped',1000,'2008-03-21','Canada','Online', +' + + + + 100 + DB2 understanding security + 3 + 149.97 + + + + + 1000 + Cars + 3 + 14.97 + + +')@ + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5001,'Shipped',1000,'2008-03-30','Canada','Online', +' + + + + 100 + DB2 understanding security + 3 + 149.97 + + + + + 1001 + The week + 3 + 8.97 + + +')@ + + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5002,'Shipped',1000,'2008-04-21','Canada','Offline', +' + + + + 100 + DB2 understanding security + 3 + 149.97 + + + 101 + PHP Power Programming + 2 + 59.98 + + +')@ + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5003,'Shipped',1000,'2008-05-21','Canada','Online', +' + + + + 102 + PHP Pear Programming + 1 + 29.99 + + + + + 2000 + 7 habbits of success + 2 + 29.98 + + +')@ + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5004,'Shipped',1000,'2008-05-22','Canada','Online', +' + + + + 100 + DB2 understanding security + 1 + 49.99 + + + + + 2002 + Crisis + 2 + 19.98 + + +')@ + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5005,'Shipped',1000,'2008-05-23','Canada','Offline', +' + + + + 1004 + Digit + 2 + 9.98 + + +')@ + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5006,'Shipped',1000,'2008-05-24','Canada','Offline', +' + + + + 100 + DB2 understanding security + 3 + 149.97 + + +')@ + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5007,'Unshipped',1000,'2008-06-24','Canada','Online', +' + + + + 100 + DB2 understanding security + 3 + 149.97 + + +')@ + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5008,'Unshipped',1005,'2008-07-03','India','Online', +' + + + + 100 + DB2 Partitioning techniques + 2 + 59.98 + + +')@ + + + +-- Create an index on the items purchased by the customer. +-- This will help retrieve details about the purchase order faster. +-- The IN clause specifies the tablespace where the INDEX created will be placed. +-- This clause overrides the any INDEX IN clause, specified during the creation of the +-- table. + +CREATE INDEX pIndex ON Purchase_Orders(pOrder) + GENERATE KEY USING XMLPATTERN '/PurchaseOrder/Books/Book/name' AS SQL VARCHAR(60) NOT PARTITIONED + IN Global_IndTbspace@ + + +-- Statistics is collected on the table 'purchaseOrder_Details' by +-- executing RUNSTATS on it. With the new statistics obtained, DB2 uses +-- the index pIndex on the table for processing any further queries on +-- the table 'purchaseOrder_Details' which uses the predicate 'name' of +-- the XML document. + +RUNSTATS ON TABLE store.Purchase_Orders FOR INDEXES ALL@ + + + +-- Select customer and purchase order details about the orders that are not shipped +SELECT p.custID, p.id, p.pOrder, c.name, c.contactNumber, c.address +FROM Purchase_Orders as p, Customers as c +WHERE c.id = p.custID and status = 'Unshipped' ORDER BY p.custID@ + + +-- Find total online sales for canada in the second quarter +SELECT sum(X."Price") AS TotalSales +FROM +XMLTABLE ('db2-fn:xmlcolumn("PURCHASE_ORDERS.PORDER")/PurchaseOrder/Books/Book' +COLUMNS + "PoNum" BIGINT PATH './../../@PoNum', + "Price" DECFLOAT PATH './price') as X, purchase_orders as p + WHERE p.id = X."PoNum" and p.orderdate BETWEEN '2008-04-01' AND '2008-06-30' + AND country = 'Canada' AND modeOfPurchase = 'Online'@ + + +-- Find total sales that has happened Online and Offline in the second quarter +WITH temp AS ( SELECT p.modeOfPurchase, p.orderDate, t.price + FROM Purchase_Orders AS p, XMLTABLE('$po/PurchaseOrder/Books/Book' + passing p.pOrder as "po" + COLUMNS price DECFLOAT path './price') AS t) +SELECT temp.modeOfPurchase, sum(temp.price) AS Total FROM temp +WHERE temp.orderDate BETWEEN '2008-04-01' AND '2008-06-30' + GROUP BY temp.modeOfPurchase@ + + +-- As the year progress, store DBA adds new partition for every quarter. +ALTER TABLE Purchase_Orders ADD PARTITION part2009a + STARTING FROM '2009-01-01' ENDING '2009-03-31' INCLUSIVE IN Tbspace1 LONG IN Ltbspace1@ + +INSERT INTO Purchase_Orders(id, status, custID, orderDate, country, modeOfPurchase, pOrder) +VALUES (5009,'Unshipped',1005,'2009-01-03','India','Online', +' + + + + 100 + DB2 Partitioning techniques + 2 + 59.98 + + +')@ + +-- Select purchase orders that are not shipped for the first quarter of 2009 +SELECT * FROM Purchase_Orders + where XMLEXISTS('$d/PurchaseOrder/Books/Book[name="DB2 Partitioning techniques"]' passing PORDER as "d") and status = 'Unshipped' and orderDate between '2009-01-01' and '2009-03-31'@ + + +REORG TABLE Purchase_Orders@ +REORG INDEX pIndex FOR TABLE Purchase_Orders ALLOW READ ACCESS CLEANUP ONLY@ +REORG INDEXES ALL FOR TABLE Purchase_Orders ON DATA PARTITION Q1@ +REORG INDEXES ALL FOR TABLE Purchase_Orders ON DATA PARTITION Q2@ +REORG INDEXES ALL FOR TABLE Purchase_Orders ON DATA PARTITION Q3@ +REORG INDEXES ALL FOR TABLE Purchase_Orders ON DATA PARTITION Q4@ +REORG INDEXES ALL FOR TABLE Purchase_Orders ON DATA PARTITION part2009a@ + +-- Clean-Up Script +DROP INDEX pIndex@ +DROP TABLE Purchase_Orders@ +DROP TABLE Customers@ +DROP TABLESPACE Tbspace1@ +DROP TABLESPACE Tbspace2@ +DROP TABLESPACE Tbspace3@ +DROP TABLESPACE Tbspace4@ +DROP TABLESPACE Ltbspace1@ +DROP TABLESPACE Ltbspace2@ +DROP TABLESPACE Ltbspace3@ +DROP TABLESPACE Ltbspace4@ +DROP TABLESPACE Global_IndTbspace@ +DROP BUFFERPOOL common_Buffer@ + +-- Close connection to the sample database +CONNECT RESET@ + diff --git a/xml/clp/xmlrunstats.db2 b/xml/clp/xmlrunstats.db2 new file mode 100644 index 0000000..b260019 --- /dev/null +++ b/xml/clp/xmlrunstats.db2 @@ -0,0 +1,109 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xmlrunstats.db2 +-- +-- SAMPLE: How to perform runstats on a table containing XML type columns +-- +-- SQL STATEMENT USED: +-- CREATE SCHEMA +-- CREATE TABLE +-- DROP SCHEMA +-- DROP TABLE +-- INSERT +-- SELECT +-- TERMINATE +-- +-- OUTPUT FILE: xmlrunstats.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to database +CONNECT TO sample; + +-- create a schema +CREATE SCHEMA testschema; + +-- create a table +CREATE TABLE testschema.customer LIKE customer; + +-- insert into the table customer +INSERT INTO testschema.customer (SELECT * FROM customer); + +-- perform Runstats on the table +-- update statistics for the table customer + +-- perform runstats on table customer for all columns including XML columns +RUNSTATS ON TABLE testschema.customer; + +-- perform runstats on table testschema.customer for XML columns +RUNSTATS ON TABLE testschema.customer ON COLUMNS (Info, History); + +-- perform runstats on table customer for XML columns +-- with the following options: +-- +-- Distribution statistics for all partitions +-- Frequent values for table set to 30 +-- Quantiles for table set to -1 (NUM_QUANTILES as in DB Cfg) +-- Allow others to have read-only while gathering statistics +RUNSTATS ON TABLE testschema.customer + ON COLUMNS(Info, History LIKE STATISTICS) + WITH DISTRIBUTION ON KEY COLUMNS + DEFAULT + NUM_FREQVALUES 30 + NUM_QUANTILES -1 + ALLOW READ ACCESS; + +-- perform runstats on table customer +-- with the following options: +-- +-- EXCLUDING XML COLUMNS. +-- This option allows the user to exclude all XML type columns +-- from statistics collection. Any XML type columns that have been +-- specified in the cols-list will be ignored and no statistics will +-- be collected from them. This clause facilitates the collection of +-- statistics on non-XML columns. +RUNSTATS ON TABLE testschema.customer + ON COLUMNS(Info, History LIKE STATISTICS) + WITH DISTRIBUTION ON KEY COLUMNS + EXCLUDING XML COLUMNS; + +-- make sure to rebind all packages that use this table to make +-- use of updated statistics after executing the RUNSTATS command. + +-- drop the table customer +DROP TABLE testschema.customer; + +-- drop the schema +DROP SCHEMA testschema RESTRICT; + +-- disconnect from the database +CONNECT RESET; + +TERMINATE; diff --git a/xml/clp/xmlschema.db2 b/xml/clp/xmlschema.db2 new file mode 100644 index 0000000..f8f7d75 --- /dev/null +++ b/xml/clp/xmlschema.db2 @@ -0,0 +1,125 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME:xmlschema.db2 +-- +-- SAMPLE USAGE SCENARIO: Consider a user who needs to insert an XML type value +-- into the table. The user would like to ensure that the XML value conforms to a +-- deterministic XML schema. +-- +-- PROBLEM: User has schema's for all the XML values and like to validate the values +-- as per schema while inserting it to the tables. +-- +-- SOLUTION: +-- To achieve the goal, the sample will follow the following steps: +-- a) Register the primary XML schema +-- b) Add the XML schema documents to the primary XML schema to ensure that the +-- schema is deterministic +-- c) Insert an XML value into an existing XML column and perform validation +-- +-- SAMPLE EXECUTION : Run this sample using following command +-- +-- db2 -td! -vf xmlschema.db2 +-- +-- PREREQUISITE :copy product.xsd, order.xsd, +-- customer.xsd, header.xsd Schema files, order.xml XML +-- document from xml/data directory to working +-- directory +-- +-- SQL STATEMENTS USED: +-- REGISTER XMLSCHEMA +-- ADD XMLSCHEMA DOCUMENT +-- COMPLETE XMLSCHEMA +-- INSERT +-- +-- SQL/XML FUNCTIONS USED: +-- XMLVALIDATE +-- XMLPARSE +-- +-- OUTPUT FILE: xmlschema.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- CONNECT TO THE DATABASE +CONNECT TO SAMPLE! + +-- REGISTER THE MAIN XML SCHEMA +REGISTER XMLSCHEMA http://www.test.com/order FROM order.xsd AS order! + +-- ADD XML SCHEMA DOCUMENT TO MAIN SCHEMA +ADD XMLSCHEMA DOCUMENT TO order ADD http://www.test.com/header FROM header.xsd! + +-- ADD XML SCHEMA DOCUMENT TO MAIN SCHEMA +ADD XMLSCHEMA DOCUMENT TO order ADD http://www.test.com/product FROM product.xsd! + +-- ADD XML SCHEMA DOCUMENT TO MAIN SCHEMA +ADD XMLSCHEMA DOCUMENT TO order ADD http://www.test.com/customer FROM customer.xsd! + +-- COMPLETE THE SCHEMA REGISTRATION +COMPLETE XMLSCHEMA order! + +-- SELECT INFORMATION ABOUT THE REGISTERED SCHEMA FROM CATALOG TABLE +SELECT CAST(OBJECTSCHEMA AS VARCHAR(15)), CAST(OBJECTNAME AS VARCHAR(15)) FROM syscat.xsrobjects WHERE OBJECTNAME='ORDER'! + +-- INSERT THE XML DOCUMENT +CREATE TABLE t1 (id INT GENERATED ALWAYS AS IDENTITY,po XML)! + +INSERT INTO t1(po) VALUES(xmlvalidate(xmlparse(document(' + +
+ 1 + 2004-01-29 + purchase order + 20 + shipped +
+ + + + Widget C + 1 + 30 + no comment + + 1 + + + + Manoj K Sardana +
ring road, bangalore
+ 918051055109 + msardana@in.ibm.com +
+
')) ACCORDING TO XMLSCHEMA ID order))! + +-- DROP THE TABLE +DROP TABLE t1! + +-- DISCONNECT FROM DATABASE +CONNECT RESET! + diff --git a/xml/clp/xmltotable.db2 b/xml/clp/xmltotable.db2 new file mode 100644 index 0000000..3eae183 --- /dev/null +++ b/xml/clp/xmltotable.db2 @@ -0,0 +1,204 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME:xmltotable.db2 +-- +-- SAMPLE USAGE SCENARIO:Purchase order XML document contains detailed +-- information about all the orders. It will also have the detail of the +-- customer with each order. +-- +-- PROBLEM: The document has some redundant information as customer info +-- and product info is repeated in each order for example +-- Customer info is repeated for each order from same customer. +-- Product info will be repeated for each order of same product from different customers. + +-- SOLUTION: The sample database has tables with both relational and XML data to remove +-- this redundant information. These relational tables will be used to store +-- the customer info and product info in the relational table having XML data +-- and id value. Purchase order will be stored in another table and it will +-- reference the customerId and productId to refer the customer and product +-- info respectively. + +-- To achieve the above goal this sample will shred the data for purchase order XML +-- document and insert it into the tables. + +-- The sample will follow the following steps + +-- 1. Get the relevant data in XML format from the purchase order XML document (use XMLQuery) +-- 2. Shred the XML doc into the relational table. (Use XMLTable) +-- 3. Select the relevant data from the table and insert into the target relational table. + +-- SAMPLE EXECUTION : Run the samples using following command +-- db2 -td! -vf xmltotable.db2 +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT +-- SELECT +-- +-- SQL/XML FUNCTIONS USED: +-- XMLQUERY +-- XMLTABLE + +-- OUTPUT FILE: xmltotable.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- CONNECT TO THE DATABASE +CONNECT TO sample! + +-- CREATE A TABLE po +CREATE TABLE po(id INT GENERATED ALWAYS AS IDENTITY,purchaseorder XML)! + +-- CREATE THE PROCEDURE +CREATE PROCEDURE PO_shred (IN purchaseorder XML) LANGUAGE SQL + BEGIN + DECLARE xmlvar XML; + DECLARE stmt_text VARCHAR(1024); + DECLARE at_end SMALLINT DEFAULT 0; + DECLARE not_found + CONDITION for SQLSTATE '02000'; + DECLARE stmt STATEMENT; + DECLARE cur1 CURSOR FOR stmt; + DECLARE CONTINUE HANDLER for not_found + SET at_end = 1; + + -- INSERT THE PURCHASEORDER XML DOCUMENT INTO PO TABLE + INSERT INTO PO(purchaseorder) VALUES(XMLDOCUMENT(purchaseorder)); + + -- SELECT THE PURCHASE ORDERS WITH THE STATUS SHIPPED USING AN XQUERY + SET stmt_text= 'XQUERY db2-fn:xmlcolumn("PO.PURCHASEORDER")/PurchaseOrders/PurchaseOrder[@Status="shipped"]'; + PREPARE stmt FROM stmt_text; + OPEN cur1; + + -- ITERATE THROUGH THE RESULT SET OF THE XQUERY + fetch_loop: + LOOP + FETCH cur1 into xmlvar; + IF at_end <> 0 THEN LEAVE fetch_loop; + END IF; + + -- XMLTABLE WILL CONVERT THE INDIVIDUAL PURCHASEORDER XML DOCUMENT TO A RELATIONAL TABLE. + -- SELECT THE DETAILS FROM THIS TABLE AND INSERT IT INTO CUSTOMER TABLE + INSERT INTO customer(CID,info,history) + SELECT T.CustID, XMLDOCUMENT(XMLELEMENT(NAME "customerinfo",XMLATTRIBUTES (T.CustID as "Cid"), + XMLCONCAT( + XMLELEMENT(NAME "name", T.Name ),T.Addr, + XMLELEMENT(NAME "phone", XMLATTRIBUTES(T.Type as "type"), T.Phone) + ))), xmldocument(T.History) + FROM XMLTABLE( '$d/PurchaseOrder' PASSING XMLDOCUMENT(xmlvar) AS "d" + COLUMNS + CustID BIGINT PATH '@CustId', + Addr XML PATH './Address', + History XML PATH './History', + Name VARCHAR(20) PATH './name', + Country VARCHAR(20) PATH './Address/@country', + Phone VARCHAR(20) PATH './phone', + Type VARCHAR(20) PATH './phone/@type' + ) as T where T.CustID not in (Select CID from customer); + INSERT INTO purchaseOrder(poid, orderdate, custid,status, porder, comments) + SELECT Poid, OrderDate, CustID, Status, xmldocument(XMLELEMENT(NAME "PurchaseOrder", + XMLATTRIBUTES(T.Poid as "PoNum", T.OrderDate as "OrderDate", + T.Status as "Status"), + T.itemlist)), Comment + FROM XMLTable ('$d/PurchaseOrder' PASSING XMLDOCUMENT(xmlvar) as "d" + COLUMNS + Poid BIGINT PATH '@PoNum', + OrderDate DATE PATH '@OrderDate', + CustID BIGINT PATH '@CustId', + Status varchar(10) PATH '@Status', + itemlist XML PATH './itemlist', + Comment varchar(1024) PATH './comments' + ) as T; + + END LOOP fetch_loop; + CLOSE cur1; +END! + +-- CALL THE ABOVE STORED PROCEDURE WITH PURCHASEORDER DOCUMENT + +CALL PO_shred(XMLPARSE(DOCUMENT(' + + Manoj K Sardana +
+ Ring Road + Bangalore + Karnataka + 560071 +
+ 9880471176 + + + + 100-103-01 + Snow Shovel, Super Deluxe 26" + 1 + 49.99 + + + +
+ + Balunaini Prasad +
+ Ring Road + Bangalore + Karnataka + 560071 +
+ 9886362610 + + + + 100-201-01 + Ice Scraper, Windshield 4" Wide + 1 + 3.99 + + + +
+
')))! + +-- SELECT FROM THE TABLES TO CHECK THAT DATA IS INSERTED CORRECTLY +SELECT POID, XMLSERIALIZE(porder as VARCHAR(1028)) FROM PURCHASEORDER ORDER BY POID! +SELECT CID, XMLSERIALIZE(info as VARCHAR(1028)) FROM CUSTOMER ORDER BY CID! + +-- DELETE THE ROWS FROM PURCHASEORDER +DELETE FROM PURCHASEORDER WHERE POID IN (110,111)! +DELETE FROM CUSTOMER WHERE CID IN (10,11)! + +-- DROP THE TABLE PO +DROP TABLE po! + +-- DROP THE PROCEDURE +DROP PROCEDURE PO_shred! + +-- RESET THE CONNECTION +CONNECT RESET! diff --git a/xml/clp/xmltrig.db2 b/xml/clp/xmltrig.db2 new file mode 100644 index 0000000..33e3865 --- /dev/null +++ b/xml/clp/xmltrig.db2 @@ -0,0 +1,264 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: xmltrig.db2 +-- +-- PURPOSE: This sample shows how triggers are used to enforce automatic +-- validation while inserting/updating xml documents. +-- +-- USAGE SCENARIO: When a customer places a purchase order request an entry +-- is made in the "customer" table by inserting customer +-- information and his history details. If the customer is +-- new, and is placing a request for the first time to this +-- supplier,then the history column in the "customer" table +-- wil be NULL. If he's an old customer, data in "customer" +-- table info and history columns are inserted. +-- +-- PREREQUISITE: +-- On Unix: copy boots.xsd file from /sqllib +-- /samples/xml/data directory to current directory. +-- On Windows: copy boots.xsd from \sqllib\ +-- samples\xml\data directory to current directory +-- +-- EXECUTION: db2 -td@ -vf xmltrig.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: The last trigger statement which uses XMLELEMENT on transition +-- variable will fail. All other trigger statements will succeed. +-- +-- OUTPUT FILE: xmltrig.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TRIGGER +-- INSERT +-- DELETE +-- DROP +-- REGISTER XMLSCHEMA +-- COMPLETE XMLSCHEMA +-- +-- SQL/XML FUNCTIONS USED: +-- XMLDOCUMENT +-- XMLPARSE +-- XMLVALIDATE +-- XMLELEMENT +-- +-- +----------------------------------------------------------------------------- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- +----------------------------------------------------------------------------- +-- SAMPLE DESCRIPTION +-- +----------------------------------------------------------------------------- +-- 1. Register boots.xsd schema with http://posample1.org namespace. +-- +-- 2. This sample consists of four different cases of create trigger +-- statements to show automatic validation of xml documents with +-- triggers. +-- +-- Case1: This first trigger statement shows how to assign values to +-- non-xml transition variables, how to validate XML documents and +-- also to show that NULL values can be assigned to XML transition +-- variables in triggers. +-- +-- Case2: Create a BEFORE INSERT trigger to validate info column in +-- "customer" table and insert a value for history column without +-- any validation +-- +-- Case3: Create a BEFORE UPDATE trigger with ACCORDING TO clause used +-- with WHEN clause.This trigger statement shows that only when WHEN +-- condition is satisfied, the action part of the trigger will be +-- executed.WHEN conditions are used with BEFORE UPDATE triggers. +-- +-- Case4: Create a BEFORE INSERT trigger with XMLELEMENT function being +-- used on a transition variable. This case results in a failure as only +-- XMLVALIDATE function is allowed on XML transition variables. +-- +-- NOTE : In a typical in real-time scenario, DBAs will create triggers +-- and users will insert records using one or more insert/update statements +-- not just one insert statement as shown in this sample. +----------------------------------------------------------------------------- +-- SETUP +----------------------------------------------------------------------------- +-- Connect to sample database +CONNECT TO sample@ +-- + +-- Register boots schema +REGISTER XMLSCHEMA http://posample1.org FROM boots.xsd AS boots@ +COMPLETE XMLSCHEMA boots@ + +----------------------------------------------------------------------------- +-- +-- Case1: This first trigger statement shows how to assign values to +-- non-xml transition variables, how to validate XML documents and +-- also to show that NULL values can be assigned to XML transition +-- variables in triggers. +-- +----------------------------------------------------------------------------- + +CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON customer +REFERENCING NEW AS n +FOR EACH ROW MODE DB2SQL +BEGIN ATOMIC + set n.Cid = 5000; + set n.info = xmlvalidate (n.info ACCORDING TO XMLSCHEMA ID customer); + set n.history = NULL; +END@ + +-- Insert values into "customer" table +INSERT INTO customer VALUES (1008, + ' + Larry Menard223 Koramangala + ring RoadTorontoOntario + M4C 5K8 + 905-555-9146 + 416-555-6121Goose Defender + 416-555-1943 + ', NULL)@ + +-- Display the inserted info from "customer" table +SELECT Cid, info FROM customer +WHERE Cid = 5000@ + +-- DROP trigger TR1 +DROP TRIGGER TR1@ + +----------------------------------------------------------------------------- +-- +-- Case2: Create a BEFORE INSERT trigger to validate info column in +-- "customer" table and insert a value for history column without +-- any validation +-- +----------------------------------------------------------------------------- + +CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON customer +REFERENCING NEW AS n +FOR EACH ROW MODE DB2SQL +BEGIN ATOMIC + set n.Cid =5001; + set n.info = xmlvalidate(n.info ACCORDING TO XMLSCHEMA ID customer); + set n.history = ' + madhavi'; +END@ + +-- INSERT row into "customer" table +INSERT INTO customer VALUES (1009, + ' + Larry Menard + 223 Koramangala ring RoadToronto + OntarioM4C 5K8 + 905-555-9146 + 416-555-6121 + Madhavi Kaza416-555-1943 + ', NULL)@ + +-- Display inserted info from "customer" table +SELECT Cid, info, history +FROM customer +WHERE Cid = 5001@ + +----------------------------------------------------------------------------- +-- +-- Case3: Create a BEFORE UPDATE trigger with ACCORDING TO clause used +-- with WHEN clause.This trigger statement shows that only when WHEN +-- condition is satisfied, the action part of the trigger will be +-- executed.WHEN conditions are used with BEFORE UPDATE triggers. +-- +----------------------------------------------------------------------------- + +CREATE TRIGGER TR2 NO CASCADE BEFORE UPDATE ON customer +REFERENCING NEW AS n +FOR EACH ROW MODE DB2SQL +WHEN (n.info is not validated ACCORDING TO XMLSCHEMA ID CUSTOMER) +BEGIN ATOMIC + set n.Cid = 5002; + set n.info = xmlvalidate(n.info ACCORDING TO XMLSCHEMA ID customer); + set n.history = ' + sum Lata'; +END@ + +-- UPDATE the 'info' column value in the "customer" table whose Cid is 5001 +UPDATE CUSTOMER SET customer.info = XMLPARSE(document + ' + Russel + Koramangala ring RoadBangalore + KarnatakaM4C 5K9 + 995-545-9142 + 476-552-6421 + Madhavi Kaza415-595-1243 + ' preserve whitespace) +WHERE Cid=5001@ + +-- Display updated data from "customer" table +SELECT Cid, info, history +FROM customer +WHERE Cid = 5002@ + +-- DROP TRIGGERS TR1 and TR2 +DROP TRIGGER TR1@ +DROP TRIGGER TR2@ + +----------------------------------------------------------------------------- +-- +-- Case4: Create a BEFORE INSERT trigger with XMLELEMENT function being +-- used on a transition variable. This case results in a failure as only +-- XMLVALIDATE function is allowed on transition variables. +-- +----------------------------------------------------------------------------- + +-- Create table "boots" +CREATE TABLE boots (Cid int, xmldoc1 XML, xmldoc2 XML)@ + +-- Trigger creation itself fails as XMLELEMENT is not allowed on +-- transition variable +CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON boots +REFERENCING NEW as n +FOR EACH ROW MODE DB2SQL +BEGIN ATOMIC + set n.Cid=5004; + set n.xmldoc1 = XMLVALIDATE(xmldoc1 ACCORDING TO XMLSCHEMA URI + 'http://posample1.org'); + set n.xmldoc2 = XMLDOCUMENT(XMLELEMENT(name adidas, n.xmldoc2)); +END@ + +----------------------------------------------------------------------------- +-- +-- CLEANUP +-- +----------------------------------------------------------------------------- + +-- Delete all rows inserted from this sample +DELETE FROM CUSTOMER +WHERE Cid > 1005@ + +-- Drop table boots +DROP TABLE boots@ + +-- Drop schema +DROP XSROBJECT BOOTS@ diff --git a/xml/clp/xmludfs.db2 b/xml/clp/xmludfs.db2 new file mode 100644 index 0000000..8cf40f5 --- /dev/null +++ b/xml/clp/xmludfs.db2 @@ -0,0 +1,474 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2008 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: xmludfs.db2 +-- +-- PURPOSE: The purpose of this sample is to show extended support of XML for +-- sourced UDF and SQL bodied UDF. +-- +-- USAGE SCENARIO: The scenario is for a Book Store that has two types of +-- customers, retail customers and corporate customers. Corporate +-- customers do bulk purchases of books for their company libraries. +-- The Book Store also maintains list of �registered customers� +-- who are frequent buyers from the store and have registered +-- themselves with the store. The store has a DBA, sales clerk and a +-- manager for maintaining the database and to run queries on different +-- tables to view the book sales. +-- +-- The store manager frequently queries various tables to get +-- information such as contact numbers of different departments, +-- location details, location manager details, employee details +-- in order to perform various business functions like promoting +-- employees, analysing sales, giving awards and bonus to employees +-- based on their sales. +-- +-- The manager is frustrated writing the same queries every time to +-- get the information and observes performance degradation as well. +-- So he decides to create a user-defined function and a stored +-- procedure for each of his requirements. +-- +-- PREREQUISITES: None +-- +-- EXECUTION: db2 -td@ -vf xmludfs.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Successfully execution of all UDFs and stored procedures. +-- +-- OUTPUT FILE: xmludfs.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT +-- UPDATE +-- DELETE +-- DROP +-- +-- SQL/XML FUNCTIONS USED: +-- XMLPARSE +-- XMLTABLE +-- XMLQUERY +-- XMLEXISTS +-- +----------------------------------------------------------------------------- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +----------------------------------------------------------------------------- +-- SAMPLE DESCRIPTION +-- +----------------------------------------------------------------------------- +-- 1. UDF Scalar function which takes an XML variable as input parameter +-- and returns XML value as output. +-- +-- 2. UDF Table function which takes an XML variable as input parameter +-- and returns a table with XML values as output. +-- +-- 3. Sourced UDF which takes an XML variable as the input parameter +-- and returns XML value as output. +-- +-- 4. SQL bodied UDF which takes an XML variable as the input parameter +-- and returns a table with XML values as output. This UDF +-- internally calls a stored procedure which takes an XML variable +-- as the input parameter and returns an XML value as output. +-- +----------------------------------------------------------------------------- +-- SETUP +----------------------------------------------------------------------------- +-- Connect to sample database +CONNECT TO sample@ + +----------------------------------------------------------------------------- +-- Setting up tables for the sample +----------------------------------------------------------------------------- + +-- Create table 'sales_department' +CREATE TABLE sales_department(dept_id CHAR(10), dept_info XML)@ + +-- Create table 'sales_employee' +CREATE TABLE sales_employee (emp_id INTEGER, total_sales INTEGER, emp_details XML)@ + +-- Create table 'performance_bonus_employees' +CREATE TABLE performance_bonus_employees(bonus_info XML)@ + +-- Insert values into 'sales_employee' table +INSERT INTO sales_employee VALUES (5001, 40000, XMLPARSE(document +' + Lethar Kessy +
+ 555 M G Road + Bangalore + Karnataka + India + 411004 +
+ 27-01-1954 + Male + + 9435344354 + + lethar@company.com + DS02 + 7 + 40000 + 25500 + Sr. Manager + regular + Harry +
'))@ + +INSERT INTO sales_employee VALUES (5002, 50000, XMLPARSE(document +' + Mathias Jessy +
Indra Nagar Road No. 5 + Bangalore + Karnataka + India + 411004 +
+ 17-01-1974 + Female + + 9438884354 + + jessy@company.com + DS02 + 6 + 50000 + 22500 + Manager + regular + Harry +
'))@ + +INSERT INTO sales_employee VALUES (5003, 40000, XMLPARSE(document +' + Mohan Kumar +
+ Vijay Nagar Road No. 5 + Bangalore + Karnataka + India + 411004 +
+ 21-11-1974 + Male + + 9438881234 + + Mohan@company.com + DS02 + 5 + 40000 + 15500 + Associate Manager + regular + Harry +
'))@ + +-- Insert values into 'sales_department' table +INSERT INTO sales_department VALUES ('DS02', XMLPARSE(document +' + sales + + Harry Thomas + + 9732432423 + + +
+ Bannerghatta + Bangalore + Karnataka + India + 560012 +
+ + 080-23464879 + 080-56890728 + 080-45282976 + +
'))@ + +----------------------------------------------------------------------------- +-- 1. UDF Scalar function which takes an XML variable as input parameter +-- and returns an XML value as output. +---------------------------------------------------------------------------- + +-- Create a scalar function 'getDeptContactNumbers' which returns a list +-- of department phone numbers +CREATE FUNCTION getDeptContactNumbers(dept_info_p XML) +RETURNS XML +LANGUAGE SQL +SPECIFIC contactNumbers +NO EXTERNAL ACTION +BEGIN ATOMIC + + -- Return a list of department phone numbers + RETURN XMLQuery('document {{$dep/department/phone}}' + PASSING dept_info_p as "dep"); + +END@ + +-- Call scalar UDF 'getDeptContactNumbers' to get contact numbers of +-- the department "DS02" +SELECT getDeptContactNumbers(sales_department.dept_info) +FROM sales_department +WHERE dept_id = 'DS02'@ + +---------------------------------------------------------------------------- +-- 2. UDF Table function which takes an XML variable as input parameter +-- and returns a table with XML values as output. +---------------------------------------------------------------------------- + +-- The store opens new branches in different parts of the city. +-- The book store manager wants to promote senior managers and associate +-- managers and designate them to manage these new branches. He wants to +-- update the skill level and salaries of all the promoted managers in the +-- sales_employee table. He asks the DBA to create a table function for +-- this requirement. The DBA creates the 'updatePromotedEmployeesInfo' +-- table function. This function updates the skill level and salaries of +-- the promoted managers in sales_employee table and returns details of +-- all the managers who got promoted. + +CREATE FUNCTION updatePromotedEmployeesInfo(emp_id_p INTEGER) +RETURNS TABLE (name VARCHAR(50), emp_id integer, skill_level integer, + salary double, address XML) +LANGUAGE SQL +MODIFIES SQL DATA +SPECIFIC func1 +BEGIN ATOMIC + + -- Update the skill_level and salary for the Sr. manager promoted to + -- Area sales manager. + + UPDATE sales_employee SET emp_details = XMLQuery('transform + copy $emp_info := $emp + modify if ($emp_info/employee[skill_level = 7 and + designation = "Sr. Manager"]) + then + ( + do replace value of $emp_info/employee/skill_level with 8, + do replace value of $emp_info/employee/salary with + $emp_info/employee/salary * 9.5 + ) + else if ($emp_info/employee[skill_level = 6 and + designation = "Manager"]) + then + ( + do replace value of $emp_info/employee/skill_level with 7, + do replace value of $emp_info/employee/salary with + $emp_info/employee/salary * 7.5 + ) + else if ($emp_info/employee[skill_level = 5 and + designation = "Associate Manager"]) + then + ( + do replace value of $emp_info/employee/skill_level with 6, + do replace value of $emp_info/employee/salary with + $emp_info/employee/salary * 5.5 + ) + else () + return $emp_info' PASSING emp_details as "emp") + WHERE emp_id = emp_id_p; + + -- To return the updated details of promoted employees, create a + -- relational view of employee_details XML document using XMLTABLE + -- function. + RETURN SELECT X.* + FROM sales_employee, XMLTABLE('$e_info/employee' PASSING + emp_details as "e_info" + COLUMNS + name VARCHAR(50) PATH 'name', + emp_id integer PATH '@id', + skill_level integer path 'skill_level', + salary double path 'salary', + addr XML path 'address') AS X WHERE sales_employee.emp_id = emp_id_p; + +END@ + +-- Call the 'updatePromotedEmployeesInfo' table function to update the details +-- of promoted employees in 'sales_employee' table +SELECT A.* + FROM sales_employee AS E, table(updatePromotedEmployeesInfo(E.emp_id)) AS A@ + + +---------------------------------------------------------------------------- +-- 3. Sourced UDF which takes an XML variable as the input parameter +-- and returns an XML value as output. +---------------------------------------------------------------------------- +-- The store manager would like to get a particular dept manager name and +-- his contact numbers. The DBA then creates a 'getManagerDetails' UDF to get +-- a particular department manager name and manager contact details. + +CREATE FUNCTION getManagerDetails(dept_info_p XML, dept_p VARCHAR(5)) +RETURNS XML +LANGUAGE SQL +SPECIFIC getManagerDetails +BEGIN ATOMIC +DECLARE tmp XML; + + -- Return manager name and manager contact details of 'dept_p' + -- department + RETURN XMLQuery('$info/department[name=$dept_name]/manager' + PASSING dept_info_p as "info", dept_p as "dept_name"); + +END@ + +-- Create a sourced UDF 'getManagerInfo' based on 'getManagerDetails' +-- user defined function +CREATE FUNCTION getManagerInfo(XML, CHAR(10)) +RETURNS XML +SOURCE getManagerDetails(XML, VARCHAR(5))@ + +-- Call the sourced UDF 'getManagerInfo' to get 'sales' department +-- manager details +SELECT getManagerInfo(sales_department.dept_info, 'sales') +FROM sales_department +WHERE dept_id='DS02'@ + + +------------------------------------------------------------------------- +-- 4. SQL bodied UDF which takes an XML variable as the input parameter +-- and returns a table with XML values as output. This UDF +-- calls a stored procedure which takes an XML variable +-- as the input parameter and returns an XML value as output. +-------------------------------------------------------------------------- + +-- Create a function which calculates an employee gift cheque amount and +-- adds this value as a new element into the employee information document + +CREATE PROCEDURE calculateGiftChequeAmount(INOUT emp_info_p XML, +IN emp_name_p VARCHAR(20)) +LANGUAGE SQL +MODIFIES SQL DATA +SPECIFIC customer_award +BEGIN +DECLARE emp_bonus_info_v XML; + + IF XMLEXISTS('$e_info/employee[name = $emp1]' PASSING emp_info_p as "e_info", + emp_name_p as "emp1") + THEN + + -- Calculate employee gift cheque amount and add a new element + -- 'customer_gift_cheque' to employee info document + SET emp_bonus_info_v = XMLQuery('copy $bonus := $info + modify + do insert {$bonus/employee/salary * 0.50 + 25000} + into $bonus/employee + return $bonus' PASSING emp_info_p as "info"); + END IF; + + -- Set output parameter value 'emp_info_p' with newly calculated + -- bonus information + SET emp_info_p = emp_bonus_info_v; + +END@ + + +-- Some employees who got customer appreciation awards and whose +-- total sales are greater than expected sales were given gift +-- cheques by the store. The DBA creates 'calculatePerformanceBonus' +-- function to calculate employee performance bonus along with +-- customer gift cheque amount and update the employee information +-- in sales_employee table. + +CREATE FUNCTION calculatePerformanceBonus(sales_info_p XML) +RETURNS table(info XML) +LANGUAGE SQL +SPECIFIC awardedemployees +MODIFIES SQL DATA +BEGIN ATOMIC +DECLARE awarded_emp_info_v XML; +DECLARE emp_name VARCHAR(20); +DECLARE min_sales_v INTEGER; +DECLARE avg_sales_v INTEGER; + + -- Extract minimum and average sales from input XML document + SET min_sales_v = XMLCAST(XMLQuery('$info/sales_per_annum/min_sales' + PASSING sales_info_p as "info") AS INTEGER); + + SET avg_sales_v = XMLCAST(XMLQuery('$info/sales_per_annum/avg_sales' + PASSING sales_info_p as "info") AS INTEGER); + + -- Loop through the employee records and select all the employees + -- whose total sales value is between target_sales and min_sales. + FOR_LOOP: FOR EACH_ROW AS + SELECT XMLCAST(XMLQuery('$info/employee/name' PASSING awarded_emp_info_v + as "info") AS VARCHAR(20)) as name, + XMLQuery('copy $e_info := $inf + modify + do insert {$e_info/employee/salary + * 0.25 + 5000} + into $e_info/employee + return $e_info' PASSING emp_details as "inf") + as info + FROM sales_employee + WHERE total_sales between min_sales_v and avg_sales_v + DO + + -- For the selected employee, calculate performance bonus and add a new + -- element 'performance_bonus' to employee info document + SET awarded_emp_info_v = EACH_ROW.info; + + -- Get the employee name + SET emp_name = EACH_ROW.name; + + -- Call the stored procedure 'calculateGiftChequeAmount' to calculate + -- gift cheque amount for the above selected employee + CALL calculateGiftChequeAmount(awarded_emp_info_v, emp_name); + + -- Insert records of employees who got performance bonus and + -- gift cheques into 'performance_bonus_employees' table + INSERT INTO performance_bonus_employees + VALUES (EACH_ROW.info); + + END FOR; + + -- Return updated employees information + RETURN SELECT * FROM performance_bonus_employees; + +END@ + +-- Call the table function 'calculatePerformanceBonus' to get the +-- information of all the employees who got gift cheques +-- and performance bonus. +SELECT * FROM table(calculatePerformanceBonus(XMLPARSE(document +' + 80000 + 70000 + 35000 +')))@ + +------------------------------------------------------------------------- +-- CLEANUP +------------------------------------------------------------------------- +DROP FUNCTION getDeptContactNumbers@ +DROP FUNCTION updatePromotedEmployeesInfo@ +DROP FUNCTION getManagerInfo@ +DROP FUNCTION calculatePerformanceBonus@ +DROP PROCEDURE calculateGiftChequeAmount@ +DROP TABLE sales_employee@ +DROP TABLE sales_department@ +DROP TABLE performance_bonus_employees@ +DROP FUNCTION getManagerDetails@ + diff --git a/xml/clp/xmlupdel.db2 b/xml/clp/xmlupdel.db2 new file mode 100644 index 0000000..b1f0698 --- /dev/null +++ b/xml/clp/xmlupdel.db2 @@ -0,0 +1,189 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xmlupdel.db2 +-- +-- SAMPLE: This sample shows how to update and delete XML documents from +-- the table. +-- +-- SQL STATEMENTS USED: +-- SELECT +-- INSERT +-- UPDATE +-- DELETE +-- +-- XML FUNTIONS USED: +-- XMLPARSE +-- XMLSERIALIZE +-- XMLVALIDATE +-- XMLCAST +-- XMLELEMENT +-- XMLATTRIBUTES +-- +-- OUTPUT FILE: xmlupdel.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to sample +CONNECT TO sample; + +-- create table 'oldcustomer' having XML column +CREATE TABLE oldcustomer(ocid integer, + firstname varchar(15), + lastname varchar(15), + addr varchar(300), + information XML); + +-- insert rows into the table 'oldcustomer'. + +INSERT INTO oldcustomer + VALUES(1009, 'Rahul','kumar', 'Rahul25Markham + OntarioN9C-3T6905-555-7258', XMLPARSE + (document '
25 WestendMarkham + Ontario
'preserve whitespace)); + +-- insert a row into table 'customer' +INSERT INTO customer(cid, info) + VALUES(1008, XMLPARSE(document ' + divya' preserve whitespace)); + +--------------------------------------------------------------------------- +-- a simple update using 'constant string(varchar)' + +-- display the contents of the 'customer' table +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +UPDATE customer + SET info = XMLPARSE(document'rohit + park streetdelhi + 'preserve whitespace) + WHERE cid = 1008; + +-- display the contents of the 'customer' table (after updation) +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +--------------------------------------------------------------------------- + +-- update where source is from 'another XML column' + +-- display the contents of the 'customer' table +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +-- display the contents of the 'oldcustomer' table +SELECT ocid, XMLSERIALIZE(information as varchar(600)) + FROM oldcustomer + WHERE ocid = 1009; + +UPDATE customer + SET info = (SELECT information + FROM oldcustomer p + WHERE p.ocid = 1009) + WHERE cid=1008; + +-- display the contents of the 'customer' table (after updation) +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +-------------------------------------------------------------------------- +-- update where source is from 'another string column' + +-- display the contents of the 'customer' table +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +-- display the contents of the 'oldcustomer' table +SELECT addr + FROM oldcustomer + WHERE ocid = 1009; + +UPDATE customer + SET info = (SELECT XMLPARSE(document addr preserve whitespace) + FROM oldcustomer p + WHERE p.ocid = 1009) + WHERE cid = 1008; + +-- display the contents of the 'customer' table (after updation) +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +-------------------------------------------------------------------------- +-- update with validation where source is 'typed of varchar' + +-- display the contents of the 'customer' table +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +-- display the contents of the 'oldcustomer' table +SELECT addr + FROM oldcustomer + WHERE ocid = 1009; + +UPDATE customer + SET info = (SELECT XMLVALIDATE(XMLPARSE(document addr preserve whitespace) + according to XMLSCHEMA ID customer) + FROM oldcustomer p + WHERE p.ocid = 1009) + WHERE cid = 1008; + +-- display the contents of the 'customer' table (after updation) +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +--------------------------------------------------------------------------- +-- delete row containing 'XML data' + +-- display the contents of the 'customer' table +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +DELETE FROM customer + WHERE cid = 1008; + +-- display the contents of the 'customer' table (after deletion) +SELECT cid, XMLSERIALIZE(info as varchar(600)) + FROM customer + WHERE cid = 1008; + +-- cleanup +DROP TABLE oldcustomer; diff --git a/xml/clp/xmlxslt.db2 b/xml/clp/xmlxslt.db2 new file mode 100644 index 0000000..3f498d5 --- /dev/null +++ b/xml/clp/xmlxslt.db2 @@ -0,0 +1,225 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: xmlxslt.db2 +-- +-- PURPOSE: The purpose of this sample is to show: +-- 1. Using the XSLTRANSFORM function to convert one XML document to +-- another using an XSLT stylesheet. +-- 2. Passing an XSL parameter document to the XSLTRANSFORM function +-- at runtime. +-- +-- USAGE SCENARIO: A supermarket manager maintains a webpage to show +-- the details of the products available in his shop. +-- He maintains two tables, namely "product_details" +-- and "display_productdetails". +-- The "product_details" table contains information about +-- all of the products available in his shop, where the +-- details for each product are in an XML document format. +-- The "display_productdetails" table contains the XSLT +-- stylesheet, which specifies how to display the product +-- details on the webpage. +-- +-- PREREQUISITE: The SAMPLE database should exist before running this sample. +-- +-- EXECUTION: db2 -tvf xmlxslt.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Displays new XML documents that result from XSLT conversion. +-- +-- OUTPUT FILE: xmlxslt.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT +-- DROP +-- +-- SQL/XML FUNCTIONS USED: +-- XSLTRANSFORM +-- +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- +-- +-- SAMPLE DESCRIPTION +-- +----------------------------------------------------------------------------- +-- 1. Using the XSLTRANSFORM function to convert one XML document to another +-- using an XSLT stylesheet. +-- 1.1 Insert an XML document into the "product_details" table. +-- 1.2 Insert an XSL stylesheet into the "display_productdetails" table. +-- 1.3 Display the new XML document after transforming the XML document +-- in the "product_details" table using the XSL stylesheet. +-- +-- 2. Passing an XSL parameter document to the XSLTRANSFORM function +-- at runtime. +-- 2.1 Insert a parameter document into the "param_tab" table. +-- 2.2 Display the new XML document after transforming the XML document +-- in the "product_details" table using the XSL stylesheet with +-- the parameter document. +-- +----------------------------------------------------------------------------- +-- +-- SETUP +-- +----------------------------------------------------------------------------- + +-- Connect to the sample database +CONNECT TO SAMPLE; + +----------------------------------------------------------------------------- +-- 1. Using the XSLTRANSFORM function to convert one XML document to another +-- using an XSLT stylesheet. +----------------------------------------------------------------------------- +-- Create the table "product_details" +CREATE TABLE product_details (productid INTEGER, description XML); + +-- Create table "display_productdetails" +CREATE TABLE display_productdetails (productid INTEGER, stylesheet CLOB (10M)); + +------------------------------------------------------------------------------ +-- 1.1 Insert an XML document into the "product_details" table. +------------------------------------------------------------------------------ + +-- Insert an XML document into the "product_details" table +INSERT INTO product_details +VALUES (1, ' + + + + Ice Scraper, Windshield 4 inch +
Basic Ice Scraper 4 inches wide, foam handle
+ 3.99 +
+ BIG BAZAR +
+
'); + +------------------------------------------------------------------------------ +-- 1.2 Insert an XSL stylesheet into the "display_productdetails" table. +------------------------------------------------------------------------------ + +-- Insert values into the "display_productdetails" table +INSERT INTO display_productdetails +VALUES(1,' + + + + + + +

+ + + + + + + + + + + + + + +
+
product IDproduct namepricedetailssupermarket name
+ + +
+ + + + + + + + + + + + + +
' +); + +---------------------------------------------------------------------------- +-- 1.3 Display the new XML document after transforming the XML document +-- in the "product_details" table using the XSL stylesheet. +---------------------------------------------------------------------------- + +-- Display the final document +SELECT XSLTRANSFORM (description USING stylesheet AS CLOB (10M)) +FROM product_details X, display_productdetails D +WHERE X.productid = D.productid; + +---------------------------------------------------------------------------- +-- 2. Passing an XSL parameter document to the XSLTRANSFORM function +-- at runtime. +-- +----------------------------------------------------------------------------- + +-- Create the table "param_tab" +CREATE TABLE param_tab (productid INTEGER, param VARCHAR (1000)); + + +----------------------------------------------------------------------------- +-- 2.1 Insert parameter document into the table "param_tab". +----------------------------------------------------------------------------- + +-- Insert parameter values into the "param_tab" table +INSERT INTO param_tab +VALUES (1, ' + + + BIG BAZAR super market + '); + +----------------------------------------------------------------------------- +-- 2.2 Display the new XML document after transforming the XML document +-- in the "product_details" table using the XSL stylesheet with +-- the parameter document. +----------------------------------------------------------------------------- + +-- Display the final document +SELECT XSLTRANSFORM (description USING stylesheet WITH param AS CLOB (1M)) +FROM product_details X, param_tab P, display_productdetails D +WHERE X.productid=P.productid AND X.productid = D.productid; + +---------------------------------------------------------------------------- +-- +-- CLEANUP +-- +---------------------------------------------------------------------------- +-- Drop all of the tables +DROP TABLE param_tab; +DROP TABLE product_details; +DROP TABLE display_productdetails; diff --git a/xml/clp/xrpart.db2 b/xml/clp/xrpart.db2 new file mode 100644 index 0000000..428c5dd --- /dev/null +++ b/xml/clp/xrpart.db2 @@ -0,0 +1,568 @@ +------------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +------------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xrpart.db2 +-- +-- SAMPLE: +-- This sample showcases the support for XML in partitioned tables. +-- +-- PREREQUISITE: +-- 1)Sample database is setup on the machine. +-- +-- Usage Scenario: +-- +-- The sample refers to a retail store which uses seven tables to store +-- data for the store operations. These tables are Product, PurchaseOrder, +-- Customer, Suppliers and four different tables to store purchase order data +-- for every year. +-- The PurchaseOrder table, which stores data for year 2007, contains an +-- XML column 'pOrder' which contains details about the purchase orders. The +-- purchase orders are large XML documents. To get better performance the DBA +-- decides to partition the PurchaseOrder table into four partitions based on +-- the order date. +-- +-- The retail store would like to maintain data for five years in one table. +-- The store takes advantage of the table partitioning feature and ATTACHes the +-- purchase order tables for year 2003, 2004, 2005 and 2006 as four separate +-- partitions to the purchaseOrder table. As the year progresses a partition is +-- ADDed to the PurchaseOrder table for every quarter to store the huge volume +-- of data. The retail store also DETACHes partitions containing old data +-- (data older by five years) that is rarely or never accessed. +-- The store can Backup or Archive the stand-alone table which is a direct result +-- of DETACHing a partition from the PurchaseOrder table. +-- +-- During winters the retail store sells many new products, such as 'snow +-- shovel'. These products are very popular and are purchased by many customers, +-- resulting in most of the purchase orders containing them. The store's supply +-- department needs to frequently query the 'purchaseOrder' table to decide, what +-- products and quantity the store should restock. The retail store DBA decides +-- to create an index on the pOrder columns containing the purchase order XML +-- documents for faster data retrieval. +-- +-- An employee from the stores department is given only a VIEW containing +-- columns from the PurchaseOrder and the Product table to restrict access to +-- other data, such as customer or transaction information. To improve query +-- performance, the developer also creates multiple INDEXes on the PurchaseOrder +-- table, with a particular XML pattern or value, for products which are in +-- great demand and frequently queried. +-- +-- SQL STATEMENTS USED: +-- CREATE +-- SELECT +-- INSERT +-- UPDATE +-- ALTER +-- SET INTEGRITY +-- +----------------------------------------------------------------------------- + +-- /***************************************************************************/ +-- /* SAMPLE DESCRIPTION */ +-- /***************************************************************************/ +-- /* 1.Create a partitioned TABLE (with a column of type XML) */ +-- /* 2.INSERT data into the table */ +-- /* 3.ATTACH a partition to the table */ +-- /* 4.ADD partitions to the table */ +-- /* 5.DETACH a partition from the table */ +-- /* 6.Create an XML Value Index on the XML column */ +-- /* 7.Create a VIEW over the partitioned table */ +-- /***************************************************************************/ + +-- /***************************************************************************/ +-- /* The Retail Store has created tables 'StoreProducts', */ +-- /* 'StoreSuppliers' and 'PurchaseOrder' to store */ +-- /* details about their day-to-day transactions. */ +-- /* These table are created in two tablespaces: 'Rcommon_Tbspace' and */ +-- /* 'Rcommon_Ltbspace'. */ +-- /***************************************************************************/ + +-- Connect to the sample database + +CONNECT TO sample; + +-- Create two table spaces 'Rcommon_Tbspace', 'Rcommon_Ltbspace'. +-- The regular data from all the tables will be placed in 'Rcommon_Tbspace' +-- table space. Any long data will be placed in 'Rcommon_Ltbspace' table space. + +SET SCHEMA = store; +CREATE BUFFERPOOL Rcommon_Buffer IMMEDIATE SIZE 1000 AUTOMATIC PAGESIZE 4K; +CREATE TABLESPACE Rcommon_Tbspace PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'rcont_com1' 10000, FILE 'rcont_com2' 10000, FILE 'rcont_com3' 10000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; +CREATE TABLESPACE Rcommon_Ltbspace PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'rcont_comL' 20000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; + +-- Create 'StoreProducts' table to contain details about the products +-- available in the store. + + +CREATE TABLE StoreProducts (id BIGINT NOT NULL PRIMARY KEY, + name VARCHAR(50), + quantity INT, + price DECFLOAT, + description VARCHAR(100)) IN Rcommon_Tbspace; + +-- Insert details about the Products in the store + +INSERT INTO StoreProducts VALUES + (100,'Snow Shovel, Deluxe 24 inch',50, 19.99, + 'Shovel made of wool, keep you warm in winter'); + +INSERT INTO StoreProducts VALUES + (102,'Snow Shovel, Super Deluxe 26 inch',50, 49.99, + 'Shovel made of wool, keep you warm in winter'); + +INSERT INTO StoreProducts VALUES + (103,'Snow Shovel, Basic 22 inch',50, 49.99, + 'Shovel made of wool, keep you warm in winter'); + +INSERT INTO StoreProducts VALUES + (104,'Ice Scraper, Windshield 4 inch',50, 3.99,''); + +INSERT INTO StoreProducts VALUES + (105,'Hand Gloves',50, 19.99,''); + +-- Create 'StoreSuppliers' table to contain details about the Suppliers +-- for the store. + +CREATE TABLE StoreSuppliers (id BIGINT, + name VARCHAR(20), + pid BIGINT, + quantityPresent INT, + unitprice DECFLOAT, + description VARCHAR(100)) IN Rcommon_Tbspace; + +-- Insert details about the Suppliers of the store + +INSERT INTO StoreSuppliers values (1,'Al',101,300,15.99,''); +INSERT INTO StoreSuppliers values (1,'Al',102,250,44.99,''); +INSERT INTO StoreSuppliers values (1,'Al',103,350,43.99,''); +INSERT INTO StoreSuppliers values (2,'Jamel',104,150,3.00,''); +INSERT INTO StoreSuppliers values (3,'James',105,200,17.99,''); + +-- Create four purchase order tables to contain data for all the +-- purchase orders placed by customer, including +-- table 'purchaseOrder2003' for the year 2003, 'purchaseOrder2004' for the +-- year 2004, 'purchaseOrder2005' for the year 2005, 'purchaseOrder2006' for +-- the year 2006. Initially, the store had a purchase order table with columns +-- to have only details about the purchase order placed by the customer; +-- later, they decided to have a XML column to save the feedback given by the +-- customer. + +CREATE TABLE purchaseOrder2003 ( id INT NOT NULL, + status VARCHAR(10), + orderDate DATE, + customerID INT, + pOrder XML) + PARTITION BY RANGE (orderDate) + (STARTING FROM '2003-01-01' ENDING '2003-12-31') +IN Rcommon_Tbspace LONG IN Rcommon_Ltbspace; + +CREATE TABLE purchaseOrder2004 ( id INT NOT NULL, + status VARCHAR(10), + orderDate DATE, + customerID INT, + pOrder XML) + PARTITION BY RANGE (orderDate) + (STARTING FROM '2004-01-01' ENDING '2004-12-31') +IN Rcommon_Tbspace LONG IN Rcommon_Ltbspace; + + +CREATE TABLE purchaseOrder2005 ( id INT NOT NULL, + status VARCHAR(10), + orderDate DATE, + customerID INT, + pOrder XML) + PARTITION BY RANGE (orderDate) + (STARTING FROM '2005-01-01' ENDING '2005-12-31') +IN Rcommon_Tbspace LONG IN Rcommon_Ltbspace; + +CREATE TABLE purchaseOrder2006 ( id INT NOT NULL, + status VARCHAR(10), + orderDate DATE, + customerID INT, + pOrder XML) + PARTITION BY RANGE (orderDate) + (STARTING FROM '2006-01-01' ENDING '2006-12-31') +IN Rcommon_Tbspace LONG IN Rcommon_Ltbspace; + +-- For the year 2007, the retail store decides to create a table which is +-- partitioned for every quarter to store the orders placed by the customer. +-- Each partition will be placed in a separate table space. +-- Four table spaces ('RTbspace1', 'RTbspace2', 'RTbspace3' and 'RTbspace4') are +-- created to contain relational data from the new 'purchaseOrder_Details' table. +-- Four table spaces ('RLtbspace1', 'RLtbspace2', 'RLtbspace3' and 'RLtbspace4') are +-- created to contain long data from the new 'purchaseOrder_Details' table. + +CREATE TABLESPACE RTbspace1 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'rcont1' 10000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; +CREATE TABLESPACE RTbspace2 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'rcont2' 10000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; +CREATE TABLESPACE RTbspace3 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'rcont3' 10000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; +CREATE TABLESPACE RTbspace4 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'rcont4' 10000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; + +-- The purchase order information is an XML document. To store XML +-- data, a large tablespace will be used. +-- Therefore four, large table spaces are created to store XML data for these +-- partition. + +CREATE TABLESPACE RLtbspace1 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lrcont1' 20000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; +CREATE TABLESPACE RLtbspace2 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lrcont2' 20000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; +CREATE TABLESPACE RLtbspace3 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lrcont3' 20000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; +CREATE TABLESPACE RLtbspace4 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'Lrcont4' 20000) + PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; + +-- Create two tablespaces 'RInd_Tbspace' and 'RGlobal_IndTbspace' to store all +-- the index data. Create 4 tablespaces 'Ind_Tbspace1', 'Ind_Tbspace2', 'Ind_Tbspace3', +-- 'Ind_Tbspace4' to store all index data for four data ranges. + +CREATE TABLESPACE RInd_Tbspace MANAGED BY DATABASE + USING (FILE 'rcont_index' 10000); +CREATE TABLESPACE RGlobal_IndTbspace MANAGED BY DATABASE + USING (FILE 'rcont_globalInd' 10000); + +CREATE TABLESPACE Ind_Tbspace1 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont_index1' 10000) +PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; + +CREATE TABLESPACE Ind_Tbspace2 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont_index2' 10000) +PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; + +CREATE TABLESPACE Ind_Tbspace3 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont_index3' 10000) +PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; + +CREATE TABLESPACE Ind_Tbspace4 PAGESIZE 4K MANAGED BY DATABASE + USING (FILE 'cont_index4' 10000) +PREFETCHSIZE 4K BUFFERPOOL Rcommon_Buffer; + + + +-- Create 'purchaseOrder_Details' table partitioned by 'orderDate' for every +-- quarter. Data for this table will be stored in tablespaces created above +-- ('RTbspace1','RTbspace2','RTbspace3','RTbspace4'). Long data will be stored in +-- large tablespaces created above ('RLtbspace1','RLtbspace2','RLtbspace3', +-- 'RLtbspace4'). Index created will be stored in a tablespace created for +-- storing indexes ('RInd_Tbspace'). + +CREATE TABLE purchaseOrder_Details ( id INT NOT NULL, + status VARCHAR(10), + orderDate DATE, + customerID INT, + pOrder XML) + INDEX IN RInd_Tbspace PARTITION BY RANGE (orderDate) + (PART part1 STARTING FROM '2007-01-01' ENDING '2007-03-31' IN RTbspace1 INDEX IN Ind_Tbspace1 LONG IN RLtbspace1, + PART part2 STARTING FROM '2007-04-01' ENDING '2007-06-30' IN RTbspace2 INDEX IN Ind_Tbspace2 LONG IN RLtbspace2, + PART part3 STARTING FROM '2007-07-01' ENDING '2007-09-30' IN RTbspace3 INDEX IN Ind_Tbspace3 LONG IN RLtbspace3, + PART part4 STARTING FROM '2007-10-01' ENDING '2007-12-31' IN RTbspace4 INDEX IN Ind_Tbspace4 LONG IN RLtbspace4); + +-- Insert data into the 'purchaseOrder_Details' table + + +INSERT INTO purchaseOrder_Details(id,status,orderDate,customerID,pOrder) VALUES + (1001,'Unshipped','2007-04-20',101, + ' + + 101 + Snow Shovel, Deluxe 24 inch + 1 + 19.99 + + + 102 + Snow Shovel, Super Deluxe 26 inch + 9 + 49.99 + + + 104 + Ice Scraper, Windshield 4 inch + 1 + 3.99 + + ' ); + + + +INSERT INTO purchaseOrder_Details(id, status, orderDate, customerID, pOrder) VALUES + (1000,'Unshipped','2007-02-20',100, + ' + + 103 + Snow Shovel, Basic 22 inch + 5 + 49.99 + + + 102 + Snow Shovel, Super Deluxe 26 inch + 13 + 49.99 + + ' ); + +INSERT INTO purchaseOrder_Details(id, status, orderDate, customerID, pOrder) VALUES + (1002,'Unshipped','2007-06-24',100, + ' + + 104 + Ice Scraper, Windshield 4 inch + 10 + 3.99 + + + 102 + Snow Shovel, Super Deluxe 26 inch + 8 + 49.99 + + ' ); + +INSERT INTO purchaseOrder_Details(id, status, orderDate, customerID, pOrder) VALUES + (1003,'Unshipped','2007-06-24',103, + ' + + 105 + Hand Gloves + 3 + 19.99 + + + 102 + Snow Shovel, Super Deluxe 26 inch + 15 + 49.99 + + ' ); + +-- Create an index on the items purchased by the customer. +-- This will help retrieve details about the purchase order faster. +-- The IN clause specifies the tablespace where the INDEX created will be placed. +-- This clause overrides the any INDEX IN clause, specified during the creation of the +-- table. + +CREATE INDEX pIndex ON purchaseOrder_Details(pOrder) + GENERATE KEY USING XMLPATTERN '/PurchaseOrder/item/name' AS SQL VARCHAR(60) NOT PARTITIONED + IN RGlobal_IndTbspace; + +-- Create an index on the items and date of purchase for the purchase made by the customer + + +CREATE INDEX DateIndex ON store.purchaseOrder_Details(pOrder) + GENERATE KEY USING XMLPATTERN '/PurchaseOrder/@OrderDate' AS SQL VARCHAR(60) PARTITIONED; + +CREATE INDEX NameIndex ON store.purchaseOrder_Details(pOrder) + GENERATE KEY USING XMLPATTERN '/PurchaseOrder/item/name' AS SQL VARCHAR(60) PARTITIONED; + +-- Statistics is collected on the table 'purchaseOrder_Details' by +-- executing RUNSTATS on it. With the new statistics obtained, DB2 uses +-- the index pIndex on the table for processing any further queries on +-- the table 'purchaseOrder_Details' which uses the predicate 'name' of +-- the XML document. + +RUNSTATS ON TABLE store.purchaseOrder_Details FOR INDEXES ALL; + +-- The retail store can checks for any orders that are not delivered. + +SELECT id FROM purchaseOrder_Details WHERE status = 'Unshipped' ORDER BY id; + +-- Once the item is shipped, 'purchaseOrder_Details' table is updated +-- to reflect the status of the product delivered. (Status is changed from +-- Unshipped to Shipped). +-- The 'purchaseOrder_Details' table is also updated to contain any feedback from +-- the customer. + +UPDATE purchaseorder_Details +SET porder = + xmlquery('transform + copy $po := $order + modify do replace value of $po/PurchaseOrder/@Status with "Shipped" + return $po' + passing pOrder as "order"), status = 'Shipped' WHERE id=1000; + + +-- /***************************************************************************/ +-- /* The retail store decides to keep all the purchase order information */ +-- /* from the last five years in 'PurchaseOrder_Details' table. */ +-- /* To do that, the store ATTACHes the four purchaseOrder tables created */ +-- /* earlier, 'purchaseOrder2003', 'purchaseOrder2004', 'purchaseOrder2005' */ +-- /* and 'purchaseOrder2006' to the main table, which is */ +-- /* 'purchaseOrder_Details'. */ +-- /* For the year 2008, the store ADDs new partition to the */ +-- /* 'purchaseOrder_Details' table for every quarter. */ +-- /***************************************************************************/ + +-- ALTER the purchaseOrder_Details table to ATTACH partitions 'part2003', +-- 'part2004', 'part2005' and 'part2006' from tables 'purchaseOrder2003', +-- 'purchaseOrder2004', 'purchaseOrder2005', 'purchaseOrder2006'. + +ALTER TABLE purchaseOrder_Details ATTACH PARTITION part2003 + STARTING FROM '2003-01-01' ENDING '2003-12-31' INCLUSIVE FROM purchaseOrder2003; +ALTER TABLE purchaseOrder_Details ATTACH PARTITION part2004 + STARTING FROM '2004-01-01' ENDING '2004-12-31' INCLUSIVE FROM purchaseOrder2004; +ALTER TABLE purchaseOrder_Details ATTACH PARTITION part2005 + STARTING FROM '2005-01-01' ENDING '2005-12-31' INCLUSIVE FROM purchaseOrder2005; +ALTER TABLE purchaseOrder_Details ATTACH PARTITION part2006 + STARTING FROM '2006-01-01' ENDING '2006-12-31' INCLUSIVE FROM purchaseOrder2006; + +-- The 'purchaseOrder_Details' table goes into Set Integrity Pending State after the +-- partitions are attached. +-- The table has to be brought out of Set Integrity Pending State before performing +-- any operation on it. + +SET INTEGRITY FOR purchaseOrder_Details IMMEDIATE CHECKED; + +-- As per the retail store policy only, five years data is maintained +-- in the table. The retail store DETACHes a partition from the table +-- 'purchaseOrder_Details' when they ADD a partition for 2008. +-- ALTER the 'purchaseOrder_Details' table to contain a new column +-- 'customerFeedback'. Populate this column with some feedback for order id 1000. +-- The DETACHed partition contains data from the year 2003 and is available as a +-- stand-alone table after the DETACH. + +ALTER TABLE purchaseOrder_Details ADD PARTITION part2008a + STARTING FROM '2008-01-01' ENDING '2008-03-31' INCLUSIVE IN RTbspace1 LONG IN RLtbspace1; + +ALTER TABLE purchaseOrder_Details ADD COLUMN customerFeedback XML; + +-- Reorganize the table and all indexes defined on a table by rebuilding the index data into +-- unfragmented, physically contiguous pages. This improves the performance of query. +-- NOTE :: REORG is also possible at partition level. + +REORG TABLE purchaseorder_Details; +REORG INDEX pIndex FOR TABLE purchaseorder_Details ALLOW READ ACCESS CLEANUP ONLY; +REORG INDEXES ALL FOR TABLE purchaseorder_Details ON DATA PARTITION part2; + +ALTER TABLE purchaseOrder_Details DETACH PARTITION part2003 INTO TABLE purchaseOrder2003; + + +-- Table purchaseOrder_Details is updated to contain the feedback from a customer + +UPDATE purchaseOrder_Details +SET customerFeedback = ' + + Snow Shovel, Basic 22 inch + + + Snow Shovel, Super Delux 26 inch + Snow Shovel is very Good, But + a little bit expensive + + ' where id = 1000; + + + + +-- Store manager selects from purchaseOrder_Details, purchase order and customerFeedback for +-- 1000th purchase order. +Select pOrder, customerFeedback FROM purchaseOrder_Details WHERE id = 1000; +-- A view is created which comprise of data from table 'product' and +-- 'purchaseOrder_Details' table, so that the employee of the store can +-- manipulate over the view and decide over the products in demand and +-- replenish the stocks in the store. + +CREATE VIEW PurchaseOrderView (ID,NAME,QUANTITY,QuantityAvail,orderDate) + AS + SELECT p.id, v.name, v.quantity, p.Quantity, v.orderDate + FROM StoreProducts AS p, XMLTABLE('db2-fn:xmlcolumn("PURCHASEORDER_DETAILS.PORDER")/PurchaseOrder/item' + COLUMNS partid INTEGER path 'partid', + name varchar(60) path 'name', + quantity INTEGER path 'quantity', + orderdate varchar(50) path 'xs:string(../@OrderDate)') AS v + WHERE p.id = v.partid; + +-- Employee select from the view 'PurchaseOrderView' created to check +-- for the total sales of the product 'Snow Shovel, Deluxe 26 inch' +-- for last 10 days, as this product is in great demand. + +SELECT ID,NAME,sum(QUANTITY) as Quantity_Sold,QUANTITYAVAIL + FROM PurchaseOrderView + WHERE name = 'Snow Shovel, Super Deluxe 26 inch' AND + orderDate BETWEEN '2007-06-20' AND '2007-06-30' +GROUP BY id,name,QUANTITYAVAIL; + +-- Employee decides to replenish the stock for the product 'Snow Shovel, Deluxe 26 inch' +-- and places a order for 25 'Snow Shovel, Deluxe 26 inch' to the supplier of store +-- as the amount of Snow Shovels sold for last 10 days is more than the stock present +-- in the store. + +SELECT * FROM StoreSuppliers + WHERE pid = (SELECT DISTINCT id FROM PurchaseOrderView + WHERE name = 'Snow Shovel, Super Deluxe 26 inch'); + +UPDATE StoreProducts SET quantity = quantity + 30 + WHERE name = 'Snow Shovel, Super Deluxe 26 inch'; + +-- /***************************************************************************/ +-- /* Cleanup Section */ +-- /***************************************************************************/ +-- Drop Indexes +DROP INDEX pIndex; +DROP INDEX DateIndex; +DROP INDEX NameIndex; + +-- Drop tables +DROP TABLE purchaseOrder2003; +DROP TABLE purchaseOrder_Details; +DROP TABLE StoreProducts; +DROP TABLE StoreSuppliers; + +-- Drop view +DROP VIEW PurchaseOrderView; + +-- Drop tablespaces +DROP TABLESPACE Rcommon_Tbspace; +DROP TABLESPACE Rcommon_Ltbspace; +DROP TABLESPACE RTbspace1; +DROP TABLESPACE RTbspace2; +DROP TABLESPACE RTbspace3; +DROP TABLESPACE RTbspace4; +DROP TABLESPACE RLtbspace1; +DROP TABLESPACE RLtbspace2; +DROP TABLESPACE RLtbspace3; +DROP TABLESPACE RLtbspace4; +DROP TABLESPACE Ind_Tbspace1; +DROP TABLESPACE Ind_Tbspace2; +DROP TABLESPACE Ind_Tbspace3; +DROP TABLESPACE Ind_Tbspace4; +DROP TABLESPACE RInd_Tbspace; +DROP TABLESPACE RGlobal_IndTbspace; +DROP BUFFERPOOL Rcommon_Buffer; + +-- Reset schema +SET SCHEMA = USER; +-- Close connection to the sample database +CONNECT RESET; + diff --git a/xml/clp/xsupdate.db2 b/xml/clp/xsupdate.db2 new file mode 100644 index 0000000..6bc7956 --- /dev/null +++ b/xml/clp/xsupdate.db2 @@ -0,0 +1,189 @@ +--/************************************************************************* +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************* +-- +-- SAMPLE FILE NAME: xsupdate.db2 +-- +-- PURPOSE: To demonstrate how to update an existing XML schema with +-- a new schema that is compatible with the original schema +-- +-- USAGE SCENARIO: A store manager maintains product details in an XML +-- document that conforms to an XML schema. The product +-- details are: Name, SKU and Price. The store manager +-- wants to add a product description for each of the +-- products, along with the existing product details. +-- +-- PREREQUISITE: The original schema and the new schema should be +-- present in the same directory as the sample. +-- Copy prod.xsd, newprod.xsd from directory +-- /xml/data to the working directory. +-- +-- EXECUTION: db2 -tvf xsupdate.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Updated schema and successful insertion of XML documents +-- with the new product descriptions. +-- +-- OUTPUT FILE: xsupdate.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- REGISTER XMLSCHEMA +-- COMPLETE XMLSCHEMA +-- INSERT +-- CREATE +-- DROP +-- +-- SQL PROCEDURES USED: +-- XSR_UPDATE +-- +-- SQL/XML FUNCTIONS USED: +-- XMLVALIDATE +-- XMLPARSE +-- +-- ************************************************************************* +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- ************************************************************************* +-- +-- SAMPLE DESCRIPTION +-- +-- ************************************************************************* +-- 1. Register the original schema with product details:Name, SKU and Price. +-- 2. Register the new schema containing the product description element +-- along with the existing product details. +-- 3. Call the XSR_UPDATE stored procedure to update the original schema. +-- 4. Insert an XML document containing the product description elements. +-- *************************************************************************/ + +-- /************************************************************************* +-- SETUP +-- **************************************************************************/ + +-- connect to the database +CONNECT TO sample; + +-- create a relational schema +CREATE SCHEMA store; + +-- /************************************************************************* +-- 1. Register the original schema with product details: Name, SKU and Price. +-- *************************************************************************/ + +-- register the original XML schema from prod.xsd +REGISTER XMLSCHEMA http://product FROM prod.xsd AS store.prod; +COMPLETE XMLSCHEMA store.prod; + +-- table for storing products in XML document +-- created with check constraint so that the XML data is validated +-- against the STORE.PROD schema +CREATE TABLE store.products(id INT GENERATED ALWAYS AS IDENTITY,plist XML CONSTRAINT ck + CHECK(plist IS VALIDATED ACCORDING TO XMLSCHEMA ID store.prod)); + +-- insert product details into table validating according to the schema store.prod +INSERT INTO store.products(plist) VALUES(XMLVALIDATE( XMLPARSE( + DOCUMENT ' + + Ice Scraper, Windshield 4 inch + stores + 999 + + + Ice Scraper, Windshield 8 inch + stores + 1999 + + + Ice Scraper, Windshield 5 inch + stores + 1299 + + ') + ACCORDING TO XMLSCHEMA ID store.prod)); + +-- check the inserted data +SELECT * FROM store.products; + +-- /************************************************************************** +-- 2. Register the new schema containing the product description element +-- along with the existing product details. +-- **************************************************************************/ + +-- register the new schema with the product description element +REGISTER XMLSCHEMA http://newproduct FROM newprod.xsd AS store.newprod; +COMPLETE XMLSCHEMA store.newprod; + +-- /************************************************************************* +-- 3. Call the XSR_UPDATE stored procedure to update the original schema. +-- **************************************************************************/ + +-- update the original schema to reflect the changes in the new schema. +-- this stored procedure will update the original schema with the new schema +-- if the new schema is compatible with the original one. +-- the last parameter is set to a non zero value to drop the schema used to +-- update the original schema, if it is set to zero then the new schema will +-- continue to reside in XSR. +CALL SYSPROC.XSR_UPDATE('STORE','PROD','STORE','NEWPROD', 1); + +-- /************************************************************************* +-- 4. Insert an XML document containing the product description elements. +-- **************************************************************************/ + +-- insert the product details along with their descriptions into the table, +-- validating against the updated schema STORE.PROD +INSERT INTO store.products(plist) VALUES(XMLVALIDATE( XMLPARSE( + DOCUMENT ' + + Ice Scraper, Windshield 4 inch + stores + 999 + A new prod + + + Ice Scraper, Windshield 8 inch + stores + 1999 + A new prod + + + Ice Scraper, Windshield 5 inch + stores + 1299 + + ') + ACCORDING TO XMLSCHEMA ID store.prod)); + +-- check the inserted data +SELECT * FROM store.products ORDER BY id; + +-- /************************************************************************* +-- CLEANUP +-- *************************************************************************/ + +-- delete the objects created +DROP XSROBJECT store.prod; +DROP TABLE store.products; +DROP SCHEMA store RESTRICT; + +CONNECT RESET; diff --git a/xml/customer.xsd b/xml/customer.xsd new file mode 100644 index 0000000..f04807f --- /dev/null +++ b/xml/customer.xsd @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/data/bookdetail.xml b/xml/data/bookdetail.xml new file mode 100644 index 0000000..c8cfcf1 --- /dev/null +++ b/xml/data/bookdetail.xml @@ -0,0 +1,36 @@ + + + 22 + + + XML is fun to learn... + We have touched on a great number of ...... + + + XML can be used with... + We've shown the basic syntax that is required for all XML ...... + + + XML Schema Usage... + We have seen how schemas can be ...... + + + The term Document object model... + DOM provides a natural, object-oriented ...... + + + Schema based programming is used... + So with Schema based programming we can...... + + + The design of the XML for our applications will affect ... + XML documents that will be used... ... + + + XML Data Binding is the process of ... + So with Data Binding feature we can ...... + + + List of books... + + diff --git a/xml/data/bookdetail.xsd b/xml/data/bookdetail.xsd new file mode 100644 index 0000000..569bc28 --- /dev/null +++ b/xml/data/bookdetail.xsd @@ -0,0 +1,88 @@ + + + + + xdb + + admin + BOOK_AUTHOR + bookAuthorRowSet + + + + + + + + + + + bookAuthorRowSet + BOOK_CONTENTS + BOOK_AVAIL + + + + + + + + + + + + + + + + + + bookAuthorRowSet + ISBN + + + BOOK_AVAIL + ISBN + + + + + + + + + BOOK_AVAIL + BOOK_TITLE + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/data/bookdetails.xml b/xml/data/bookdetails.xml new file mode 100644 index 0000000..20315bc --- /dev/null +++ b/xml/data/bookdetails.xml @@ -0,0 +1,30 @@ + + + Padma Kota + 532 + 956 + + + XML is fun to learn... + We have touched on a great number of ...... + + + XML can be used with... + We've shown the basic syntax that is required for all XML ...... + + + The term Document object model... + DOM provides a natural, object-oriented ...... + + + The design of the XML for our applications will affect ... + XML documents that will be used... ... + + + XML Data Binding is the process of ... + So with Data Binding feature we can ...... + + + List of books... + + diff --git a/xml/data/bookdetails.xsd b/xml/data/bookdetails.xsd new file mode 100644 index 0000000..166740f --- /dev/null +++ b/xml/data/bookdetails.xsd @@ -0,0 +1,115 @@ + + + + + xdb + + admin + BOOK_AUTHOR + bookAuthorRowSet + + + + + + + + + + + bookAuthorRowSet + BOOK_CONTENTS + BOOKS_AVAIL + + + + + + + + + + + + + BOOKS_AVAIL + AUTHNAME + + + + + + + + + BOOKS_AVAIL + AUTHID + + + + + + + + + + + + + + bookAuthorRowSet + ISBN + + + BOOKS_AVAIL + ISBN + + + + + + + + + BOOKS_AVAIL + BOOK_TITLE + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/data/booksreturned.del b/xml/data/booksreturned.del new file mode 100644 index 0000000..b1274a6 --- /dev/null +++ b/xml/data/booksreturned.del @@ -0,0 +1,3 @@ +1000,"" +1001,"" +1002,"" \ No newline at end of file diff --git a/xml/data/booksreturned.xsd b/xml/data/booksreturned.xsd new file mode 100644 index 0000000..7a96710 --- /dev/null +++ b/xml/data/booksreturned.xsd @@ -0,0 +1,42 @@ + + + + + xdb + + xdb + BOOKS_AVAIL + bookAvailRowSet + + + + + + + + + + + + + + + + + + + bookAvailRowSet + BOOK_TITLE + + + + + + + + + + + + + diff --git a/xml/data/booksreturned1.xml b/xml/data/booksreturned1.xml new file mode 100644 index 0000000..37075bc --- /dev/null +++ b/xml/data/booksreturned1.xml @@ -0,0 +1,16 @@ + + + My First XML Book + Padma Kota + 532 + 956 + 50 + + + DB2 Architecture + Carl + 234 + 1090 + 15 + + diff --git a/xml/data/booksreturned2.xml b/xml/data/booksreturned2.xml new file mode 100644 index 0000000..3cf7574 --- /dev/null +++ b/xml/data/booksreturned2.xml @@ -0,0 +1,17 @@ + + + Explore XML + Carl + 234 + 900 + 17 + + + Learn DB2 + Peter + 78 + 800 + 29 + + + diff --git a/xml/data/booksreturned3.xml b/xml/data/booksreturned3.xml new file mode 100644 index 0000000..143cd25 --- /dev/null +++ b/xml/data/booksreturned3.xml @@ -0,0 +1,17 @@ + + + XML Decomposition + Carl + 234 + 900 + 15 + + + Learn DB2 Architecture + Prashanth + 2 + 180 + 5 + + + diff --git a/xml/data/boots.xsd b/xml/data/boots.xsd new file mode 100644 index 0000000..4bea2a9 --- /dev/null +++ b/xml/data/boots.xsd @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/data/cleanupfordecomposition.db2 b/xml/data/cleanupfordecomposition.db2 new file mode 100644 index 0000000..4c2d072 --- /dev/null +++ b/xml/data/cleanupfordecomposition.db2 @@ -0,0 +1,56 @@ +--/************************************************************************* +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************* +-- +-- FILE NAME: cleanupfordecomposition.db2 +-- +-- PURPOSE: This is the clean up script for the sample xmldecompostion.db2, +-- xmldecomposition.sqc, xmldecomposition.java. +-- The tables are dropped that were created by the setup script. +-- +-- SQL STATEMENTS USED: +-- DROP +-- +-- ************************************************************************* +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- *************************************************************************/ + +CONNECT TO sample; + +-- drop the schemas and tables created +DROP XSROBJECT XDB.BOOKDETAILS; +DROP XSROBJECT XDB.BOOKSRETURNED; +DROP TABLE XDB.BOOK_CONTENTS; +DROP TABLE ADMIN.BOOK_AUTHOR; +DROP TABLE XDB.BOOKS_AVAIL; +DROP TABLE XDB.BOOK_AVAIL; +DROP TABLE XDB.BOOKS_RETURNED; +DROP TABLE XDB.BOOKS_RECEIVED; +DROP TABLE XDB.BOOKS_RECEIVED_BLOB; + +-- RESET CONNECTION +CONNECT RESET; diff --git a/xml/data/cleanupscript.db2 b/xml/data/cleanupscript.db2 new file mode 100644 index 0000000..b3fc14a --- /dev/null +++ b/xml/data/cleanupscript.db2 @@ -0,0 +1,47 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: cleanupscript.db2 +-- +-- SAMPLE: Clean up script for the sample reltoxmltype. +-- +-- SQL STATEMENTS USED: +-- DROP +-- +-- OUTPUT FILE: cleaupscript.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- +CONNECT TO SAMPLE; +DROP TABLE Products_Relational; +DROP TABLE CustomerInfo_Relational; +DROP TABLE PurchaseOrder_Relational; +DROP TABLE LineItem_Relational; +DROP TABLE CustomerInfo_New; +DROP TABLE PurchaseOrder_new; +CONNECT RESET; diff --git a/xml/data/cust1021.xml b/xml/data/cust1021.xml new file mode 100644 index 0000000..d4d2bea --- /dev/null +++ b/xml/data/cust1021.xml @@ -0,0 +1 @@ +chandra shekhar
khandala
diff --git a/xml/data/cust1022.xml b/xml/data/cust1022.xml new file mode 100644 index 0000000..bd6e24b --- /dev/null +++ b/xml/data/cust1022.xml @@ -0,0 +1 @@ +sanjay
bangalore
diff --git a/xml/data/cust1023.xml b/xml/data/cust1023.xml new file mode 100644 index 0000000..f840dbc --- /dev/null +++ b/xml/data/cust1023.xml @@ -0,0 +1 @@ +anitha
N.R.Colony
diff --git a/xml/data/customer.xsd b/xml/data/customer.xsd new file mode 100644 index 0000000..b123136 --- /dev/null +++ b/xml/data/customer.xsd @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/xml/data/header.xsd b/xml/data/header.xsd new file mode 100644 index 0000000..3580f45 --- /dev/null +++ b/xml/data/header.xsd @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/xml/data/loaddata1.del b/xml/data/loaddata1.del new file mode 100644 index 0000000..1cc80ec --- /dev/null +++ b/xml/data/loaddata1.del @@ -0,0 +1,4 @@ +1, "" +2, "" +3, "" +4, "" diff --git a/xml/data/loaddata2.del b/xml/data/loaddata2.del new file mode 100644 index 0000000..7743e50 --- /dev/null +++ b/xml/data/loaddata2.del @@ -0,0 +1,6 @@ +1, "" +2, "" +3, "" +4, "" +5, "" +6, "" diff --git a/xml/data/loadfile1.xml b/xml/data/loadfile1.xml new file mode 100644 index 0000000..3d04962 --- /dev/null +++ b/xml/data/loadfile1.xml @@ -0,0 +1 @@ +100-100-01Snow Shovel, Basic 22 inch39.99100-103-01Snow Shovel, Super Deluxe 26 inch549.99 diff --git a/xml/data/loadfile2.xml b/xml/data/loadfile2.xml new file mode 100644 index 0000000..6c0bc71 --- /dev/null +++ b/xml/data/loadfile2.xml @@ -0,0 +1 @@ + 100-101-01 Snow Shovel, Deluxe 24 inch 1 19.99 100-103-01 Snow Shovel, Super Deluxe 26 inch 2 49.99 100-201-01 Ice Scraper, Windshield 4 inch 1 3.99 diff --git a/xml/data/musicplayer.xsd b/xml/data/musicplayer.xsd new file mode 100644 index 0000000..3574ca4 --- /dev/null +++ b/xml/data/musicplayer.xsd @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/data/newprod.xsd b/xml/data/newprod.xsd new file mode 100644 index 0000000..3f713c5 --- /dev/null +++ b/xml/data/newprod.xsd @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/data/order.xml b/xml/data/order.xml new file mode 100644 index 0000000..b593d04 --- /dev/null +++ b/xml/data/order.xml @@ -0,0 +1,27 @@ + + +
+ 1 + 2004-01-29 + purchase order + 20 + shipped +
+ + + + Widget C + 1 + 30 + no comment + + 1 + + + + Manoj K Sardana +
ring road, bangalore
+ 918051055109 + msardana@in.ibm.com +
+
diff --git a/xml/data/order.xsd b/xml/data/order.xsd new file mode 100644 index 0000000..9e01889 --- /dev/null +++ b/xml/data/order.xsd @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/data/prod.xsd b/xml/data/prod.xsd new file mode 100644 index 0000000..11e3902 --- /dev/null +++ b/xml/data/prod.xsd @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/data/product.xsd b/xml/data/product.xsd new file mode 100644 index 0000000..e6222a4 --- /dev/null +++ b/xml/data/product.xsd @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/xml/data/purchaseorder.xml b/xml/data/purchaseorder.xml new file mode 100644 index 0000000..e843408 --- /dev/null +++ b/xml/data/purchaseorder.xml @@ -0,0 +1,43 @@ + + + Manoj K Sardana +
+ Ring Road + Bangalore + Karnataka + 560071 +
+ 9880471176 + + + + 100-103-01 + Snow Shovel, Super Deluxe 26" + 1 + 49.99 + + + +
+ + Balunaini Prasad +
+ Ring Road + Bangalore + Karnataka + 560071 +
+ 9886362610 + + + + 100-201-01 + Ice Scraper, Windshield 4" Wide + 1 + 3.99 + + + +
+ +
diff --git a/xml/data/recemp.xml b/xml/data/recemp.xml new file mode 100644 index 0000000..a3c5af0 --- /dev/null +++ b/xml/data/recemp.xml @@ -0,0 +1,27 @@ + + 639963 + E32 + + 639964 + E32 + + + 111111 + E34 + + + 222222 + E23 + + 565656 + E23 + + 399663 + E23 + + 439964 + E23 + + + + diff --git a/xml/data/recemp.xsd b/xml/data/recemp.xsd new file mode 100644 index 0000000..318c040 --- /dev/null +++ b/xml/data/recemp.xsd @@ -0,0 +1,26 @@ + + + + + + xdb + + + + + + + + + + + + + + + + diff --git a/xml/data/setupfordecomposition.db2 b/xml/data/setupfordecomposition.db2 new file mode 100644 index 0000000..a59a3ac --- /dev/null +++ b/xml/data/setupfordecomposition.db2 @@ -0,0 +1,149 @@ +--/************************************************************************* +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************* +-- +-- FILE NAME: setupfordecomposition.db2 +-- +-- PURPOSE: This is the set up script for the sample xmldecompostion.db2, +-- xmldecomposition.sqc, xmldecomposition.java. +-- The tables are created that are needed for the decomposition +-- of the XML document bookdetail.xml. +-- +-- SQL STATEMENTS USED: +-- CREATE +-- +-- ************************************************************************* +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- ************************************************************************* + +--CONNET TO DATABASE +CONNECT TO sample; + +CREATE TABLE admin.book_author ( + authid INTEGER NOT NULL , + authname VARCHAR(50), + isbn VARCHAR(13) NOT NULL, + book_title VARCHAR(50), + PRIMARY KEY (isbn)); + +CREATE TABLE xdb.book_contents ( + isbn VARCHAR(13) REFERENCES admin.book_author(isbn), + chptnum INTEGER, + chpttitle VARCHAR(50), + chptcontent VARCHAR(1000)); + + +CREATE TABLE xdb.books_avail ( + isbn VARCHAR(13) REFERENCES admin.book_author(isbn), + book_title VARCHAR(50), + authname VARCHAR(50), + authid INTEGER, + price DECFLOAT, + no_of_copies INTEGER DEFAULT 0); + +CREATE TABLE xdb.book_avail ( + isbn VARCHAR(13) REFERENCES admin.book_author(isbn), + book_title VARCHAR(50), + authname VARCHAR(50), + authid INTEGER, + price DECFLOAT, + no_of_copies INTEGER DEFAULT 0); + + +-- table to store the information about books returned by customers +CREATE TABLE xdb.books_returned (customerID VARCHAR(10), booksreturned XML); + +-- CREATE books_recevied to store book details of books received from different suppliers +CREATE TABLE xdb.books_received_BLOB( supplierID VARCHAR(15), booksinfo BLOB(10K)); + + +CREATE TABLE xdb.books_received( supplierID VARCHAR(15), booksinfo XML); + + +-- Insert data into the required tables +INSERT INTO admin.book_author VALUES(234,'Carl','111111-20','DB2 Architecture'); +INSERT INTO admin.book_author VALUES(234,'Carl','111112-12','Explore XML'); +INSERT INTO admin.book_author VALUES(78,'Peter','111112-29','Learn DB2'); +INSERT INTO admin.book_author VALUES(234,'Carl','111112-34','XML Decomposition'); +INSERT INTO admin.book_author VALUES(2,'Prashanth','1-11-111112-2','Learn DB2 Architecture '); +INSERT INTO admin.book_author VALUES(32,'Kevin','111111-100','DB2 DBA'); +INSERT INTO admin.book_author VALUES(234,'Carl','211111-20','DB2 fundamentals'); +INSERT INTO admin.book_author VALUES(234,'Carl','111111-12','XML and DB2 fundamentals'); +INSERT INTO admin.book_author VALUES(32,'Kevin','111112-120','DB2 DBA2'); + +-- import the XML data to books_returned table +IMPORT FROM booksreturned.del OF DEL + INSERT INTO xdb.books_returned; + + +-- INSERT books information into books_received table +INSERT INTO xdb.books_received_BLOB VALUES ('1011', CAST(' + + + DB2 fundamentals + Carl + 234 + 80 + 10 + + + DB2 DBA + Kevin + 32 + 180 + 20 + + ' AS BLOB)); + +-- INSERT books information into books_received table +INSERT INTO xdb.books_received_BLOB VALUES ('1012', CAST(' + + + XML and DB2 fundamentals + Carl + 234 + 802 + 12 + + + DB2 DBA2 + Kevin + 32 + 182 + 22 + + ' AS BLOB)); + +-- insert the data from xdb.books_received_BLOB table +INSERT INTO xdb.books_received(SELECT supplierID, booksinfo FROM xdb.books_received_BLOB); + + +-- COMMIT +COMMIT; + +-- RESET CONNECTION +CONNECT RESET; diff --git a/xml/data/setupscript.db2 b/xml/data/setupscript.db2 new file mode 100644 index 0000000..5a6a807 --- /dev/null +++ b/xml/data/setupscript.db2 @@ -0,0 +1,120 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: setupscript.db2 +-- +-- SAMPLE: This file serves as the setupscript for the sample +-- reltoxmltype.clp, .java and .sqc. +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT +-- +-- OUTPUT FILE: setupscript.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + + +CONNECT TO SAMPLE; + +CREATE TABLE Products_Relational + ( + ProdID varchar(20) not null primary key, + Price decimal(10,2), + Description varchar (50), + Info varchar( 2000 ) + ); + +CREATE TABLE CustomerInfo_Relational + ( + CustID integer not null primary key, + Name varchar(28), + Street varchar(28), + City varchar(28), + Province varchar(28), + PostalCode varchar(7) + ); +CREATE TABLE PurchaseOrder_Relational + ( + PoNum integer not null primary key, + OrderDate date, + CustID integer, + Status varchar(20), + Comment varchar(1024), + FOREIGN KEY (CustID) references CustomerInfo_Relational + ); + +CREATE TABLE LineItem_Relational + ( + PoNum integer, + ProdID varchar(20), + Quantity integer, + FOREIGN KEY (PoNum) references PurchaseOrder_Relational, + FOREIGN KEY (ProdID) references Products_Relational + ); + +-- Create table CustomerInfo and PurchaseOrder. +CREATE TABLE CustomerInfo_New + ( + CustID integer not null primary key, + Address XML + ); + +CREATE TABLE PurchaseOrder_new + ( + PoNum integer not null primary key, + OrderDate date, + CustID integer, + Status varchar(20), + Price decimal(10,2), + LineItems XML, + Comment varchar(1024), + FOREIGN KEY (CustID) references CustomerInfo_new + ); + +INSERT INTO products_relational values + ('A-101', 20.80, 'Steel Spoon', 'Dozen spoons with length as 12 cm and weight as 75 gm and steel color'), + ('A-102', 4.56, 'Plastic Spoon', 'Dozen spoons with length as 8.5 cm and weight as 15 gm and white color'), + ('B-101', 30.23, 'Steel glass', '6 in numer and capacity of 300ml'); + +INSERT INTO CustomerInfo_Relational values + ( 10082, 'Mark', 'Leslie', 'Toronto', 'Ontario', '3422212'), + ( 10342, 'Gupta', 'Domlur', 'Bangalore', 'Karnataka', '569923'), + ( 12033, 'Shaun', 'Markham', 'Toronto', 'Ontario', '2332333'); + +INSERT INTO PurchaseOrder_Relational values + ( 8647, '2005-12-11', 10082, 'Delivered', 'Payment Received'), + ( 1233, '2005-11-17', 10342, 'Payment Pending', 'To be sent once Payment is received'); + +INSERT INTO LineItem_Relational values + ( 8647, 'A-101', 12), + ( 1233, 'B-101', 06); + + +CONNECT RESET; diff --git a/xml/data/xmldata.del b/xml/data/xmldata.del new file mode 100644 index 0000000..0c2cbf9 --- /dev/null +++ b/xml/data/xmldata.del @@ -0,0 +1,4 @@ +1001,"" +1002,"" +1003,"" +1004,"" diff --git a/xml/data/xmlfiles.001.xml b/xml/data/xmlfiles.001.xml new file mode 100644 index 0000000..d3b8266 --- /dev/null +++ b/xml/data/xmlfiles.001.xml @@ -0,0 +1 @@ +Kathy Smith25 EastCreekTorontoOntarioM8X-3T6416-555-1358 diff --git a/xml/history.xsd b/xml/history.xsd new file mode 100644 index 0000000..c618e9c --- /dev/null +++ b/xml/history.xsd @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/xml/java/jdbc/README b/xml/java/jdbc/README new file mode 100644 index 0000000..5ae8e9a --- /dev/null +++ b/xml/java/jdbc/README @@ -0,0 +1,408 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for Java XML Samples +* +* For windows, the \sqllib\samples\xml\java\jdbc directory and +* for unix, /sqllib/samples/xml/java/jdbc directory contain this +* README file where is the location of DB2 9.7 on your hard +* drive. The default location for is C:\Program Files\IBM for +* windows and $HOME for unix based platform. +* +* This README describes how to build and run jdbc sample code for DB2 9.7. +* The DB2 9.7 jdbc sample are located in the +* \sqllib\samples\xml\java\jdbc directory for windows platform +* and /sqllib/samples/java/xml/java/jdbc for unix based +* platforms. +* +* Copy the files from this directory to your working directory prior to +* building the sample programs. The sample programs directory is +* typically read-only on most platforms and some samples produce output +* files that require write permissions on the directory. +* +* WARNINGS: +* 1. Some of these samples may change your database or database +* manager configuration. Execute the samples against a test database +* only, such as the DB2 SAMPLE database. +* +******************************************************************************* +* +* Prepare your DB2 sample development environment +* +* 1) Copy the files in \sqllib\samples\xml\java\jdbc\* (for +* windows platform) or /sqllib/samples/xml/java/jdbc/* +* (for UNIX based platform) to your working directory and ensure that +* directory has write permission. +* +* 2) Modify the CLASSPATH. +* For Windows include +* \sqllib\java\db2java.zip, +* \sqllib\java\db2jcc.jar, +* \sqllib\java\db2jcc_license_cu.jar, +* \sqllib\java\jdk\lib, +* \sqllib\lib, \sqllib\function +* +* For UNIX based platform include +* /sqllib/java/db2java.zip, +* /sqllib/java/db2jcc.jar, +* /sqllib/java/db2jcc_license_cu.jar, +* /sqllib/java/jdk/lib, +* /sqllib/lib,/sqllib/function, +* +* Modify the PATH. +* For Windows include +* \sqllib\java\\bin +* \sqllib\lib +* where is the name of the java directory. +* +* For UNIX include +* /sqllib/java//bin +* /sqllib/lib +* where is the name of the java directory. +* +* Please make sure that JDK_PATH( db2 +* database manager configuration parameter) is +* pointing to the \sqllib\java\ for windows +* and /sqllib/java/ for unix platform. +* +* To see the dbm cfg parameter value, run the following from db2 +* command window (open the db2 command window from +* Start -> Run -> db2cmd for windows platform) and look for the value +* of JDK_PATH +* +* db2 "get dbm cfg" +* +* 3) Start the Database Manager with the following command: +* db2start +* +* 4) Create the sample database with the following command: +* db2sampl -xml +* +* 5) Connect to the database with the following command: +* db2 "connect to sample" +* +* 6) To build Stored Procedures and User Defined Functions, ensure +* that you have write permission on the +* \sqllib\function directory for windows platform. +* +* 7) cd to the directory containing the files copied in step 1. +* +* +******************************************************************************* +* +* Building DB2 Samples +* +* There are two ways to build DB2 samples: using a nmake utility for windows +* (make utility for unix based platform) or using the java compiler which +* comes along with the DB2 installation +* +* o To build samples using the nmake utility for windows see +* 'BUILDING SAMPLES USING nmake UTILITY on WINDOWS'. +* o To build samples using the make utility for unix see +* 'BUILDING SAMPLES USING make UTILITY on UNIX'. +* o To build samples using the java compiler or when you do not +* have a compatible nmake utility see 'BUILDING +* SAMPLES USING JAVA COMPILER'. +* +* NOTE: +* +* 1. Some of the samples might need one or more data files at runtime. +* some of the samples may also need setup script to be run before +* running the sample.See the specific sample descriptions in +* "File Descriptions" section for more details. +* +* +* 2. There are utility files available in this directory that are used +* by these samples for error checking. Please make sure that these +* files are present in you working directory. The information +* about these files can be found in "File Descriptions" section of +* this README. +* +* 3. Refer to the "File Descriptions" section in this README for +* information on specific samples and any special considerations +* relevant for each. The HEADER sections of these samples also +* provide further details on each sample. +* +* +* *** BUILDING SAMPLES USING nmake UTILITY on WINDOWS *** +* +* If you have a compatible nmake utility on your system, you +* can use the makefile provided. Such a nmake utility may be +* provided by another language compiler.Modify the PATH +* variable to include the directory containing the nmake +* utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'nmake' command in your working +* directory: +* +* nmake - Builds the program designated by . +* +* nmake all - Builds all supplied sample programs +* +* nmake srv - Builds sample that can only be run on the +* server, (stored procedure) +* +* nmake all_client - Builds all client samples (all programs in the +* 'call_rtn' and 'client_run' categories). +* +* nmake call_rtn - Builds client programs that call stored +* procedure +* +* nmake client_run - Builds all programs that run completely on the +* client (not ones that call stored procedure) +* +* nmake clean - Erases all intermediate files produced in the +* build process. +* +* nmake cleanall - Erases all files produced in the build process +* (all files except the original source files). +* +******************************************************************************* +* +* *** BUILDING SAMPLES USING make UTILITY on UNIX *** +* +* If you have a compatible make utility on your system, you +* can use the makefile provided. Modify the PATH +* variable to include the directory containing the make +* utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'make' command in your working +* directory: +* +* make - Builds the program designated by . +* +* make all - Builds all supplied sample programs +* +* make srv - Builds sample that can only be run on the server +* (stored procedure) +* +* make all_client - Builds all client samples (all programs in the +* 'call_rtn' and 'client_run' categories). +* +* make call_rtn - Builds client programs that call stored procedure +* +* make client_run - Builds all programs that run completely on the +* client (not ones that call stored procedure) +* +* make clean - Erases all intermediate files produced in the +* build process. +* +* make cleanall - Erases all files produced in the build process +* (all files except the original source files). +* +******************************************************************************* +* +* *** BUILDING SAMPLES USING JAVA COMPILER *** +* +* If you do not have a compatible make utility you can use +* the javac bytecode compiler to build JDBC programs +* +* +* These samples used classes in Util.java. Compile the Util.java program +* using the following command. +* +* javac Util.java +* +* To build a individual JDBC sample, use the following command +* +* javac .java +* +* To run the sample, use the following command +* +* java +* +******************************************************************************* +* +* Common file Descriptions +* +* The following are the common files for JDBC samples. For more +* information on these files, refer to the program source files. +* +******************************************************************************* +* +* Common files +* +* README - This file. +* makefile - makefile for all files +* Util.java - utilities used by most programs +* +******************************************************************************* +* +* JDBC Sample Descriptions +* +* The following are the JDBC sample files included with DB2. For more +* information on the sample programs, refer to the program source files. +* +******************************************************************************* +* +* Sample Files +* +* XmlSchema.java - How to register an XML schema to a database. +* How to use this registered schema to validate an XML +* value before inserting into a table. +* PREREQUISITE: copy product.xsd, order.xsd, +* customer.xsd, header.xsd Schema files, order.xml XML +* document from xml/data directory to working +* directory. +* +* XmlToTable.java - How to insert the data from XML document to a +* relational table using XML Constructor function and +* SQL/XML functions. +* PREREQUISITE: copy purchaseorder.xml XML document +* from xml/data directory to the working directory. +* +* XmlDecomposition.java - How to decompose data stored in a XML file and +* insert those into relational tables with constraints. +* PREREQUISITE:run the script setupfordecomposition.db2 +* before running the sample. Run the script +* cleanupfordecomposition.db2 after running the sample +* to cleanup the object created for the samples. These +* scripts can be found in xml/data directory. This +* sample require bookdetails.xsd, booksreturned.xsd, bookdetails.xml, +* booksreturned.del, booksreturned1.xml, booksreturned2.xml, +* booksreturned3.xml files at run time. Copy these files to your +* working directory before running the sample. These files can +* be found in xml/data directory. +* +* RecXmlDecomp.java - How to register a recursive XML schema to the XSR and +* enable the same for decomposition. +* PREREQUISITE: The instance document and the annotated +* schema should exist in the same directory as the sample. +* Copy recemp.xml, recemp.xsd from directory +* /sqllib/samples/xml/data in UNIX and +* \sqllib\samples\xml\data in Windows to the +* working directory. +* +* RelToXmlDoc.java - How to create XML object from data stored in +* relational tables using various SQL/XML Constructor +* functions. The XML object is created using stored +* procedure. +* PREREQUISITE: This sample uses a stored procedure. +* Stored procedure should be registered before running +* the sample. Follow the step given in the header of +* the sample for more details. Run the cleanup.db2 +* and setupscript.db2 scripts before running this +* simple.Run the cleanupscript.db2 script to cleanup +* the database objects after running the sample. +* These scripts can be found in xml/data directory. +* +* reltoxmlproc.db2 - Stored procedure used by the RelToXmlDoc.java sample. +* +* RelToXmlType.java - How to create XML object from data stored in +* relational tables using various SQL/XML Constructor +* functions. +* PREREQUISITE: Run the script setupscript.db2 before +* running this simple. Run the cleanupscript.db2 script +* to cleanup the database objects after running the +* sample. These scripts can be found in xml/data +* directory. +* +* XmlRead.java - How to read XML data stored in tables. +* +* XmlInsert.java - How to insert XML data into tables having an XML +* column. +* PREREQUISITE: copy the files expPrg1.xml and +* expPrg.xml to working directory before running the +* sample. These files can be found in xml/data +* directory. +* +* XmlUpDel.java - How to update and delete XML documents in tables. +* PREREQUISITE: copy the files expPrg1.xml and +* expPrg.xml to working directory before running the +* sample. These files can be found in xml/data +* directory. +* +* XmlRunstats.java - How to perform runstats on a table with XML type +* columns. +* +* XmlIndex.java - How to create an index on a table with XML type +* columns and how to query using XQUERY on the +* index created. +* +* XmlConst.java - How to put constraints on an XML column. +* NOTE : This sample demonstrate the how to enforce the +* constraints on an XML value. There are some statement +* in the samples which are expected to fail because of +* constraint violation so The sql error SQL803N, +* SQL20305N and SQL20306N are expected. +* +* XsUpdate.java - How to update an XML schema with a compatible schema. +* PREREQUISITE: The original schema and the new schema +* should be present in the same directory as the sample. +* Copy prod.xsd, newprod.xsd from directory +* /xml/data to the working directory. +* +* XmlCheckConstraint - How to create check constraints on XML column +* validating XML document against single schema or +* multiple schemas +* PREREQUISITE: boots.xsd and musicplayer.xsd schemas +* must be copied from /xml/data to +* current working directory where sample is being +* executed. +* XmlTrig - How to automate validation of XML documents while +* insertion/updation using XML triggers. +* PREREQUISITE: boots.xsd schema must be copied +* from /xml/data to current working +* directory where sample is being executed. +* +* XmlUdfs - How XML data type is supported in Scalar UDFs, Sourced +* UDFs and SQL bodied UDFs. +* +* XmlMdc - How to create an MDC table with XML column and how +* faster insert and faster delete options are supported +* on MDC table having XML column. +* +******************************************************************************* +* +* Stored Procedure Samples +* +* Simple_XmlProc_Client.java - Client application that calls the stored +* procedure. +* PREREQUISITE: build the server +* "Simple_XmlProc.java"and register the procedure +* using spcat_xml. +* +* Simple_XmlProc.java - Stored procedure functions built and run on the +* server. +* +* spcat_xml - shell script that first calls +* Simple_XmlProc_Drop.db2 and then calls +* Simple_XmlProc_Create.db2. This file will be +* found only for unix platforms. +* spcat_xml.bat - Batch file that first calls +* Simple_XmlProc_Drop.db2 and then calls +* Simple_XmlProc_Create.db2. This file +* will be found only for windows platforms. +* +* Simple_XmlProc_Create.db2 - CLP script to issue CREATE PROCEDURE statement. +* +* Simple_XmlProc_Drop.db2 - CLP script to drop stored procedure from the +* catalog. +* +******************************************************************************* diff --git a/xml/java/jdbc/RecXmlDecomp.java b/xml/java/jdbc/RecXmlDecomp.java new file mode 100644 index 0000000..6906cc8 --- /dev/null +++ b/xml/java/jdbc/RecXmlDecomp.java @@ -0,0 +1,275 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +// ************************************************************************** +// +// SAMPLE FILE NAME: RecXmlDecomp.java +// +// PURPOSE: How to register a recursive XML schema to the XSR and +// enable the same for decomposition. +// +// USER SCENARIO: +// The existing PurchaseOrder schema in the Sample database is +// enhanced to have new Employee tables to process the purchase orders. +// We have Recursive Schema for Employee data management, an employee +// can be a manager and himself reporting to another employee. The XML document +// contains the employee information along with department details which needs +// to be stored in relational tables for easy retrieval of data. +// +// PREREQUISITE: +// The instance document and the annotated schema should exist in the same +// directory as the sample. Copy recemp.xml, recemp.xsd from directory +// /sqllib/samples/xml/data in UNIX and +// \sqllib\samples\xml\data in Windows to the working directory. +// +// EXECUTION: i) javac RecXmlDecomp.java ( Compile the sample) +// ii) java RecXmlDecomp ( Run the sample) +// +// INPUTS: NONE +// +// OUTPUTS: Decomposition of XML document according to the annotations +// in recursive schema. +// +// OUTPUT FILE: RecXmlDecomp.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// REGISTER XMLSCHEMA +// COMPLETE XMLSCHEMA +// DECOMPOSE XML DOCUMENT +// CREATE +// SELECT +// DROP +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// Statement +// ResultSet +// +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** +// +// SAMPLE DESCRIPTION +// +// ***************************************************************************** +// 1. Register the annotated recursive XML schema. +// 2. Decompose the XML document using the registered XML schema. +// 3. Select data from the relational tables to see the decomposed data. +// ***************************************************************************** + +import java.lang.*; +import java.sql.*; +import java.io.*; +import com.ibm.db2.jcc.DB2Xml; + +class RecXmlDecomp +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS: How to register a recursive XML schema"); + System.out.println(" to the XSR and enable the same for decomposition."); + System.out.println(); + + // connect to the 'sample' database + db.connect(); + + // call the function to decompose data + RecXmlDecompose(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void RecXmlDecompose(Connection con) + { + try + { + String dbname; + String RelSchema; + String SchemaName; + String SchemaLocation; + String PrimaryDocument; + String xmlfilename; + int shred = 1; + String Status; + String Decomposition; + String Decomposition_version; + boolean xmlRegister = false; + boolean xmlAdd = false; + boolean xmlComplete = false; + boolean xmlDecomp = false; + + System.out.println( + "\n Execute Statement: \n" + + "CREATE TABLE xdb.poemployee(empid VARCHAR(20),deptid VARCHAR(20),members XML) \n"); + + Statement stmt1 = con.createStatement(); + String create = "CREATE TABLE xdb.poemployee (empid VARCHAR(20), deptid VARCHAR(20), members XML)" ; + stmt1.executeUpdate(create); + + // *************************************************************************** + // 1. Register the recursive XML schema. + // *************************************************************************** + + RelSchema = "xdb"; + SchemaName = "employee"; + SchemaLocation = "http://porder.com/employee.xsd"; + PrimaryDocument = "recemp.xsd"; + xmlfilename = "recemp.xml"; + + // Register the XML Schema to the XSR. + CallableStatement callStmt = con.prepareCall("CALL SYSPROC.XSR_REGISTER(?,?,?,?,NULL)"); + File xsdfile = new File(PrimaryDocument); + FileInputStream xsdfileis = new FileInputStream(xsdfile); + + callStmt.setString(1, RelSchema ); + callStmt.setString(2, SchemaName ); + callStmt.setString(3, SchemaLocation ); + callStmt.setBinaryStream(4, xsdfileis, (int)xsdfile.length() ); + callStmt.execute(); + xsdfileis.close(); + callStmt.close(); + System.out.println("**** CALL SYSPROC.XSR_REGISTER SUCCESSFULLY"); + + // Complete the Schema registration with Validate Option true. + callStmt = con.prepareCall("CALL SYSPROC.XSR_COMPLETE(?,?,NULL,?)"); + callStmt.setString(1, RelSchema ); + callStmt.setString(2, SchemaName ); + callStmt.setInt(3, shred ); + callStmt.execute(); + callStmt.close(); + System.out.println("**** CALL SYSPROC.XSR_COMPLETE SUCCESSFULLY"); + + // Check the status of the XSR object registered. + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT status, decomposition, decomposition_version FROM SYSIBM.SYSXSROBJECTS WHERE XSROBJECTNAME = 'EMPLOYEE'"); + + while(rs.next()) + { + Status = rs.getString(1); + Decomposition = rs.getString(2); + Decomposition_version = rs.getString(3); + + System.out.println("\nStatus : " + + Data.format(Status, 5) + "\n" + + "Decomposition : " + + Data.format(Decomposition, 5) + "\n" + + "Version : " + + Data.format(Decomposition_version, 5)); + } + rs.close(); + + // *************************************************************************** + // 2. Decompose the XML document using the registered XML schema. + // *************************************************************************** + + // Decompose the XML document by calling the SYSPROC.XDBDECOMPXML + callStmt = con.prepareCall("CALL SYSPROC.XDBDECOMPXML(?,?,?,?,?, NULL, NULL, NULL)"); + File xmlfile = new File(xmlfilename); + FileInputStream xmlfileis = new FileInputStream(xmlfile); + callStmt.setString(1, RelSchema ); + callStmt.setString(2, SchemaName ); + callStmt.setBinaryStream(3, xmlfileis, (int)xmlfile.length() ); + callStmt.setString(4, SchemaName ); + callStmt.setInt(5, shred); + callStmt.execute(); + xmlfileis.close(); + callStmt.close(); + System.out.println("**** CALL SYSPROC.XDBDECOMPXML SUCCESSFULLY"); + + // *************************************************************************** + // 3. Select data from the relational tables to see the decomposed data. + // *************************************************************************** + + // Read Data from the tables, where the data is stored after decomposition. + SelectFromTable(con); + + // Drop the XSROBJECT + String drop = "DROP XSROBJECT xdb.employee"; + stmt1.executeUpdate(drop); + + // Drop the table + drop = "DROP TABLE xdb.poemployee"; + stmt1.executeUpdate(drop); + + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } + static void SelectFromTable(Connection con) + { + try + { + + String empid = ""; + String deptid = ""; + String members = ""; + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT empid, deptid,xmlserialize( members as varchar(500)) FROM XDB.POEMPLOYEE ORDER BY empid"); + + while (rs.next()) + { + empid = rs.getString(1); + deptid = rs.getString(2); + members = rs.getString(3) ; + + System.out.println("\nEMPID : " + + Data.format(empid, 13) + "\n" + + "DEPTID : " + + Data.format(deptid, 5) + "\n" + + "MEMBERS : " + + Data.format(members, 500) ); + } + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } //Try Block + } //SelectFromTable +} //RecXmlDecomp Class + diff --git a/xml/java/jdbc/RelToXmlDoc.java b/xml/java/jdbc/RelToXmlDoc.java new file mode 100644 index 0000000..68278e9 --- /dev/null +++ b/xml/java/jdbc/RelToXmlDoc.java @@ -0,0 +1,287 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: RelToXmlDoc.java +// +// SAMPLE USER SCENARIO : Purchase order database uses relational tables to store the +// orders of different customers. This data can be returned as an XML object +// to the application. The XML object can be created using the XML constructor +// functions on the server side. +// To achieve this, the user can +// 1. Create a stored procedure to implement the logic to create the XML +// object using XML constructor functions. +// 2. Register the above stored procedure to the database. +// 3. Call the procedure whenever all the PO data is needed as XML +// instead of using complex joins. +// +// SAMPLE : This sample basically demostrates two things +// 1. Using joins on relational data +// 2. Using constructor function to get purchaseorder data as an XML object +// +// To run this sample, peform the following steps: +// 1. create and populate the SAMPLE database +// 2. create stored procedure reltoxmlproc by executing +// db2 -td@ -f reltoxmlproc.db2 +// +// SQL Statements USED: +// SELECT +// +// SQL/XML Functions Used : +// XMLELEMENT +// XMLATTRIBUTES +// XMLCONCAT +// XMLNAMESPACES +// XMLCOMMENT +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// OUTPUT FILE: RelToXmlDoc.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class RelToXmlDoc +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CONVERT DATA RELATIONAL TABLES\n" + + "INTO A XML DOCUMENT USING THE XML CONSTRUCTOR FUNCTIONS"); + + // connect to the 'sample' database + db.connect(); + + // select the purchaseorder data using joins + execQuery(db.con); + + // function to call the stored procedure which will + // select purchaseorder data using XMLconstructors + callRelToXmlProc(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void execQuery(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " Statement\n" + + "TO EXECUTE THE QUERY WITH XML CONSTRUCTORS."); + + Statement stmt = con.createStatement(); + + // execute the query + System.out.println(); + System.out.println( + " Execute Statement:\n" + + "SELECT po.CustID, po.PoNum, po.OrderDate, po.Status,\n" + + " count(l.ProdID) as Items, sum(p.Price) as total,\n" + + " po.Comment, c.Name, c.Street, c.City, c.Province, c.PostalCode\n" + + " FROM PurchaseOrder_relational as po, CustomerInfo_relational as c,\n" + + " Lineitem_relational as l, Products_relational as p\n" + + " WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID\n" + + " GROUP BY po.PoNum,po.CustID,po.OrderDate,po.Status,c.Name,\n" + + " c.Street, c.City,c.Province, c.PostalCode,po.Comment\n" + + " ORDER BY po.CustID,po.OrderDate\n"); + + ResultSet rs = stmt.executeQuery( + "SELECT po.CustID, po.PoNum, po.OrderDate, po.Status," + + " count(l.ProdID) as Items, sum(p.Price) as total," + + " po.Comment, c.Name, c.Street, c.City, c.Province, c.PostalCode" + + " FROM PurchaseOrder_relational as po, CustomerInfo_relational as c," + + " Lineitem_relational as l, Products_relational as p" + + " WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID" + + " GROUP BY po.PoNum,po.CustID,po.OrderDate,po.Status,c.Name," + + " c.Street, c.City,c.Province, c.PostalCode,po.Comment" + + " ORDER BY po.CustID,po.OrderDate"); + + System.out.println(); + System.out.println(" Results:\n" + + " CustId PoNum OrderDate Status" + + " \t Items Total_Price Comment\n" + + " \t\t Name \t\t Street \t City \t Province \t PostalCode\n" + + " -----------------------------------------------------------------------------\n"); + + int CustId = 0; + int PoNum = 0; + String OrderDate = ""; + String Status = ""; + int Items = 0; + double Price = 0; + String Comment = ""; + String Name = ""; + String Street= ""; + String City = ""; + String Province = ""; + int PostalCode = 0; + + while (rs.next()) + { + CustId = rs.getInt(1); + PoNum = rs.getInt(2); + OrderDate = rs.getString(3); + Status = rs.getString(4); + Items = rs.getInt(5); + Price = rs.getDouble(6); + Comment = rs.getString(7); + Name = rs.getString(8); + Street = rs.getString(9); + City = rs.getString(10); + Province = rs.getString(11); + PostalCode = rs.getInt(12); + System.out.println(" " + + Data.format(CustId, 8) + " " + + Data.format(PoNum, 8) + " " + + Data.format(OrderDate, 11) + " " + + Data.format(Status, 50) + " " + + Data.format(Items, 5) + " " + + Data.format(Price,6,2) + " " + + Data.format(Comment, 200) + " " + + Data.format(Name, 20) + " " + + Data.format(Street, 20) + " " + + Data.format(City, 20) + " " + + Data.format(Province, 20) + " " + + Data.format(PostalCode, 8)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } //execQuery + + public static void callRelToXmlProc(Connection con) + { + try + { + // prepare the CALL statement for ONE_RESULT_SET + String procName = "RELTOXMLPROC"; + String sql = "CALL " + procName + "()"; + CallableStatement callStmt = con.prepareCall(sql); + + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + callStmt.execute(); + + System.out.println(procName + " completed successfully"); + ResultSet rs = callStmt.getResultSet(); + fetchAll(rs); + + // close ResultSet and callStmt + rs.close(); + callStmt.close(); + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callRelToXmlProc + + public static void fetchAll(ResultSet rs) + { + try + { + System.out.println( + "============================================================="); + + // retrieve the number, types and properties of the + // resultset's columns + ResultSetMetaData stmtInfo = rs.getMetaData(); + + String PurchaseOrder = ""; + int numOfColumns = stmtInfo.getColumnCount(); + int r = 0; + + while (rs.next()) + { + r++; + System.out.print("Row: " + r + ": "); + for (int i = 1; i <= numOfColumns; i++) + { + if (i == 1 || i == 2) + { + System.out.print(Data.format(rs.getInt(i), 8)); + } + if (i == 3) + { + System.out.print(rs.getString(i)); + } + if (i == 4) + { + PurchaseOrder = rs.getString(i); + System.out.print(Data.format(PurchaseOrder, 500)); + } + if (i != numOfColumns) + { + System.out.print(", "); + } + } + System.out.println(); + } + } + catch (Exception e) + { + System.out.println("Error: fetchALL: exception"); + System.out.println(e.getMessage()); + } + } // fetchAll +} // RelToXmlDoc + + diff --git a/xml/java/jdbc/RelToXmlType.java b/xml/java/jdbc/RelToXmlType.java new file mode 100644 index 0000000..25bdca3 --- /dev/null +++ b/xml/java/jdbc/RelToXmlType.java @@ -0,0 +1,242 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: RelToXmlType.java +// +// SAMPLE : Purchase order database uses relational tables to store the orders of +// different customers. This data can be returned as an XML object to the +// application. The XML object can be created using the XML constructor +// functions on the server side. +// To achieve this, the user can +// 1. Create new tables having XML columns. (Done in set up script) +// 2. Change the relational data to XML type using constructor functions. +// 3. Insert the data in new tables +// 4. Use the query to select all PO data. +// +// PREREQUISITE: +// The relational tables that store the purchase order data will have to +// be created before this sample is executed. For this the file +// setupscript.db2 will have to be run using the command +// db2 -tvf setupscript.db2 +// After successfull execution of the script, this sample can be compiled using +// javac RelToXmlType.java +// and executed using +// java RelToXmlType +// +// Please make sure that you run the cleanup script after running the +// sample using following command +// db2 -tvf cleanupscript.db2 +// +// SQL Statements USED: +// SELECT +// INSERT +// +// SQL/XML FUNCTION USED: +// XMLDOCUMENT +// XMLELEMENT +// XMLATTRIBUTES +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// OUTPUT FILE: RelToXmlType.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class RelToXmlType +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CONVERT DATA RELATIONAL TABLES\n" + + "INTO A XML DOCUMENT USING THE XML CONSTRUCTOR FUNCTIONS"); + + // connect to the 'sample' database + db.connect(); + + // execute the Query to Select data from relation tables + // and insert into tables as XML data type. + execQuery(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void execQuery(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " Statement\n" + + "TO EXECUTE THE QUERY WITH XML CONSTRUCTORS."); + + Statement stmt = con.createStatement(); + + // execute the query + System.out.println(); + System.out.println( + " Execute Statement:\n" + + "INSERT INTO Customerinfo_New (Custid, Address)\n" + + "(SELECT Custid, \n" + + "XMLDOCUMENT( \n" + + "XMLELEMENT(NAME \"Address\", \n" + + "XMLELEMENT(NAME \"Name\", c.Name), \n" + + "XMLELEMENT(NAME \"Street\", c.Street), \n" + + "XMLELEMENT(NAME \"City\", c.City), \n" + + "XMLELEMENT(NAME \"Province\", c.Province), \n" + + "XMLELEMENT(NAME \"PostalCode\", c.PostalCode))) \n" + + "FROM CustomerInfo_relational AS C)\n"); + + stmt.executeUpdate( + "INSERT INTO Customerinfo_New (Custid, Address)" + + "(SELECT Custid, " + + "XMLDOCUMENT( " + + "XMLELEMENT(NAME \"Address\", " + + "XMLELEMENT(NAME \"Name\", c.Name), " + + "XMLELEMENT(NAME \"Street\", c.Street), " + + "XMLELEMENT(NAME \"City\", c.City), " + + "XMLELEMENT(NAME \"Province\", c.Province), " + + "XMLELEMENT(NAME \"PostalCode\", c.PostalCode))) " + + "FROM CustomerInfo_relational AS C)"); + + System.out.println( + "Execute Statement:\n" + + "INSERT INTO purchaseorder_new(PoNum, OrderDate, CustID, Status, LineItems)\n" + + "(SELECT Po.PoNum, OrderDate, CustID, Status,\n" + + "XMLDOCUMENT(\n" + + "XMLELEMENT(NAME \"itemlist\", \n" + + "XMLELEMENT(NAME \"PartID\", l.ProdID),\n" + + "XMLELEMENT(NAME \"Description\", p.Description ),\n" + + "XMLELEMENT(NAME \"Quantity\", l.Quantity),\n" + + "XMLELEMENT(NAME \"Price\", p.Price)))\n" + + "FROM purchaseorder_relational AS po, lineitem_relational AS l,\n" + + "products_relational AS P\n" + + "WHERE l.PoNum=po.PoNum AND l.ProdID=P.ProdID)\n"); + + stmt.executeUpdate( + "INSERT INTO purchaseorder_new(PoNum, OrderDate, CustID, Status, LineItems) " + + "(SELECT Po.PoNum, OrderDate, CustID, Status, " + + "XMLDOCUMENT( " + + "XMLELEMENT(NAME \"itemlist\", " + + "XMLELEMENT(NAME \"PartID\", l.ProdID), " + + "XMLELEMENT(NAME \"Description\", p.Description ), " + + "XMLELEMENT(NAME \"Quantity\", l.Quantity), " + + "XMLELEMENT(NAME \"Price\", p.Price))) " + + "FROM purchaseorder_relational AS po, lineitem_relational AS l, " + + " products_relational AS P " + + "WHERE l.PoNum=po.PoNum AND l.ProdID=P.ProdID)"); + + System.out.println(); + + ResultSet rs = stmt.executeQuery( + "SELECT po.PoNum, po.CustId, po.OrderDate, " + + "XMLELEMENT(NAME \"PurchaseOrder\", " + + "XMLATTRIBUTES(po.CustID AS \"CustID\", po.PoNum AS \"PoNum\", " + + " po.OrderDate AS \"OrderDate\", po.Status AS \"Status\")), " + + "XMLELEMENT(NAME \"Address\", c.Address), " + + "XMLELEMENT(NAME \"lineitems\", po.LineItems) " + + "FROM PurchaseOrder_new AS po, CustomerInfo_new AS c " + + "WHERE po.custid = c.custid " + + "ORDER BY po.custID"); + + int CustId = 0; + int PoNum = 0; + String OrderDate = ""; + String PurchaseOrder = ""; + String Address = ""; + String LineItem = ""; + String Name = ""; + String Street= ""; + String City = ""; + String Province = ""; + int PostalCode = 0; + + while (rs.next()) + { + PoNum = rs.getInt(1); + CustId = rs.getInt(2); + OrderDate = rs.getString(3); + PurchaseOrder = rs.getString(4); + Address = rs.getString(5); + LineItem = rs.getString(6); + + System.out.println(" " + + "\n Customer ID : " + + Data.format(CustId, 8) + " " + + "\n Purchase Order Number : " + + Data.format(PoNum, 8) + " " + + "\n Purchase Order Date : " + + Data.format(OrderDate, 11) + " " + + "\n Purchase Order Document : \n" + + Data.format(PurchaseOrder, 1000) + " " + + "\n Address in XML Format: \n" + + Data.format(Address, 500) + " " + + "\n Line Item in XML Format\n" + + Data.format(LineItem, 500)); + } + rs.close(); + + // Rollback the changes + con.rollback(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } //execQuery +} // RelToXmlType + + diff --git a/xml/java/jdbc/Simple_XmlProc.java b/xml/java/jdbc/Simple_XmlProc.java new file mode 100644 index 0000000..ea20f83 --- /dev/null +++ b/xml/java/jdbc/Simple_XmlProc.java @@ -0,0 +1,198 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: Simple_XmlProc.java +// +// SAMPLE: Code implementation of stored procedure Simple_XML_Proc_Java +// The stored procedures defined in this program are called by the +// client application Simple_XmlProc_Client.java. Before building and +// running Simple_XmlProc_Client.java, build the shared library by +// completing the following steps: +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file Simple_XmlProc.java (this will +// erase the existing library/class files and copy the newly +// compiled class files, Simple_XmlProc.class, from the current +// directory to the $(DB2PATH)\function directory): +// nmake/make Simple_XmlProc +// 2. Compile the client source file Simple_XmlProc_Client.java(this will +// also call the script 'spcat_xml' to create and catalog the stored +// procedures): +// nmake/make Simple_XmlProc_Client +// 3. Run the client Simple_XmlProc_Client: +// java Simple_XmlProc_Client +// +// II) If you don't have a compatible make/nmake program on your +// system do the following: +// 1. Compile the server source file with: +// javac Simple_XmlProc.java +// 2. Erase the existing library/class files (if exists), +// Simple_XmlProc.class from the following path, +// $(DB2PATH)\function. +// 3. Copy the class files, Simple_XmlProc.class from the current +// directory to the $(DB2PATH)\function. +// 4. Catalog the stored procedures in the database with the script: +// spcat_xml +// 5. Compile Simple_XmlProc_Client with: +// javac Simple_XmlProc_Client.java +// 6. Run Simple_XmlProc_Client with: +// java Simple_XmlProc_Client +// +// Class Simple_XmlProc contains one method which solves the following scenario: +// This method will take Customer Information ( of type XML) as input , +// finds whether the customer with Cid in Customer Information exists in the +// customer table or not, if not this will insert the customer information +// into the customer table with same Customer id, and returns all the customers +// from the same city of the input customer information in XML format to the caller +// along with location as an output parameter in XML format. +// +// SQL Statements USED: +// CREATE +// SELECT +// INSERT +// +// OUTPUT FILE: Simple_XmlProc_Client.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; // JDBC classes +import java.io.*; // Input/Output classes +import java.lang.*; // for String class +import COM.ibm.db2.app.StoredProc; // Stored Proc classes +import com.ibm.db2.jcc.DB2Xml; // XML classes +import COM.ibm.db2.app.Clob; // CLOB classes +import java.math.BigDecimal; // Basic Arithmetic + +// Java stored procedure in this class +public class Simple_XmlProc extends StoredProc +{ + Connection con; + ResultSet outRs; + public void Simple_Proc ( com.ibm.db2.jcc.DB2Xml inXML, + com.ibm.db2.jcc.DB2Xml outXML, + int retcode ) + throws Exception + { + com.ibm.db2.jcc.DB2Xml tempXML = null; + int custid = 0; + String city = null; + int count = 0; + + // get caller's connection to the database + con = DriverManager.getConnection("jdbc:default:connection"); + + // get the input XML document into an application variable + String ipdata = inXML.getDB2String() ; + + // find whether the customer with that Info exists in the customer table + String query1 = "SELECT COUNT(*) FROM customer WHERE " + + " XMLEXISTS('$info/customerinfo[@Cid=$id]' PASSING by ref " + + "cast(? as XML) AS \"info\", cid as \"id\")"; + PreparedStatement stmt1 = con.prepareStatement(query1); + stmt1.setString (1, ipdata); + ResultSet rs1 = stmt1.executeQuery(); + if(rs1.next()) + { + count = rs1.getInt(1); + } + rs1.close(); + + // if customer doesn't exist ...... insert into the table + if ( count < 1 ) + { + // get the custid from the customer information + String query2 = "SELECT XMLCAST( XMLQUERY('$info/customerinfo/@Cid' " + + "passing by ref cast(? as XML) as \"info\") as " + + "INTEGER) FROM SYSIBM.SYSDUMMY1 "; + PreparedStatement stmt2 = con.prepareStatement(query2); + stmt2.setString (1, ipdata); + ResultSet rs2 = stmt2.executeQuery(); + if(rs2.next()) + { + custid = rs2.getInt(1); + } + rs2.close(); + + // insert into customer table with that custid + String query3 = "INSERT INTO customer(Cid, Info) VALUES (?,?)"; + PreparedStatement stmt3 = con.prepareStatement(query3); + stmt3.setInt(1, custid); + stmt3.setString(2, ipdata); + stmt3.executeUpdate(); + } + + // find the city of the customer and assign it to an application variable + String query4 = "SELECT XMLCAST( XMLQUERY('$info/customerinfo//city' " + + "passing by ref cast(? as XML) as \"info\") as " + + "VARCHAR(100)) FROM SYSIBM.SYSDUMMY1"; + PreparedStatement stmt4 = con.prepareStatement(query4); + stmt4.setString (1, ipdata); + ResultSet rs4 = stmt4.executeQuery(); + if(rs4.next()) + { + city=rs4.getString(1); + } + rs4.close(); + + // select location fron the input XML and assign it to output parameter + String query5 = "SELECT XMLQUERY('let $city := $info/customerinfo//city " + + "let $prov := $info/customerinfo//prov-state return " + + "{$city, $prov} ' passing by ref cast(? as XML) as " + + "\"info\") FROM SYSIBM.SYSDUMMY1"; + PreparedStatement stmt5 = con.prepareStatement(query5); + stmt5.setString (1, ipdata); + ResultSet rs5 = stmt5.executeQuery(); + if(rs5.next()) + { + tempXML = (DB2Xml) rs5.getObject(1) ; + } + // assign the result XML document to output parameters + set(2, tempXML); + rs5.close(); + + // findout all the customers from that city and return as an XML to caller + String query6 = "XQUERY for $cust in db2-fn:xmlcolumn(\"CUSTOMER.INFO\")/customerinfo/ " + + "addr[city = \"" + city + "\"] return {$cust/../@Cid}" + + "{$cust/../name}"; + // prepare the SQL statement + PreparedStatement stmt6 = con.prepareStatement(query6); + // get the result set that will be returned to the client + outRs = stmt6.executeQuery(); + con.close(); + + set(3, 0); + } +} + + diff --git a/xml/java/jdbc/Simple_XmlProc_Client.java b/xml/java/jdbc/Simple_XmlProc_Client.java new file mode 100644 index 0000000..99fce44 --- /dev/null +++ b/xml/java/jdbc/Simple_XmlProc_Client.java @@ -0,0 +1,245 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: Simple_XmlProc_Client.java +// +// SAMPLE: Call the stored procedure implemented in Simple_XmlProc.java +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file Simple_XmlProc.java (this will +// also erase the existing library/class files and copy the newly +// compiled class files, Simple_XmlProc.class, from the current +// directory to the $(DB2PATH)\function directory): +// nmake/make Simple_XmlProc +// 2. Compile the client source file Simple_XmlProc_Client.java (this +// will also call the script 'spcat_xml' to create and catalog the +// stored procedures): +// nmake/make Simple_XmlProc_Client +// 3. Run the client Simple_XmlProc_Client: +// java Simple_XmlProc_Client +// +// II) If you don't have a compatible make/nmake program on your +// system do the following: +// 1. Compile the server source file with: +// javac Simple_XmlProc.java +// 2. Erase the existing library/class files (if exists), +// Simple_XmlProc.class from the following path, +// $(DB2PATH)\function. +// 3. Copy the class files, Simple_XmlProc.class from the current +// directory to the $(DB2PATH)\function. +// 4. Catalog the stored procedures in the database with: +// spcat_xml +// 5. Compile Simple_XmlProc_Client with: +// javac Simple_XmlProc_Client.java +// 6. Run Simple_XmlProc_Client with: +// java Simple_XmlProc_Client +// +// Simple_XmlProc_Client calls callSimple_Proc method that calls the stored procedure: +// This method will take Customer Information ( of type XML) as input , +// finds whether the customer with Cid in Customer Information exists in the +// customer table or not, if not this will insert the customer information +// into the customer table with same Customer id, and returns all the customers +// from the same city of the input customer information in XML format to the caller +// along with location as an output parameter in XML format. +// +// Parameter types used: IN XML AS CLOB(5000) +// OUT XML AS CLOB(5000) +// OUT INTEGER +// SQL Statements USED: +// CALL +// +// OUTPUT FILE: Simple_XmlProc_Client.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; // for String class +import java.io.*; // for ...Stream classes +import COM.ibm.db2.app.StoredProc; // Stored Proc classes +import java.sql.*; // for JDBC classes +import com.ibm.db2.jcc.*; // for XML class +import COM.ibm.db2.app.Clob; // for CLOB class +import java.util.*; // Utility classes + +class Simple_XmlProc_Client +{ + + public static void main(String argv[]) + { + Connection con = null; + // connect to sample database + String url = "jdbc:db2:sample"; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + catch (Exception e) + { + System.out.println(" Error loading DB2 Driver...\n"); + System.out.println(e); + System.exit(1); + } + try + { + con = DriverManager.getConnection(url); + con.setAutoCommit(false); + } + catch (SQLException e) + { + System.out.println("Connection to sample db can't be established."); + System.err.println(e) ; + System.exit(1); + } + // call the procedure to call stored procedure + callSimple_Proc(con); + + return ; + } // end main + + // callSimple_Proc procedure to call the stored procedure + public static void callSimple_Proc(Connection con) + { + try + { + // prepare the CALL statement + String procName = "Simple_XML_Proc_Java"; + String sql = "CALL " + procName + "( ?, ?, ?)"; + + CallableStatement callStmt = con.prepareCall(sql); + + // input data + String inXml = "" + + "Kathy Smith25 EastCreek" + + "MarkhamOntario" + + "N9C-3T6905-566-7258" + + ""; + callStmt.setString (1, inXml ) ; + + // register the output parameter + callStmt.registerOutParameter(2, com.ibm.db2.jcc.DB2Types.XML); + callStmt.registerOutParameter(3, Types.INTEGER); + + // call the stored procedure + System.out.println(); + System.out.println("Calling stored procedure " + procName); + callStmt.execute(); + System.out.println(procName + " called successfully"); + // retrieve output parameters + com.ibm.db2.jcc.DB2Xml outXML = (DB2Xml) callStmt.getObject(2); + System.out.println("\n \n Location is :\n " + + outXML.getDB2String()); + ResultSet rs = callStmt.getResultSet(); + fetchAll(rs); + // close ResultSet and callStmt + rs.close(); + int retcode = callStmt.getInt(3); + System.out.println("\n \n Return code " + " : " + retcode ); + + // Rollback the transactions to keep database consistent + System.out.println("\n \n --Rollback the transaction-----"); + con.rollback(); + System.out.println(" Rollback done!"); + + // clean up resources + callStmt.close(); + + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + System.out.println(); + + if (con != null) + { + try + { + System.out.println("--Rollback the transaction-----"); + con.rollback(); + System.out.println(" Rollback done!"); + } + catch (Exception error ) + { + } + } + System.out.println("--FAILED----"); + } + + return ; + } + public static void fetchAll(ResultSet rs) + { + try + { + System.out.println( + "============================================================="); + + // retrieve the number, types and properties of the + // resultset's columns + ResultSetMetaData stmtInfo = rs.getMetaData(); + + int numOfColumns = stmtInfo.getColumnCount(); + int r = 0; + + System.out.println("\n \n Procedure returned :"); + + while (rs.next()) + { + r++; + for (int i = 1; i <= numOfColumns; i++) + { + if (i == 1) + { + com.ibm.db2.jcc.DB2Xml tempXML = (DB2Xml) rs.getObject(i); + System.out.println("\n \n " + tempXML.getDB2String()); + } + else + { + System.out.print(rs.getString(i)); + } + + if (i != numOfColumns) + { + System.out.print(", "); + } + } + System.out.println(); + } + } + catch (Exception e) + { + System.out.println("Error: fetchALL: exception"); + System.out.println(e.getMessage()); + } + } // fetchAll +} + diff --git a/xml/java/jdbc/Simple_XmlProc_Create.db2 b/xml/java/jdbc/Simple_XmlProc_Create.db2 new file mode 100644 index 0000000..868e674 --- /dev/null +++ b/xml/java/jdbc/Simple_XmlProc_Create.db2 @@ -0,0 +1,47 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: Simple_XmlProc_Create.db2 +-- +-- SAMPLE: How to catalog the stored procedure contained in Simple_XmlProc.java +-- +-- To run this script from the CLP, +-- issue the command "db2 -td@ -vf Simple_XmlProc_Create.db2" +---------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- create the procedure +CREATE PROCEDURE Simple_XML_Proc_Java( IN inXML XML as CLOB(5000), + OUT outXML XML as CLOB(5000), + OUT RetCode INTEGER) +DYNAMIC RESULT SETS 1 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE DB2GENERAL +NO DBINFO +FENCED +THREADSAFE +MODIFIES SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'Simple_XmlProc.Simple_Proc'@ + +CONNECT RESET@ diff --git a/xml/java/jdbc/Simple_XmlProc_Drop.db2 b/xml/java/jdbc/Simple_XmlProc_Drop.db2 new file mode 100644 index 0000000..195024c --- /dev/null +++ b/xml/java/jdbc/Simple_XmlProc_Drop.db2 @@ -0,0 +1,36 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: Simple_XmlProc_Drop.db2 +-- +-- SAMPLE: How to uncatalog the stored procedure in Simple_XmlProc.java +-- +-- To run this script from the CLP, +-- issue the command "db2 -td@ -vf Simple_XmlProc_Drop.db2" +---------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- drop the procedure +DROP PROCEDURE Simple_XML_Proc_Java( XML AS CLOB(5000), XML AS CLOB(5000), INTEGER)@ + +CONNECT RESET@ + diff --git a/xml/java/jdbc/Util.java b/xml/java/jdbc/Util.java new file mode 100644 index 0000000..954b84b --- /dev/null +++ b/xml/java/jdbc/Util.java @@ -0,0 +1,340 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Util.java +// +// SAMPLE: Utilities for JDBC sample programs +// +// This sample has 3 classes: +// 1. Data - Display the data in the table +// 2. Db - Connect to or disconnect from the 'sample' database +// 3. JdbcException - Handle Java Exceptions +// +// JAVA 2 CLASSES USED: +// DriverManager +// Connection +// Exception +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.util.*; +import java.sql.*; +import java.math.BigDecimal; + +class Data +{ + public static String format(String strData, int finalLen) throws Exception + { + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = strData; + for (int i = strData.length(); i < finalLen; i++) + { + finalStr = finalStr + " "; + } + } + return (finalStr); + } // format(String, int) + + public static String format(int intData, int finalLen) throws Exception + { + String strData = String.valueOf(intData); + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + return (finalStr); + } // format(int, int) + + public static String format(Integer integerData, int finalLen) + throws Exception + { + int intData; + String finalStr; + + intData = integerData.intValue(); + finalStr = format(intData, finalLen); + + return (finalStr); + } // format(Integer, int) + + public static String format(double doubData, int precision, int scale) + throws Exception + { + BigDecimal decData = new BigDecimal(doubData); + decData = decData.setScale(scale, BigDecimal.ROUND_HALF_EVEN); + String strData = decData.toString(); + + // prepare the final string + int finalLen = precision + 1; + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + + return (finalStr); + } // format(double, int, int) + + public static String format(BigDecimal decData, int precision, int scale) + throws Exception + { + decData = decData.setScale(scale, BigDecimal.ROUND_HALF_EVEN); + String strData = decData.toString(); + + // prepare the final string + int finalLen = precision + 1; + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + + return (finalStr); + } // format(BigDecimal, int, int) + + public static String format(Double doubleData, int precision, int scale) + throws Exception + { + double doubData; + String finalStr; + + doubData = doubleData.doubleValue(); + return (format(doubData, precision, scale)); + } // format(Double, int, int) +} // Data + +class Db +{ + public String alias; + public String server; + public int portNumber = -1; // < 0 use universal type 2 connection + // > 0 use universal type 4 connection + public String userId; + public String password; + public Connection con = null; + + public Db() + { + } + + public Db(String argv[]) throws Exception + { + if( argv.length > 5 || + ( argv.length == 1 && + ( argv[0].equals( "?" ) || + argv[0].equals( "-?" ) || + argv[0].equals( "/?" ) || + argv[0].equalsIgnoreCase( "-h" ) || + argv[0].equalsIgnoreCase( "/h" ) || + argv[0].equalsIgnoreCase( "-help" ) || + argv[0].equalsIgnoreCase( "/help" ) ) ) ) + { + throw new Exception( + "Usage: prog_name [dbAlias] [userId passwd] (use universal JDBC type 2 driver)\n" + + " prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)" ); + } + + switch (argv.length) + { + case 0: // Type 2, use all defaults + alias = "sample"; + userId = ""; + password = ""; + break; + case 1: // Type 2, dbAlias specified + alias = argv[0]; + userId = ""; + password = ""; + break; + case 2: // Type 2, userId & passwd specified + alias = "sample"; + userId = argv[0]; + password = argv[1]; + break; + case 3: // Type 2, dbAlias, userId & passwd specified + alias = argv[0]; + userId = argv[1]; + password = argv[2]; + break; + case 4: // Type 4, use default dbAlias + alias = "sample"; + server = argv[0]; + portNumber = Integer.valueOf( argv[1] ).intValue(); + userId = argv[2]; + password = argv[3]; + break; + case 5: // Type 4, everything specified + alias = argv[0]; + server = argv[1]; + portNumber = Integer.valueOf( argv[2] ).intValue(); + userId = argv[3]; + password = argv[4]; + break; + } + } // Db Constructor + + public Connection connect() throws Exception + { + String url = null; + + // In Partitioned Database environment, set this to the node number + // to which you wish to connect (leave as "0" in non-Partitioned Database environment) + String nodeNumber = "0"; + + Properties props = new Properties(); + + if ( portNumber < 0 ) + { + url = "jdbc:db2:" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 2 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + else + { + url = "jdbc:db2://" + server + ":" + portNumber + "/" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 4 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + + if( null != userId ) + { + props.setProperty("user", userId); + props.setProperty("password", password); + } + + props.setProperty("CONNECTNODE", nodeNumber); + + con = DriverManager.getConnection( url, props ); + + // enable transactions + con.setAutoCommit(false); + return con; + } // connect + + public void disconnect() throws Exception + { + System.out.println(); + System.out.println(" Disconnect from '" + alias + "' database."); + + // makes all changes made since the previous commit/rollback permanent + // and releases any database locks currrently held by the Connection. + con.commit(); + + // immediately disconnects from database and releases JDBC resources + con.close(); + } // disconnect +} // Db + +class JdbcException extends Exception +{ + Connection conn; + + public JdbcException(Exception e) + { + super(e.getMessage()); + conn = null; + } + + public JdbcException(Exception e, Connection con) + { + super(e.getMessage()); + conn = con; + } + + public void handle() + { + System.out.println(getMessage()); + System.out.println(); + + if (conn != null) + { + try + { + System.out.println("--Rollback the transaction-----"); + conn.rollback(); + System.out.println(" Rollback done!"); + } + catch (Exception e) + { + }; + } + } // handle + + public void handleExpectedErr() + { + System.out.println(); + System.out.println( + "**************** Expected Error ******************\n"); + System.out.println(getMessage()); + System.out.println( + "**************************************************"); + } // handleExpectedError +} // JdbcException + diff --git a/xml/java/jdbc/XmlCheckConstraint.java b/xml/java/jdbc/XmlCheckConstraint.java new file mode 100644 index 0000000..053f08f --- /dev/null +++ b/xml/java/jdbc/XmlCheckConstraint.java @@ -0,0 +1,793 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: XmlCheckConstraint.java +// +// PURPOSE: This sample shows how to create check constraints on XML column. +// +// USAGE SCENARIO: Super market maintains different stores for different +// products like music players, boots, headphones. Each store sells one +// type of product, as they would want to have separate accounting or +// billing for their products. Super market application maintains a +// separate table data for each product to make his work easy.Whenever +// a customer purchases some product an entry is made in the corresponding +// table restricting the table to a particular product entry. +// Because there are multiple tables and if the manager wants to frequently +// view data from multiple tables, he creates a view on top of these product +// tables with required columns. Also, when a customer purchases 2 or +// more products, inserting data from view has made his job easy. +// Some times when he wants to get the customer address details, he uses +// "customer" table from sample database to get only valid data using +// IS VALIDATED predicate. In XML case, users can insert data into tables +// through views. But if the user wants to select data, as indexes are +// created on XML documents on base tables and not on views, it would be +// best to make use of indexes on base tables rather than using +// select on views. +// +// PREREQUISITE: +// On Unix: copy boots.xsd file from /sqllib +// /samples/xml/data directory to current directory. +// copy musicplayer.xsd file from /sqllib +// /samples/xml/data directory to current directory. +// On Windows: copy boots.xsd file from \sqllib\samples\ +// xml\data directory to current directory +// copy musicplayer.xsd file from \sqllib\ +// samples\xml\data directory to current directory +// +// EXECUTION: javac XmlCheckConstraint.java +// java XmlCheckConstraint +// +// INPUTS: NONE +// +// OUTPUTS: One of the insert statements will fail because of check +// constraint violation. All other statements will succeed. +// +// +// OUTPUT FILE: XmlCheckConstraint.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// CREATE +// INSERT +// DELETE +// DROP +// +// SQL/XML FUNCTIONS USED: +// XMLDOCUMENT +// XMLPARSE +// XMLVALIDATE +// +//*************************************************************************** +// For more information about the command line processor (CLP) scripts, +// see the README file. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, building, and running DB2 +// applications, visit the DB2 application development website: +// http://www.software.ibm.com/data/db2/udb/ad +// +//*************************************************************************** +// SAMPLE DESCRIPTION +// +//*************************************************************************** +// +// 1. Register XML schemas +// +// 2. Create tables with check constraint on XML column and insert data into +// tables. +// +// 3. Show partitioning of tables by schema. +// +// 4. Show usage of IS VALIDATED and IS NOT VALIDATED predicates. +// +// 5. Shows insert statement failure when check constraint is violated. +// +// 6. Show check constraint and view dependency on schema. +// +//*************************************************************************** +// +// IMPORT ALL PACKAGES AND CLASSES +// +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; + +class XmlCheckConstraint +{ + public static void main(String argv[]) + { + int rc = 0; + String url = "jdbc:db2:sample"; + Connection con = null; + try + { + + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + System.out.println(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + System.out.println("THIS SAMPLE SHOWS HOW TO CREATE CHECK CONSTRAINTS"); + System.out.println(" ON XML COLUMN"); + System.out.println("------------------------------------------------\n"); + + registerXmlSchemaBoots(con); + registerXmlSchemaMusicPlayer(con); + createCheckConstrainOnXmlColumn(con); + partitionTablesBySchema(con); + usageOfValidatedPredicates(con); + checkConstraintViolation(con); + dependencyOnSchema(con); + cleanUp(con); + } //main + + //************************************************************************** + // 1. Register XML schemas + //************************************************************************** + static void registerXmlSchemaBoots(Connection con) + { + String relSchema=new String("POSAMPLE1"); + String schemaName=new String("boots");; + String schemaLocation= new String("http://posample1.org/boots"); + String primaryDocument= new String("boots.xsd"); + int shred = 0; + + try + { + // register primary XML Schema + System.out.println("--------------------------------------------------"); + System.out.println("Registering main schema "+ primaryDocument +"..."); + CallableStatement callStmt = + con.prepareCall("CALL SYSPROC.XSR_REGISTER(?,?,?,?,NULL)"); + File xsdFile = new File(primaryDocument); + FileInputStream xsdData = new FileInputStream(xsdFile); + callStmt.setString(1, relSchema); + callStmt.setString(2, schemaName); + callStmt.setString(3, schemaLocation ); + callStmt.setBinaryStream(4, xsdData, (int)xsdFile.length() ); + callStmt.execute(); + xsdData.close(); + + // complete the registeration + System.out.println(" Completing XML Schema registeration"); + callStmt=con.prepareCall("CALL SYSPROC.XSR_COMPLETE(?,?,NULL,?)"); + callStmt.setString(1,relSchema); + callStmt.setString(2, schemaName); + callStmt.setInt(3, shred); + callStmt.execute(); + System.out.println("Schema registered successfully"); + callStmt.close(); + System.out.println("-------------------------------------------------"); + System.out.println("\n\n"); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(IOException ioe) + { + System.out.println("Error opening file " + primaryDocument); + } + } //registerXmlSchemaBoots + + static void registerXmlSchemaMusicPlayer(Connection con) + { + String relSchema=new String("POSAMPLE1"); + String schemaName=new String("musicplayer");; + String schemaLocation= new String("http://posample1.org/musicplayer"); + String primaryDocument= new String("musicplayer.xsd"); + int shred = 0; + + try + { + // register primary XML Schema + System.out.println("--------------------------------------------------"); + System.out.println("Registering main schema "+ primaryDocument +"..."); + CallableStatement callStmt = + con.prepareCall("CALL SYSPROC.XSR_REGISTER(?,?,?,?,NULL)"); + File xsdFile = new File(primaryDocument); + FileInputStream xsdData = new FileInputStream(xsdFile); + callStmt.setString(1, relSchema); + callStmt.setString(2, schemaName); + callStmt.setString(3, schemaLocation ); + callStmt.setBinaryStream(4, xsdData, (int)xsdFile.length() ); + callStmt.execute(); + xsdData.close(); + + // complete the registeration + System.out.println(" Completing XML Schema registeration"); + callStmt=con.prepareCall("CALL SYSPROC.XSR_COMPLETE(?,?,NULL,?)"); + callStmt.setString(1,relSchema); + callStmt.setString(2, schemaName); + callStmt.setInt(3, shred); + callStmt.execute(); + System.out.println("Schema registered successfully"); + callStmt.close(); + System.out.println("-------------------------------------------------"); + System.out.println("\n\n"); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(IOException ioe) + { + System.out.println("Error opening file " + primaryDocument); + } + } //registerXmlSchemaMusicPlayer + + //************************************************************************** + // 2. Create tables with check constraint on XML column and insert data into + // tables. + //************************************************************************** + static void createCheckConstrainOnXmlColumn(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + + System.out.println("Create table with check constraints and insert"); + System.out.println(" data into tables "); + System.out.println("-----------------------------------------------\n"); + + // Shows check constraint on multiple schemas + String str = "CREATE TABLE item(custid int, xmldoc XML constraint "+ + "valid_check CHECK(xmldoc IS VALIDATED ACCORDING TO "+ + "XMLSCHEMA IN (ID posample1.musicplayer, ID posample1.boots)))"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + str = "INSERT INTO item "+ + "VALUES(100, xmlvalidate(xmlparse(document "+ + "' "+ + ""+ + "samsung"+ + " 200 watts "+ + "5"+ + "3"+ + "2"+ + "400.00"+ + ""+ + " ') ACCORDING TO XMLSCHEMA ID posample1.musicplayer))"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + str = "INSERT INTO item "+ + "VALUES (100, XMLVALIDATE(XMLPARSE(document "+ + "'"+ + ""+ + "adidas"+ + "7"+ + "10"+ + "299.9"+ + ""+ + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + str = "CREATE TABLE musicplayer (custid int, "+ + "xmldoc XML constraint valid_check1 CHECK(xmldoc "+ + "IS VALIDATED ACCORDING TO XMLSCHEMA ID "+ + " posample1.musicplayer))"; + + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + str = "INSERT INTO musicplayer "+ + "VALUES(100, xmlvalidate(xmlparse(document "+ + "'"+ + ""+ + "sony"+ + " 100 watts"+ + "5"+ + "3"+ + "4"+ + "200.00"+ + ""+ + " ') ACCORDING TO XMLSCHEMA ID posample1.musicplayer))"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + str = "CREATE TABLE boots (custid int, "+ + "xmldoc XML constraint valid_check2 CHECK(xmldoc "+ + "IS VALIDATED ACCORDING TO XMLSCHEMA ID posample1.boots))"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + str = "INSERT INTO boots "+ + "VALUES (100, XMLVALIDATE(XMLPARSE(document "+ + "'"+ + ""+ + "nike"+ + "7"+ + "10"+ + "99.9"+ + ""+ + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //createCheckConstrainOnXmlColumn + + //************************************************************************** + // 3. Show partitioning of tables by schema. + //************************************************************************** + + static void partitionTablesBySchema(Connection con) + { + Statement stmt = null; + try + { + System.out.println(); + System.out.println("--------------------------------------------"); + System.out.println(" Partition tables by schema "); + System.out.println("--------------------------------------------"); + System.out.println(); + + stmt = con.createStatement(); + String str = "CREATE VIEW view_purchases(custid, xmldoc) AS "+ + "(SELECT * FROM musicplayer " + + "UNION ALL SELECT * FROM boots)"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + str = "INSERT INTO view_purchases "+ + "VALUES (1001,xmlvalidate(xmlparse(document "+ + "'"+ + ""+ + "philips"+ + " 1000 watts"+ + "2"+ + "5"+ + "4"+ + "1200.00"+ + ""+ + "') ACCORDING TO XMLSCHEMA ID posample1.musicplayer))"; + System.out.println(); + System.out.println(str); + stmt.executeUpdate(str); + + str = "INSERT INTO view_purchases "+ + "VALUES (1002, XMLVALIDATE(XMLPARSE(document "+ + "'"+ + ""+ + "adidas"+ + "10"+ + "2"+ + "199.9"+ + ""+ + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"; + System.out.println(); + System.out.println(str); + stmt.executeUpdate(str); + + + System.out.println(); + System.out.println("SELECT * FROM musicplayer ORDER BY custid"); + System.out.println("--------------------------------------------"); + System.out.println(); + PreparedStatement pstmt = con.prepareStatement( + "SELECT * FROM musicplayer ORDER BY custid"); + ResultSet rs = pstmt.executeQuery(); + + int custid = 0; + String info = null; + + while (rs.next()) + { + custid = rs.getInt(1); + info= rs.getString(2); + + System.out.println(Data.format(custid , 10)+" "+ + Data.format(info,1024)); + } + + + System.out.println("SELECT * FROM boots ORDER BY custid"); + System.out.println("--------------------------------------------"); + System.out.println(); + + pstmt = con.prepareStatement("SELECT * FROM boots ORDER BY custid"); + rs = pstmt.executeQuery(); + + while (rs.next()) + { + custid = rs.getInt(1); + info= rs.getString(2); + + System.out.println(Data.format(custid , 10)+" "+ + Data.format(info,1024)); + } + + rs.close(); + + stmt.close(); + pstmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //partitionTablesBySchema + + //************************************************************************** + // 4. Show usage of IS VALIDATED and IS NOT VALIDATED predicates. + //************************************************************************** + + static void usageOfValidatedPredicates(Connection con) + { + try + { + System.out.println("-------------------------------------------"); + System.out.println("Show usage of IS VALIDATED predicate"); + System.out.println("-------------------------------------------"); + + System.out.println("Get customer addresses from customer table"+ + " for the customers who purchased boots or "+ + " musicplayers "); + System.out.println(); + + PreparedStatement pstmt = con.prepareStatement( + "SELECT custid, info "+ + "FROM customer C, view_purchases V "+ + "WHERE V.custid = C.Cid AND info IS VALIDATED ORDER BY custid"); + + System.out.println("SELECT custid, info "+ + "FROM customer C, view_purchases V "+ + "WHERE V.custid = C.Cid AND info IS VALIDATED"); + System.out.println(); + ResultSet rs = pstmt.executeQuery(); + + int custid = 0; + String info = null; + + while (rs.next()) + { + custid = rs.getInt(1); + info = rs.getString(2); + + System.out.println(Data.format(custid, 10)+" "+ + Data.format(info, 1024)); + } + + System.out.println("Show usage of IS NOT VALIDATED predicate"); + System.out.println("-------------------------------------------"); + System.out.println(); + + String str = "CREATE TABLE temp_table (custid int, xmldoc XML)"; + Statement stmt = con.createStatement(); + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + str = "INSERT INTO temp_table "+ + "VALUES(1003, "+ + "'"+ + ""+ + "Red Tape"+ + "6"+ + "2"+ + "1199.9"+ + ""+ + "')"; + + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + + str = "INSERT INTO temp_table "+ + "VALUES(1004, XMLVALIDATE(XMLPARSE(document "+ + "'"+ + ""+ + "Liberty"+ + "6"+ + "2"+ + "900.90"+ + ""+ + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + + str = "CREATE VIEW temp_table_details AS "+ + "(SELECT * FROM temp_table "+ + "WHERE xmldoc IS NOT VALIDATED)"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + pstmt = con.prepareStatement("SELECT * FROM temp_table_details"); + rs = pstmt.executeQuery(); + + while (rs.next()) + { + custid = rs.getInt(1); + info = rs.getString(2); + System.out.println(Data.format(custid, 10)+" "+ + Data.format(info, 1024)); + } + + rs.close(); + stmt.close(); + pstmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //usageOfValidatedPredicates + + //************************************************************************** + // 5. Shows insert statement failure when check constraint is violated. + //************************************************************************** + + static void checkConstraintViolation(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + String str = "INSERT INTO musicplayer "+ + "VALUES (1005, XMLVALIDATE(XMLPARSE(document "+ + "'"+ + ""+ + "Red Tape"+ + "6"+ + "2"+ + "1199.9"+ + ""+ + "') ACCORDING TO XMLSCHEMA ID posample1.boots))"; + stmt.executeUpdate(str); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + } + catch(Exception e) + {} + } //checkConstraintViolation + + //************************************************************************** + // 6. Show check constraint and view dependency on schema. + //************************************************************************** + + static void dependencyOnSchema(Connection con) + { + Statement stmt = null; + try + { + + System.out.println("Shows constraint and view dependency on schema"); + System.out.println("-----------------------------------------------"); + System.out.println(); + + stmt = con.createStatement(); + String str = "DROP XSROBJECT posample1.boots"; + + System.out.println("DROP XSROBJECT posample1.boots"); + System.out.println(); + stmt.executeUpdate(str); + + str = "INSERT INTO boots "+ + "VALUES (1006, "+ + "'"+ + ""+ + "Red Tape"+ + "6"+ + "2"+ + "1199.9"+ + ""+ + " ')"; + System.out.println(str); + System.out.println(); + System.out.println("Insert succeeds without any validation\n"); + stmt.executeUpdate(str); + + str = "INSERT INTO view_purchases "+ + "VALUES (1007, "+ + "'"+ + "philips"+ + " 1000 watts"+ + "2"+ + "5"+ + "4"+ + "1200.00"+ + "')"; + System.out.println(str); + System.out.println(); + System.out.println("Insert succeeds without any validation\n"); + stmt.executeUpdate(str); + + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + } + catch(Exception e) + {} + } //dependencyOnSchema + + //************************************************************************** + // Cleanup + //************************************************************************** + + static void cleanUp(Connection con) + { + Statement stmt = null; + + try + { + stmt = con.createStatement(); + + String str = "DROP XSROBJECT POSAMPLE1.MUSICPLAYER"; + stmt.executeUpdate(str); + + str = "DROP TABLE item"; + stmt.executeUpdate(str); + + str = "DROP TABLE musicplayer"; + stmt.executeUpdate(str); + + str = "DROP TABLE boots"; + stmt.executeUpdate(str); + + str = "DROP VIEW view_purchases"; + stmt.executeUpdate(str); + + str = "DROP VIEW temp_table_details"; + stmt.executeUpdate(str); + + str = "DROP TABLE temp_table"; + stmt.executeUpdate(str); + + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //cleanUp +} //XmlCheckConstraint class diff --git a/xml/java/jdbc/XmlConst.java b/xml/java/jdbc/XmlConst.java new file mode 100644 index 0000000..83139f4 --- /dev/null +++ b/xml/java/jdbc/XmlConst.java @@ -0,0 +1,467 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlConst.java +// +// SAMPLE: How to create UNIQUE index on XML columns +// +// SQL Statements USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// OUTPUT FILE: XmlConst.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +// +// NOTE: Primary key, unique constraint, or unique index are not supported +// for XML column in the Database Partitioning Feature available with +// DB2 Enterprise Server Edition for Linux, UNIX, and Windows. +// +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; + +class XmlConst +{ + public static void main(String argv[]) + { + Connection con=null; + + try + { + Db db = new Db(argv); + + System.out.println("THIS SAMPLE SHOWS HOW TO CREATE UNIQUE INDEX. \n"); + + // Connect to sample database + db.connect(); + + TbIndexUniqueConstraint1(db.con); + dropall(db.con); + TbIndexUniqueConstraint2(db.con); + dropall(db.con); + TbIndexVarcharConstraint(db.con); + dropall(db.con); + TbIndexVarcharConstraint1(db.con); + + // disconnect from sample database + db.disconnect(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } + + static void TbIndexUniqueConstraint1(Connection con) + { + Statement stmt = null; + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE JAVA 2 CLASS: \n" + + "statement \n" + + "To execute a query. "); + + stmt = con.createStatement(); + + //execute the query + + System.out.println(); + System.out.println( + "Execute Statement:" + + " CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"); + + String create = "CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"; + stmt.executeUpdate(create); + + System.out.println("create unique index on XML column \n"); + + System.out.println("CREATE UNIQUE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'" + + "AS SQL DOUBLE\n"); + + stmt = con.createStatement(); + stmt.executeUpdate("CREATE UNIQUE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'" + + "AS SQL DOUBLE "); + + System.out.println("Insert row1 into table \n"); + + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))\n"); + + stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))"); + + stmt = con.createStatement(); + System.out.println("Insert row2 into table \n"); + System.out.println("Unique violation error because of id=\"31201\""); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + " Finance" + + " '))\n"); + + stmt.executeUpdate( + "INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + " Finance" + + " '))"); + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + } + catch(Exception e) + {} + } + + static void TbIndexUniqueConstraint2(Connection con) + { + Statement stmt = null; + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE JAVA 2 CLASS: \n" + + "statement \n" + + "To execute a query. "); + + stmt = con.createStatement(); + + //execute the query + + System.out.println(); + System.out.println( + "Execute Statement:" + + " CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML)"); + + String create = "CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML)"; + stmt.executeUpdate(create); + + System.out.println("create unique index on XML column \n"); + System.out.println("CREATE UNIQUE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'" + + "AS SQL DOUBLE\n"); + stmt = con.createStatement(); + stmt.executeUpdate("CREATE UNIQUE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'" + + "AS SQL DOUBLE "); + + stmt = con.createStatement(); + System.out.println("Insert row3 into table \n"); + System.out.print("No index entry is inserted because \"ABCDE\""); + System.out.println("cannot be cast to the DOUBLE data type."); + System.out.println(); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse" + + " (document '" + + " Laura Brown" + + " Finance'))"); + + stmt.executeUpdate( + "INSERT INTO company values (1, 'doc1', xmlparse" + + " (document '" + + " Laura Brown" + + " Finance'))"); + + stmt = con.createStatement(); + System.out.println("Insert row4 into table \n"); + System.out.print("The insert succeeds because no index entry is inserted"); + System.out.println("since \"ABCDE\" cannot be cast to the DOUBLE data type."); + System.out.println(); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse "+ + " (document 'Laura Brown"+ + " Finance"+ + "'))\n"); + + stmt.executeUpdate( + "INSERT INTO company values (1, 'doc1', xmlparse "+ + " (document '" + + " Laura Brown " + + " Finance'))"); + + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + } + catch(Exception e) + {} + } + + static void TbIndexVarcharConstraint(Connection con) + { + Statement stmt = null; + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE JAVA 2 CLASS: \n" + + "statement \n" + + "To execute a query. "); + + stmt = con.createStatement(); + + //execute the query + + System.out.println(); + System.out.println( + "Execute Statement:" + + " CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML)"); + + String create = "CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"; + stmt.executeUpdate(create); + + System.out.println("create unique index on XML column \n"); + System.out.println("CREATE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'" + + "AS SQL VARCHAR(4)\n"); + stmt = con.createStatement(); + stmt.executeUpdate("CREATE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'" + + "AS SQL VARCHAR(4)"); + + System.out.println("Insert row5 into table \n"); + System.out.println("Insert statement succeeds because the length of \"312\" < 4"); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))\n"); + + stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))"); + + System.out.println("Insert row6 into table \n"); + System.out.println("Insert statement fails because the length of \"31202\" > 4."); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))\n"); + + stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))"); + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + } + catch(Exception e) + {} + } + + static void TbIndexVarcharConstraint1(Connection con) + { + Statement stmt = null; + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE JAVA 2 CLASS: \n" + + "statement \n" + + "To execute a query. "); + + stmt = con.createStatement(); + + //execute the query + + System.out.println(); + System.out.println( + "Execute Statement:" + + " CREATE TABLE COMPANY(ID int, DOCNAME VARCHAR(20), DOC XML)"); + + String create = "CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"; + stmt.executeUpdate(create); + + System.out.println("Insert row7 into table \n"); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))\n"); + + stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))"); + + System.out.println("Insert row8 into table \n"); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))\n"); + + stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO company values (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))"); + + System.out.println("create index with Varchar constraint fails " + + "because the length of \"31202\" > 4"); + System.out.println("CREATE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'" + + "AS SQL VARCHAR(4)\n"); + stmt = con.createStatement(); + stmt.executeUpdate("CREATE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'" + + "AS SQL VARCHAR(4)"); + + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } + + static void dropall(Connection con) + { + Statement stmt = null; + try + { + System.out.println("drop index and table \n"); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX\""); + stmt.executeUpdate("DROP TABLE \"COMPANY\""); + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } +} diff --git a/xml/java/jdbc/XmlDecomposition.java b/xml/java/jdbc/XmlDecomposition.java new file mode 100644 index 0000000..991576b --- /dev/null +++ b/xml/java/jdbc/XmlDecomposition.java @@ -0,0 +1,475 @@ +// ************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +// ************************************************************************* +// +// SAMPLE FILE NAME: XmlDecomposition.java +// +// PURPOSE: To demonstrate annotated XML schema decomposition +// +// USER SCENARIO: +// A bookstore has books for sale and the descriptive information about +// each book is stored as an XML document. The store owner needs to store +// these details in different relational tables with referential +// constraints for easy retreival of data. +// The Bookstore that has two types of customers, retail customers and +// corporate customers. Corporate customers do bulk purchases of books +// for their company libraries. The store has a DBA for maintaining +// the database, the store manager runs queries on different tables +// to view the book sales. The information about books returned by +// customers due to damage or due to exchange with some other book +// is stored as xml document in books_returned table. At the end of +// the day a batch process decomposes these XML documents to update +// the books available status with the latest information. The batch +// process uses the DECOMPOSE XML DOCUMENTS command to decompose +// binary or XML column data into relational tables. +// +// SOLUTION: +// The store manager must have an annotated schema based on which the XML data +// can be decomposed. Once a valid annotated schema for the instance document +// is ready, it needs to be registered with the XML schema repository with +// the decomposition option enabled. Also, the tables in which the data will be +// decomposed must exist before the schema is registered. The user can +// decompose the instance documents and store the data in the relational +// tables using annotated XML Decomposition. +// +// +// PREREQUISITE: +// The instance documents and the annotated schema must exist in the same +// directory as the sample. +// Copy bookdetails.xsd, booksreturned.xsd, bookdetails.xml, +// booksreturned.del, booksreturned1.xml, booksreturned2.xml, booksreturned3.xml, +// setupfordecomposition.db2 and cleanupfordecomposition.db2 from directory +// /sqllib/samples/xml/data in UNIX and +// \sqllib\samples\xml\data in Windows to the working directory. +// +// EXECUTION: i) db2 -tvf setupfordecomposition.db2 (setup script +// to create the required tables and populate them) +// ii) javac XmlDecomposition.java (compile the sample) +// java XmlDecomposition (run the sample) +// iii) db2 -tvf cleanupfordecomposition.db2 (clean up +// script to drop all the objects created) +// +// INPUTS: NONE +// +// OUTPUTS: Decomposition of XML documents according to the dependencies +// specified in the annotated XML schema. +// +// OUTPUT FILE: XmlDecomposition.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// REGISTER XMLSCHEMA +// COMPLETE XMLSCHEMA +// SELECT +// CALL +// DECOMPOSE XML DOCUMENT +// DECOMPOSE XML DOUMENTS IN +// +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** +// +// SAMPLE DESCRIPTION +// +// ************************************************************************* +// 1. Register the annotated XML schemas. +// 2. Decompose a single XML document using the registered XML schema. +// 3. Decompose XML documents using the registered XML schema from +// 3.1. An XML column. +// 3.2. A BLOB column. +// 4. Decompose XML documents from an XML column resulted by +// 4.1. Join operation +// 4.2. Union operation +// ************************************************************************* + +import java.lang.*; +import java.sql.*; +import java.io.*; + +class XmlDecomposition +{ + + public static String relSchema=new String("XDB"); + public static String schemaName=new String("BOOKDETAILS");; + public static String schemaLocation= new String("http://book.com/bookdetails.xsd"); + public static String primaryDocument= new String("bookdetails.xsd"); + + public static String schemaName1=new String("BOOKSRETURNED");; + public static String schemaLocation1= new String("http://book.com/booksreturned.xsd"); + public static String primaryDocument1= new String("booksreturned.xsd"); + + public static String query = " "; + + public static void main(String argv[]) + { + try + { + + Db db = new Db(argv); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO " + "\n 1. DECOMPOSE A SINGLE XML DOCUMENT"); + System.out.println(" 2. DECOMPOSE XML DATA FROM AN XML COLOUMN "); + System.out.println(" 3. DECOMPOSE XML DATA FROM A BLOB COLOUMN "); + System.out.println(" 4. DECOMPOSE XML DATA FROM AN XML COLOUMN RESULT OF JOIN OPERATION"); + System.out.println(" 5. DECOMPOSE XML DATA FROM AN XML COLOUMN RESULT OF UNION OPERATION"); + + // connect to the 'sample' database + db.connect(); + + // register the XML Schemas + registerXmlSchema(db.con,schemaName,schemaLocation,primaryDocument); + registerXmlSchema(db.con,schemaName1,schemaLocation1,primaryDocument1); + + System.out.println("/*************************************************************************"); + System.out.println(" Decompose a single XML document using the registered XML schema."); + System.out.println("*************************************************************************/"); + + singleXMLDecompose(db.con); + + System.out.println("/*************************************************************************"); + System.out.println(" Decompose XML documents from an XML column."); + System.out.println("*************************************************************************/"); + + query = "SELECT customerID, booksreturned FROM xdb.books_returned"; + bulkXmlDecompose(db.con, query); + + System.out.println("/************************************************************************* "); + System.out.println(" Decompose XML documents from a BLOB column."); + System.out.println("*************************************************************************/ "); + + query = "SELECT supplierID, booksinfo from xdb.books_received_BLOB"; + bulkXmlDecompose(db.con, query); + + System.out.println("/*************************************************************************"); + System.out.println(" Decompose XML documents from an XML column resulted by Join operation."); + System.out.println("*************************************************************************/"); + query = "SELECT id, data FROM(SELECT br.customerID as id, br.booksreturned AS info " + + "FROM xdb.books_returned as br,xdb.books_received AS brd " + + "WHERE XMLEXISTS('$bi/books/book[@isbn] = $bid/books/book[@isbn]' " + + "PASSING br.booksreturned as \"bi\", " + + "brd.booksinfo as \"bid\")) AS temp(id,data)"; + bulkXmlDecompose(db.con, query); + + + System.out.println("/*************************************************************************"); + System.out.println(" Decompose XML documents from an XML column resulted by union operation."); + System.out.println("*************************************************************************/"); + + query = "SELECT id, data FROM(SELECT customerID as cid, booksreturned AS info " + + "FROM xdb.books_returned " + + "WHERE XMLEXISTS('$bk/books/book[author=\"Carl\"]' " + + "PASSING booksreturned AS \"bk\") "+ + "UNION ALL " + + "SELECT supplierID as sid, booksinfo AS books " + + "FROM xdb.books_received " + + "WHERE XMLEXISTS('$br/books/book[author=\"Carl\"]' " + + "PASSING booksinfo AS \"br\")) AS temp(id,data) "; + bulkXmlDecompose(db.con, query); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + + + // Method to register an XML Schema + static void registerXmlSchema(Connection con,String schName,String schLoc,String schDoc) + { + try + { + int shred = 1; + // register XML Schema + System.out.println("\nRegistering Schema "+ relSchema + "." +schName +"..."); + CallableStatement callStmt = con.prepareCall("CALL SYSPROC.XSR_REGISTER(?,?,?,?,NULL)"); + File xsdFile = new File(schDoc); + FileInputStream xsdData = new FileInputStream(xsdFile); + callStmt.setString(1, relSchema); + callStmt.setString(2, schName); + callStmt.setString(3, schLoc); + callStmt.setBinaryStream(4, xsdData, (int)xsdFile.length() ); + callStmt.execute(); + xsdData.close(); + + // complete the registration + System.out.println("Completing XML Schema registration..."); + callStmt=con.prepareCall("CALL SYSPROC.XSR_COMPLETE(?,?,NULL,?)"); + callStmt.setString(1, relSchema); + callStmt.setString(2, schName); + callStmt.setInt(3, shred); + callStmt.execute(); + System.out.println("Schema "+ relSchema + "." +schName +" registered successfully \n\n"); + callStmt.close(); + + // Check the status of the XSR object registered. + PreparedStatement pstmt = con.prepareStatement( + "SELECT status, decomposition, decomposition_version " + + "FROM SYSIBM.SYSXSROBJECTS WHERE XSROBJECTNAME = ? "); + pstmt.setString(1,schName); + ResultSet rs = pstmt.executeQuery(); + while(rs.next()) + { + String Status = rs.getString(1); + String Decomposition = rs.getString(2); + String Decomposition_version = rs.getString(3); + + System.out.println("\nStatus : " + Status + "\n" + + "Decomposition : " + Decomposition + "\n" + + "Version : " + Decomposition_version); + } + rs.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(IOException ioe) + { + System.out.println("Error opening file " + schDoc); + } + }// registerXmlSchema + + static void singleXMLDecompose(Connection con) + { + try + { + String xmlfilename = "bookdetails.xml"; + int shred = 1; + + // Decompose the XML document by calling the SYSPROC.XDBDECOMPXML + CallableStatement callStmt = con.prepareCall("CALL SYSPROC.XDBDECOMPXML(?,?,?,?,?, NULL, NULL, NULL)"); + File xmlfile = new File(xmlfilename); + FileInputStream xmlfileis = new FileInputStream(xmlfile); + callStmt.setString(1, relSchema ); + callStmt.setString(2, schemaName ); + callStmt.setBinaryStream(3, xmlfileis, (int)xmlfile.length() ); + callStmt.setString(4, schemaName ); + callStmt.setInt(5, shred); + callStmt.execute(); + xmlfileis.close(); + callStmt.close(); + System.out.println("**** CALL SYSPROC.XDBDECOMPXML SUCCESSFULLY"); + + // Read Data from the tables, where the data is stored after decomposition. + SelectFromAllTables(con); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(IOException ioe) + { + System.out.println("Error opening file "); + } + + } + + static void bulkXmlDecompose(Connection con, String query) + { + try + { + System.out.print(query); + // Decompose the XML document by calling the SYSPROC.XDBDECOMPXML + CallableStatement callStmt = + con.prepareCall("CALL SYSPROC.XDB_DECOMP_XML_FROM_QUERY('XDB','BOOKSRETURNED',?, 1, 0, 0, NULL, NULL, 1, ?, ?, ?)"); + System.out.println("Calling SYSPROC.XDB_DECOMP_XML_FROM_QUERY...."); + // register the output parameter + callStmt.setString(1, query); + callStmt.registerOutParameter(2, Types.INTEGER); + callStmt.registerOutParameter(3, Types.INTEGER); + callStmt.registerOutParameter(4, Types.BLOB); + callStmt.execute(); + ResultSet rs = callStmt.getResultSet(); + System.out.println("\n CALLED SYSPROC.XDB_DECOMP_XML_FROM_QUERY SUCCESSFULLY"); + int totaldocs = callStmt.getInt(2); + System.out.println("\nTotal documents to be decomposed:" + totaldocs); + int numdocsdecomposed = callStmt.getInt(3); + System.out.println("\nNumber of documents decomposed:" + numdocsdecomposed); + String err = callStmt.getObject(4).toString(); + System.out.println("\n \n Error report :" + err); + //callStmt.close(); + + // Read Data from the tables, where the data is stored after decomposition. + SelectFromBooksAvail(con); + //rs.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } + + + static void SelectFromBooksAvail(Connection con) + { + try + { + String isbn = " "; + int authid = 0; + String authname = " "; + String book_title = " "; + float price = 0; + int no_of_copies = 0; + + Statement stmt = con.createStatement(); + ResultSet rs1 = stmt.executeQuery("SELECT isbn, book_title, authid, authname, price, no_of_copies FROM XDB.BOOKS_AVAIL"); + System.out.println("\n SELECT isbn, book_title, authid, authname, price, no_of_copies FROM XDB.BOOKS_AVAIL"); + while(rs1.next()) + { + isbn = rs1.getString(1); + book_title = rs1.getString(2); + authid = rs1.getInt(3); + authname = rs1.getString(4); + price = rs1.getFloat(5); + no_of_copies = rs1.getInt(6); + + System.out.println("\nISBN : " + isbn + + "\nBook Title : " + book_title + + "\nAuthor ID : " + authid + + "\nAuthor : " + authname + + "\nPrice : " + price + + "\nNo of copies : " + no_of_copies); + } + // rs1.close(); + // stmt.close(); + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate("DELETE FROM XDB.BOOKS_AVAIL"); + // stmt1.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } //SelectFromBooksAvail + + static void SelectFromAllTables(Connection con) + { + try + { + String isbn = " "; + int chptnum = 0; + String chpttittle = " "; + String chptcontent = " "; + int authid = 0; + String authname = " "; + String book_title = " "; + String status = " "; + String decompose = " "; + String decomp_version = " "; + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT isbn, chptnum, chpttitle, chptcontent FROM XDB.BOOK_CONTENTS"); + System.out.println("\n SELECT isbn, chptnum, chpttitle, chptcontent FROM XDB.BOOK_CONTENTS"); + while (rs.next()) + { + isbn = rs.getString(1); + chptnum = rs.getInt(2); + chpttittle = rs.getString(3); + chptcontent = rs.getString(4); + + System.out.println("\nISBN : " + isbn + "\n" + + "Chapter Number : " + chptnum + "\n" + + "Chapter Title : " + chpttittle + "\n" + + "Chapter Content : " + chptcontent); + } + + // Select data from the ADMIN.BOOK_AUTHOR TABLE. + rs = stmt.executeQuery("SELECT authid, authname, isbn, book_title FROM ADMIN.BOOK_AUTHOR"); + System.out.println("\n SELECT authid, authname, isbn, book_title FROM ADMIN.BOOK_AUTHOR"); + while(rs.next()) + { + authid = rs.getInt(1); + authname = rs.getString(2); + isbn = rs.getString(3); + book_title = rs.getString(4); + + System.out.println("\nAuthor ID : " + authid + "\n" + + "Author Name : " + authname + "\n" + + "ISBN : " + isbn + "\n" + + "Book Title : " + book_title); + } + rs.close(); + + // Select data from the XDB.BOOKS_AVAIL TABLE. + SelectFromBooksAvail(con); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } //SelectFromAllTables + + +} //XmlDecomposition Class + + diff --git a/xml/java/jdbc/XmlIndex.java b/xml/java/jdbc/XmlIndex.java new file mode 100644 index 0000000..19ea977 --- /dev/null +++ b/xml/java/jdbc/XmlIndex.java @@ -0,0 +1,643 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlIndex.java +// +// SAMPLE: How to create an index on an XML column in different ways +// +// SQL Statements USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// +// OUTPUT FILE: XmlIndex.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; + +class XmlIndex +{ + public static void main(String argv[]) + { + int rc = 0; + String url = "jdbc:db2:sample"; + Connection con = null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + System.out.println(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + + System.out.println("THIS SAMPLE SHOWS HOW TO CREATE INDEX ON "+ + "XML COLUMNS IN DIFFERENT WAYS"); + + //Different ways to create an index on XML columns + createandInsertIntoTable(con); + createIndex(con); + createIndexwithSelf(con); + createIndexonTextnode(con); + createIndexwith2Paths(con); + createIndexwithNamespace(con); + createIndexwith2Datatypes(con); + createIndexuseAnding(con); + createIndexuseAndingOrOring(con); + createIndexwithDateDatatype(con); + createIndexOnCommentNode(con); + dropall(con); + + } // main + + // This function creates a table and inserts rows having + // XML data + static void createandInsertIntoTable(Connection con) + { + Statement stmt = null; + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE JAVA 2 CLASS: \n" + + "statement \n" + + "To execute a query. "); + + stmt = con.createStatement(); + + //execute the query + + System.out.println(); + System.out.println( + "Execute Statement:" + + " CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"); + + String create = "CREATE TABLE company(id INT,"+ + "docname VARCHAR(20),"+ + "doc XML)"; + stmt.executeUpdate(create); + + System.out.println(); + System.out.println("Insert row1 into table \n"); + stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO company VALUES (1, 'doc1', xmlparse " + + "(document ' " + + " Laura Brown" + + "Finance" + + "'))"); + + stmt = con.createStatement(); + System.out.println("Insert row2 into table \n"); + stmt.executeUpdate( + " INSERT INTO company VALUES (2,'doc2',xmlparse (" + + "document ' " + + "ChrisMurphy " + + "Marketing "+ + "NicoleMurphy " + + "Sales '))" ); + } + catch(Exception e) + { + System.out.println(e); + } + } // createandInsertIntoTable + + // This function creates an index and shows how we can use XQUERY on + // the index created + static void createIndex(Connection con) + { + try + { + System.out.println("create index on attribute \n"); + Statement stmt = con.createStatement(); + + System.out.println("CREATE INDEX empindex1 ON company(doc) " + + "GENERATE KEY USING XMLPATTERN '/company/emp/@*'"+ + " AS SQL VARCHAR(25)\n "); + stmt.executeUpdate( + "CREATE INDEX empindex1 ON company(doc) GENERATE KEY "+ + "USING XMLPATTERN '/company/emp/@*' AS SQL VARCHAR(25) "); + + ResultSet rs = stmt.executeQuery("XQUERY for $i in db2-fn:" + + "xmlcolumn('COMPANY.DOC') /company/"+ + "emp[@id = '42366'] return $i/name "); + + System.out.println("-----------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data = (com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + System.out.println(); + } + System.out.println("-----------------------------------------------"); + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + System.out.println(e); + } + } // createIndex + + // This function creates an index with self or descendent forward + // axis and shows how we can use XQUERY on the index + static void createIndexwithSelf(Connection con) + { + try + { + System.out.println("create index with self or " + + "descendent forward axis \n"); + Statement stmt = con.createStatement(); + + System.out.println("CREATE INDEX empindex2 ON company(doc) "+ + "GENERATE KEY USING XMLPATTERN '//@salary' "+ + "AS SQL DOUBLE\n"); + + stmt.executeUpdate( + "CREATE INDEX empindex2 ON company(doc) GENERATE KEY "+ + "USING XMLPATTERN '//@salary' AS SQL DOUBLE "); + ResultSet rs = stmt.executeQuery("XQUERY for $i in db2-fn:xmlcolumn"+ + "('COMPANY.DOC') /company/emp[@salary "+ + "> 35000] return {$i/@salary}"+ + " "); + + System.out.println("-----------------------------------------------"); + String name = null; + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data = (com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + System.out.println(); + } + + System.out.println("-----------------------------------------------"); + rs.close(); + stmt.close(); + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexwithSelf + + // This function creates an index on a text mode and shows how to use + // XQUERY on the index + static void createIndexonTextnode(Connection con) + { + try + { + System.out.println("create index on a text mode\n"); + Statement stmt = con.createStatement(); + System.out.println("CREATE INDEX empindex3 ON company(doc) GENERATE"+ + " KEY USING XMLPATTERN '/company/emp/dept/text()'"+ + " AS SQL VARCHAR(30)\n "); + stmt.executeUpdate( + "CREATE INDEX empindex3 ON company(doc) GENERATE KEY USING"+ + " XMLPATTERN '/company/emp/dept/text()' AS SQL VARCHAR(30) "); + + ResultSet rs = stmt.executeQuery("XQUERY for $i in db2-fn:xmlcolumn"+ + "('COMPANY.DOC')/ company/emp[dept"+ + "/text() = 'Finance' or dept/text()"+ + " = 'Marketing'] return $i/name" ); + + System.out.println("-----------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data = (com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + System.out.println(); + } + System.out.println("-----------------------------------------------"); + rs.close(); + stmt.close(); + + } + catch (Exception e) + { + System.out.println(e); + } + } //createIndexonTextnode + + // This function creates an index when 2 paths are qualified by + // an XML and also shows how to use XQUERY on the index + static void createIndexwith2Paths(Connection con) + { + try + { + System.out.println("create index when 2 paths are qualified "+ + "by an XML \n"); + Statement stmt = con.createStatement(); + + System.out.println("CREATE INDEX empindex4 ON company(doc) "+ + "GENERATE KEY USING XMLPATTERN '//@id' AS "+ + "SQL VARCHAR(25)\n"); + + stmt.executeUpdate( + "CREATE INDEX empindex4 ON company(doc) GENERATE KEY USING"+ + " XMLPATTERN '//@id' AS SQL VARCHAR(25)"); + ResultSet rs = stmt.executeQuery("XQUERY for $i in db2-fn:xmlcolumn" + + "('COMPANY.DOC') /company/emp[@id = "+ + "'31201'] return $i/name"); + System.out.println("-----------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data = (com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + System.out.println(); + } + System.out.println("-----------------------------------------------"); + + System.out.println("XQUERY for $j in db2-fn:xmlcolumn('COMPANY.DOC')"+ + "/company/emp[dept/@id = 'K55'] return $j/name"); + + ResultSet rs1 = stmt.executeQuery("XQUERY for $j in db2-fn:xmlcolumn"+ + "('COMPANY.DOC') /company/emp"+ + "[dept/@id = 'K55'] return $j/name"); + + System.out.println("-----------------------------------------------"); + while (rs1.next()) + { + com.ibm.db2.jcc.DB2Xml data = (com.ibm.db2.jcc.DB2Xml) rs1.getObject(1); + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + System.out.println(); + } + System.out.println("-----------------------------------------------"); + rs.close(); + rs1.close(); + stmt.close(); + + } + catch (Exception e) + { + System.out.println(e); + } + } // createIndexwith2Paths + + // This function creates an index with namespace + static void createIndexwithNamespace(Connection con) + { + try + { + System.out.println("create index with namespace \n"); + Statement stmt = con.createStatement(); + + System.out.println("CREATE INDEX empindex5 ON company(doc) GENERATE "+ + "KEY USING XMLPATTERN 'declare default element "+ + "namespace \"http://www.mycompany.com/\";declare "+ + "namespace m = \"http://www.mycompanyname.com/\";"+ + "/company/emp/ @m:id' AS SQL VARCHAR(30)\n"); + + stmt.executeUpdate( + "CREATE INDEX empindex5 ON company(doc) GENERATE KEY USING"+ + " XMLPATTERN 'declare default element namespace " + + "\"http://www.mycompany.com/\";declare namespace " + + "m = \"http://www.mycompanyname.com/\";/company/emp/ "+ + "@m:id' AS SQL VARCHAR(30)"); + + stmt.close(); + } + catch (Exception e) + { + System.out.println(e); + } + } // createIndexwithNamespace + + // This function creates an index with two different data types + static void createIndexwith2Datatypes(Connection con) + { + try + { + System.out.println("create indexes with same XMLPATTERN but "+ + "with different data types \n"); + Statement stmt = con.createStatement(); + + System.out.println("CREATE INDEX empindex6 ON company(doc) GENERATE "+ + "KEY USING XMLPATTERN '/company/emp/@id' AS SQL "+ + "VARCHAR(10)\n"); + + stmt.executeUpdate( + "CREATE INDEX empindex6 ON company(doc) GENERATE KEY "+ + "USING XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(10)"); + + System.out.println("CREATE INDEX empindex7 ON company(doc) GENERATE "+ + " KEY USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE\n"); + + stmt.executeUpdate( + "CREATE INDEX empindex7 ON company(doc) GENERATE KEY "+ + " USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE"); + + stmt.close(); + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexwith2Datatypes + + // This function creates an index using joins and shows how + // to use XQUERY on the index created + static void createIndexuseAnding(Connection con) + { + try + { + System.out.println("create index using joins (Anding) \n"); + Statement stmt = con.createStatement(); + + System.out.println("CREATE INDEX empindex8 ON company(doc) GENERATE "+ + "KEY USING XMLPATTERN '/company/emp/name/last' "+ + "AS SQL VARCHAR(100)\n"); + + stmt.executeUpdate( + "CREATE INDEX empindex8 ON company(doc) GENERATE KEY USING "+ + " XMLPATTERN '/company/emp/name/last' AS SQL VARCHAR(100)"); + + System.out.println("CREATE INDEX deptindex on company(doc) GENERATE "+ + "KEY USING XMLPATTERN '/company/emp/dept/text()' "+ + "AS SQL VARCHAR(30)\n"); + + stmt.executeUpdate( + "CREATE INDEX deptindex on company(doc) GENERATE KEY USING "+ + " XMLPATTERN '/company/emp/dept/text()' AS SQL VARCHAR(30)"); + + System.out.println("XQUERY for $i in db2-fn:xmlcolumn('COMPANY.DOC')"+ + "/company/ emp[name/last = 'Murphy' and dept/text()"+ + " = 'Sales']return $i/name/last"); + + ResultSet rs = stmt.executeQuery("XQUERY for $i in db2-fn:xmlcolumn"+ + "('COMPANY.DOC')/company/ emp[name"+ + "/last = 'Murphy' and dept/text() ="+ + " 'Sales']return $i/name/last"); + + System.out.println("----------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data = (com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + System.out.println(); + } + System.out.println("----------------------------------------------"); + rs.close(); + stmt.close(); + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexuseAnding + + // This function creates an index using joins (ANDing or ORing) + // and shows how to use XQUERY on the index created + static void createIndexuseAndingOrOring(Connection con) + { + try + { + System.out.println("create index using joins (Anding or Oring ) \n"); + Statement stmt = con.createStatement(); + + System.out.println("CREATE INDEX empindex9 ON company(doc) "+ + "GENERATE KEY USING XMLPATTERN '/company"+ + "/emp/@salary' AS SQL DOUBLE\n"); + stmt.executeUpdate( + "CREATE INDEX empindex9 ON company(doc) GENERATE KEY "+ + "USING XMLPATTERN '/company/emp/@salary' AS SQL DOUBLE"); + + System.out.println("CREATE INDEX empindex10 ON company(doc) GENERATE"+ + " KEY USING XMLPATTERN '/company/emp/dept' AS "+ + " SQL VARCHAR(25)\n"); + stmt.executeUpdate( + "CREATE INDEX empindex10 ON company(doc) GENERATE KEY "+ + "USING XMLPATTERN '/company/emp/dept' AS SQL VARCHAR(25)"); + + System.out.println("CREATE INDEX empindex11 ON company(doc) GENERATE "+ + "KEY USING XMLPATTERN '/company/emp/name/last' "+ + "AS SQL VARCHAR(25)\n"); + stmt.executeUpdate( + "CREATE INDEX empindex11 ON company(doc) GENERATE KEY "+ + "USING XMLPATTERN '/company/emp/name/last' AS SQL "+ + "VARCHAR(25)"); + + ResultSet rs = stmt.executeQuery("XQUERY for $i in db2-fn:xmlcolumn"+ + "('COMPANY.DOC')/company/emp [@salary"+ + " > 50000 and dept = 'Finance']/name"+ + "[last = 'Brown'] return $i/last"); + + System.out.println("----------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data = (com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + System.out.println(); + } + System.out.println("----------------------------------------------"); + rs.close(); + stmt.close(); + + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexuseAndingOrOring + + // This function creates an index with Date Data type and shows how + // how to use an XQUERY on the index created + static void createIndexwithDateDatatype(Connection con) + { + try + { + System.out.println("create index with Date Data type \n"); + Statement stmt = con.createStatement(); + + System.out.println("CREATE INDEX empindex12 ON company(doc) GENERATE"+ + "KEY USING XMLPATTERN '/company/emp/@DOB' as "+ + "SQL DATE\n"); + stmt.executeUpdate( + "CREATE INDEX empindex12 ON company(doc) GENERATE KEY "+ + "USING XMLPATTERN '/company/emp/@DOB' as SQL DATE"); + ResultSet rs = stmt.executeQuery("XQUERY for $i in db2-fn:xmlcolumn"+ + "('COMPANY.DOC') /company/emp[@DOB < "+ + "'11-11-78'] return $i/name"); + + System.out.println("----------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data = (com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + System.out.println(); + } + System.out.println("----------------------------------------------"); + rs.close(); + stmt.close(); + + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexwithDateDatatype + + // This function creates an index on the comment node and shows + // how to use XQUERY on the index created + static void createIndexOnCommentNode(Connection con) + { + try + { + System.out.println("create index on comment node\n"); + Statement stmt = con.createStatement(); + + System.out.println("CREATE INDEX empindex13 ON company(doc) GENERATE"+ + "KEY USING XMLPATTERN '/company//comment() AS"+ + " SQL VARCHAR HASHED"); + + stmt.executeUpdate("CREATE INDEX empindex13 ON company(doc) GENERATE"+ + " KEY USING XMLPATTERN '/company//comment()' AS"+ + " SQL VARCHAR HASHED"); + + ResultSet rs = stmt.executeQuery("XQUERY for $i in db2-fn:xmlcolumn("+ + "'COMPANY.DOC') /company/emp[comment"+ + "() = ' good ']return $i/name"); + + System.out.println("----------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data = (com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + System.out.println(); + } + System.out.println("----------------------------------------------"); + rs.close(); + stmt.close(); + } + catch (Exception e) + { + System.out.println(e); + } + } // createIndexOnCommentNode + + // This function does all clean up work. It drops all the indexes + // created and drops the table created + static void dropall(Connection con) + { + try + { + Statement stmt = null; + + System.out.println("drop all indexes and table\n"); + System.out.println("-----------------------------\n"); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX1\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX2\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX3\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX4\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX5\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX6\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX7\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX8\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX9\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX10\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX11\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX12\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"EMPINDEX13\""); + stmt = con.createStatement(); + stmt.executeUpdate("DROP INDEX \"DEPTINDEX\""); + + + System.out.println("drop table \n"); + stmt = con.createStatement(); + String drop = "DROP TABLE \"COMPANY\""; + stmt.executeUpdate(drop); + } + catch (Exception e) + { + System.out.println(e); + } + } // dropall +} diff --git a/xml/java/jdbc/XmlInsert.java b/xml/java/jdbc/XmlInsert.java new file mode 100644 index 0000000..4e3c244 --- /dev/null +++ b/xml/java/jdbc/XmlInsert.java @@ -0,0 +1,906 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlInsert.java +// +// SAMPLE: How to insert rows having XML data into a table. +// +// SQL Statements USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// PREREQUISITE : copy the files cust1021.xml, cust1022.xml and +// cust1023.xml to working directory before running the +// sample. These files can be found in xml/data +// directory. +// OUTPUT FILE: XmlInsert.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.util.*; +import java.io.*; + + +class XmlInsert +{ + public static void main(String argv[]) + { + Connection con = null; + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO INSERT XML TABLE DATA."); + + // connect to the 'sample' database + db.connect(); + + preRequisites(db.con); + mostSimpleInsert(db.con); + InsertFromAnotherXmlColumn(db.con); + InsertFromAnotherStringColumn(db.con); + InsertwhereSourceisXmlFunction(db.con); + InsertwhereSourceisBlob(db.con); + InsertwhereSourceisClob(db.con); + InsertBlobDataWithImplicitParsing(db.con); + InsertFromStringNotWellFormedXML(db.con); + InsertwhereSourceisTypecastToXML(db.con); + InsertwithValidationSourceisVarchar(db.con); + ValidateXMLDocument(db.con); + DeleteofRowwithXmlData(db.con); + + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // main + + static void mostSimpleInsert(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM A SIMPLE INSERT."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1006); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1006,XMLPARSE(document 'divya'" + + " preserve whitespace))\n" + + "\n"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO customer(cid,info) " + + "VALUES(1006,XMLPARSE(document '" + + "divya' preserve whitespace))"); + + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1006); + + // rs.close(); + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // mostSimpleInsert + + static void InsertFromAnotherXmlColumn(Connection con) + { + try + { + System.out.println(); + System.out.println( + "---------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS FROM ANOTHER XML COLUMN."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1007); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " SELECT ocid,information FROM oldcustomer "+ + "p WHERE p.ocid=1007\n" + + "\n"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO customer(cid,info)" + + "SELECT ocid,information " + + "FROM oldcustomer p " + + "WHERE p.ocid=1007"); + + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1007); + + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // InsertFromAnotherXmlColumn + + static void InsertFromAnotherStringColumn(Connection con) + { + try + { + System.out.println(); + System.out.println( + "---------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS FROM " + + "ANOTHER STRING COLUMN."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " SELECT ocid,XMLPARSE(document addr preserve " + + " whitespace) FROM oldcustomer p " + + " WHERE p.ocid=1008\n" + + "\n"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO customer(cid,info) " + + "SELECT ocid,XMLPARSE(document addr preserve whitespace) " + + "FROM oldcustomer p " + + "WHERE p.ocid=1008"); + + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // InsertFromAnotherStringColumn + + static void InsertwithValidationSourceisVarchar(Connection con) + { + try + { + System.out.println(); + System.out.println( + "--------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WITH VALIDATION WHERE" + + " SOURCE IS TYPED OF VARCHAR."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1009); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " SELECT ocid,XMLVALIDATE(XMLPARSE(document "+ + " addr preserve whitespace)according to " + + " XMLSCHEMA id customer) " + + " FROM oldcustomer p " + + " WHERE p.ocid=1009\n" + + "\n"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO customer(cid,info) " + + "SELECT ocid,XMLVALIDATE(XMLPARSE(document addr "+ + "preserve whitespace)according to " + + "XMLSCHEMA ID CUSTOMER) " + + "FROM oldcustomer p " + + "WHERE p.ocid=1009"); + + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1009); + + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // InsertwithValidationSourceisVarchar + + static void InsertwhereSourceisXmlFunction(Connection con) + { + try + { + System.out.println(); + System.out.println( + "--------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS A XML FUNCTION."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1010); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " SELECT ocid,XMLPARSE(document " + + " XMLSERIALIZE(content " + + " XMLELEMENT(NAME\"oldCustomer\", " + + " XMLATTRIBUTES(s.ocid,s.firstname||' '||" + + " s.lastname AS \"name\")) " + + " as varchar(200)) strip whitespace) " + + " FROM oldcustomer s " + + " WHERE s.ocid=1010\n" + + "\n"); + + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO customer(cid,info) " + + "SELECT ocid,XMLPARSE(document XMLSERIALIZE(content " + + "XMLELEMENT(NAME\"oldCustomer\",XMLATTRIBUTES" + + "(s.ocid,s.firstname||' '||s.lastname AS \"name\")) " + + "as varchar(200)) strip whitespace) " + + "FROM oldcustomer s " + + "WHERE s.ocid=1010"); + + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1010); + + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // InsertwhereSourceisXmlFunction + + static void InsertwhereSourceisTypecastToXML(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS TYPECAST TO XML."); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1031,XMLCAST(? AS XML))" + + "\n"); + + PreparedStatement pstmt = con.prepareStatement( + "INSERT INTO customer(cid,info) " + + "VALUES(1031,XMLCAST(XMLPARSE(document '
56 hillview"+ + "kolarkarnataka
"+ + "
' preserve whitespace) as XML))"); + pstmt.execute(); + + //display the content of the 'customer' table + CustomerTbContentDisplay(con,1031); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } //InsertwhereSourceisTypecastToXML + + static void ValidateXMLDocument(Connection con) + { + try + { + + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + " TO PERFORM AN INSERT WITH VALIDATION WHEN " + + " DOCUMENT IS NOT AS PER SCHEMA"); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1012); + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES (1012, XMLVALIDATE(XMLPARSE(document '
12 gandhimarg"+ + " belgaumkarnataka"+ + "
' preserve whitespace))"+ + " according to XMLSCHEMA ID customer) \n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "INSERT INTO customer(cid,info) "+ + "VALUES (1012, XMLVALIDATE(XMLPARSE(document '12 gandhimarg" + + " belgaumkarnataka"+ + " ' preserve whitespace ) according to XMLSCHEMA ID"+ + " CUSTOMER ))"); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con, 1012); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + //try {con.rollback(); } + //catch (Exception e) {} + } + catch(Exception e) + {} + } //ValidateXMLDocument + + static void InsertwhereSourceisBlob(Connection con) + { + try + { + String xsdData = new String(); + xsdData=returnFileValues("cust1021.xml"); + byte[] byteArray=xsdData.getBytes(); + // Create a BLOB object + java.sql.Blob blobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(byteArray); + + System.out.println(); + System.out.println( + "--------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS A BLOB VARIABLE."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1021); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1021,XMLPARSE(document " + + " cast(? as Blob) strip whitespace))\n" + + "\n"); + + PreparedStatement pstmt = con.prepareStatement( + "INSERT INTO customer(cid,info) " + + "VALUES(1021,XMLPARSE(document cast(? as Blob) strip whitespace))"); + + System.out.println(); + System.out.println(" Set parameter value: parameter 1 = " + "blobData" ); + + pstmt.setBlob(1, blobData); + + System.out.println(); + System.out.println(" Execute prepared statement"); + pstmt.execute(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1021); + + pstmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // InsertwhereSourceisBlob + + static void InsertBlobDataWithImplicitParsing(Connection con) + { + try + { + String xsdData = new String(); + xsdData=returnFileValues("cust1022.xml"); + byte[] byteArray=xsdData.getBytes(); + // Create a BLOB object + java.sql.Blob blobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(byteArray); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS A BLOB VARIABLE" + + " WITH IMPLICIT PARSING" ); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1022); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1022, " + + " cast(? as Blob) strip whitespace)\n" + + "\n"); + + PreparedStatement pstmt = con.prepareStatement( + "INSERT INTO customer(cid,info) " + + "VALUES(1022, cast(? as Blob))"); + pstmt.setBlob(1, blobData); + pstmt.execute(); + + + // display the content of the 'customer' table + CustomerTbContentDisplay(con, 1022); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } //InsertBlobDataWithImplicitParsing + + static void InsertwhereSourceisClob(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + String xsdData = new String(); + xsdData=returnFileValues("cust1023.xml"); + + // Create a CLOB Object + java.sql.Clob clobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createClob(xsdData); + + System.out.println(); + System.out.println( + "----------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS A CLOB VARIABLE."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1023); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1023,XMLPARSE(document " + + " cast(? as Clob) strip whitespace))\n" + + "\n"); + + + PreparedStatement pstmt = con.prepareStatement( + "INSERT INTO customer(cid,info)" + + "VALUES(1023,XMLPARSE(document cast(? as Clob) strip whitespace))"); + + System.out.println(); + System.out.println(" Set parameter value: parameter 1 = " + "clobData" ); + + pstmt.setClob(1, clobData); + + System.out.println(); + System.out.println(" Execute prepared statement"); + pstmt.execute(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1023); + + pstmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // InsertwithValidationSourceisClob + + static void InsertFromStringNotWellFormedXML(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM INSERT WITH NOT WELL FORMED XML"); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1032, "+ + " 'divya" + + " ')\n" + + " \n"); + + + PreparedStatement pstmt = con.prepareStatement( + "INSERT INTO customer(cid,info) VALUES(1032," + + "'divya')"); + pstmt.execute(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con, 1032); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + //try {con.rollback(); } + //catch (Exception e) {} + } + catch(Exception e) + {} + } //InsertFromStringNotWellFormedXML + + // helping function + static void preRequisites(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + // create table 'oldcustomer' + stmt.executeUpdate( + "CREATE TABLE oldcustomer(ocid integer," + + "firstname varchar(15)," + + "lastname varchar(15)," + + "addr varchar(300)," + + "information XML)"); + + + // populate table oldcustomer with data + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate( + "INSERT INTO oldcustomer " + + "VALUES (1007,'Raghu','nandan',' " + + "karnatakabangalore" + + " ',XMLPARSE(document'
24 gulmarg" + + "bangalorekarnataka " + + "
'preserve whitespace))"); + + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "INSERT INTO oldcustomer " + + " VALUES(1008,'Rama','murthy','karnatakabelgaum" + + " ',XMLPARSE(document'
12 " + + " gandhimarg belgaumkarnataka"+ + "
'preserve whitespace))"); + + + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate( + "INSERT INTO oldcustomer " + + "VALUES(1009,'Rahul','kumar'," + + "'Rahul" + + " 25MarkhamOntario"+ + " N9C-3T6905-555-7258'," + + "XMLPARSE(document ' " + + "
25 Westend" + + "MarkhamOntario
" + + "
'preserve whitespace))"); + + Statement stmt4 = con.createStatement(); + stmt4.executeUpdate( + "INSERT INTO oldcustomer " + + "VALUES(1010,'Sweta','Priya','" + + "karnatakakolar'," + + "XMLPARSE(document'
56 hillview" + + "kolarkarnataka
i" + + "
'preserve whitespace))"); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // PreRequisites + + // helping function + static void CustomerTbContentDisplay(Connection con,int Cid) + { + try + { + int customerid = 0; + String customerInfo = ""; + + // prepare the query + System.out.println(); + System.out.println( + " Prepare Statement:\n" + + " SELECT cid,XMLSERIALIZE(info as varchar(600))\n" + + " FROM customer WHERE cid=" + Cid); + + PreparedStatement pstmt = con.prepareStatement( + " SELECT cid,XMLSERIALIZE(info as varchar(600)) FROM " + + " customer WHERE cid = ?"); + + System.out.println(); + System.out.println(" Set parameter value: parameter 1 = " + Cid); + + pstmt.setInt(1, Cid); + + System.out.println(); + System.out.println(" Execute prepared statement"); + ResultSet rs = pstmt.executeQuery(); + + System.out.println( + " CUSTOMERID CUSTOMERINFO \n" + + " ---------- -------------- "); + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + customerid = rs.getInt(1); + customerInfo = rs.getString(2); + + System.out.println( + " " + + Data.format(customerid, 10) + " " + + Data.format(customerInfo, 1024)); + } + + rs.close(); + pstmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } // CustomerTableContentDisplay + + // this function will Read a file in a buffer and + // return the String value to called function + public static String returnFileValues(String fileName) + { + String record = null; + try + { + FileReader fr = new FileReader(fileName); + BufferedReader br = new BufferedReader(fr); + record = new String(); + record = br.readLine(); + String descReturn=record; + while ((record = br.readLine()) != null) + descReturn=descReturn+record; + return descReturn; + } + catch (IOException e) + { + // catch possible io errors from readLine() + System.out.println(" file " + fileName + "doesn't exist"); + + System.out.println(" Quitting program!"); + System.out.println(); + System.exit(-1); + } + return null; + }// returnFileValues + + + static void DeleteofRowwithXmlData(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "---------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO PERFORM A DELETE OF ROW WITH XML DATA."); + + System.out.println(); + System.out.println(" Perform:\n" + + " DELETE FROM customer\n" + + " WHERE cid>=1006 and cid <= 1032\n" + + "\n"); + + PreparedStatement stmt1 = con.prepareStatement( + "DELETE FROM customer " + + "WHERE cid>=1006 and cid <= 1032"); + + stmt1.execute(); + PreparedStatement stmt2 = con.prepareStatement( + "DROP TABLE oldcustomer"); + stmt2.execute(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1007); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + {} + } //DeleteofRowwithXmlData +} //XmlInsert diff --git a/xml/java/jdbc/XmlMdc.java b/xml/java/jdbc/XmlMdc.java new file mode 100644 index 0000000..e2a5f05 --- /dev/null +++ b/xml/java/jdbc/XmlMdc.java @@ -0,0 +1,768 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2008 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose +// of assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty +// of any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS +// OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions +// do not allow for the exclusion or limitation of implied warranties, so the +// above limitations or exclusions may not apply to you. IBM shall not be liab +// le for any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility +// of such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: XmlMdc.java +// +// PURPOSE: This sample demonstrates the following features +// 1. XML data type columns in MDC tables. +// 2. Faster insert and faster delete options supported in MDC tables +// having XML columns. +// +// USAGE SCENARIO: The scenario is for a Book Store that has two types +// of customers, retail customers and corporate customers. +// Corporate customers do bulk purchases of books for their company +// libraries. The store's DBA maintains the database, +// the store manager runs queries on different tables to view +// the book sales. +// +// The store expands and opens four more branches +// in the city, all the books are spread across different branches. +// The store manager complains to the DBA that queries to get details +// like availability of a particular book by a particular author +// in a particular branch are very slow. +// +// The DBA decides to improve the query performance by converting a +// non-MDC table, for books available in different branches of the +// store, into an MDC table. To further improve the query performace, +// the DBA decides to create partition on the MDC table based on +// the published date of the book. By creating an MDC table, the query +// performance increases and the sales clerk can do faster inserts into +// this table when he receives books from different suppliers. He can +// also do faster deletes when he wants to delete a particular type of +// book due to low sales in a particular branch for that category of +// book in that location. +// +// PREREQUISITE: None +// +// EXECUTION: i) javac Util.java +// ii) javac XmlMdc.java +// iii) java XmlMdc +// +// INPUTS: NONE +// +// OUTPUTS: Successfull execution of all the queries. +// +// OUTPUT FILE: XmlMdc.out (available in the online documentation) +// +// SQL Statements USED: +// CREATE +// INSERT +// DROP +// +// +// SQL/XML Functions USED: +// XMLEXISTS +// +// ************************************************************************* +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// *************************************************************************/ +// +// SAMPLE DESCRIPTION +// +// /************************************************************************* +// This sample will demonstrate +// 1. Moving data from a non-MDC table to an MDC table. +// 2. MDC table with partition. +// 3. Faster inserts into MDC table containing an XML column. +// 4. Faster delete on MDC table containing an XML column. +// 5. Exploiting block indexes and XML indexes in a query. +// *************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.util.*; +import java.io.*; + +class XmlMdc +{ + static Db db; + public static void main(String argv[]) + { + String url="jdbc:db2:sample"; + Connection con = null; + ResultSet rs = null; + javax.sql.DataSource ds = null; + try + { + db=new Db(argv); + } + catch (Exception e) + { + System.out.println(" Error loading DB2 Driver...\n"); + System.out.println(e); + System.exit(1); + } + try + { + con = db.connect(); + } + catch (Exception e) + { + System.out.println("Connection to sample db can't be established."); + System.err.println(e) ; + System.exit(1); + } + System.out.println("This sample demonstrates the following: "); + System.out.println("XML data type columns in MDC tables"); + System.out.println("Faster insert and Faster delete options support in MDC"+ + " tables having XML columns"); + try + { + moveFromNonMdcToMdc(con); + mdcWithRangepartition(con); + mdcFasterInsert(con); + mdcFasterDelete(con); + mdcWithXmlAndBlockIndexes(con); + cleanUp(con); + } + catch(Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void moveFromNonMdcToMdc(Connection con) + { + Statement stmt = null; + try + { + System.out.println("\n-------------------------------------------------"); + System.out.println("1. Moving data from a non-MDC table to an MDC table"); + System.out.println("-------------------------------------------------\n"); + + stmt = con.createStatement(); + + System.out.println("CREATE TABLE books(book_id VARCHAR(10), "+ + "publish_date DATE, category VARCHAR(20),"+ + "location VARCHAR(20), status VARCHAR(15))"); + + stmt.executeUpdate(" CREATE TABLE books(book_id VARCHAR(10), "+ + "publish_date "+ + "DATE, category VARCHAR(20),"+ + "location VARCHAR(20), status VARCHAR(15))"); + + String cmd = "INSERT INTO books VALUES ('BK101', '10-01-2008', "+ + "'Management', 'Tasman','available')"; + stmt.executeUpdate(cmd); + + cmd = "INSERT INTO books VALUES ('BK102', '01-01-2008', "+ + "'Fantasy', 'Cupertino', 'available')"; + + stmt.executeUpdate(cmd); + + cmd = "INSERT INTO books VALUES('BK103', '10-10-2007', "+ + "'Fantasy', 'Cupertino', 'ordered')"; + stmt.executeUpdate(cmd); + + cmd = "INSERT INTO books VALUES ('BK104', '05-02-2007', "+ + "'Spiritual', 'Tasman', 'available')"; + stmt.executeUpdate(cmd); + + System.out.println("\n--------------------------------------------------"); + System.out.println("Create 'books_mdc' table partitioned by "+ + "'publish date' and organized by multiple dimensions -"+ + " category, location and status."); + System.out.println("\n-------------------------------------------------"); + System.out.println("CREATE TABLE books_mdc(book_id VARCHAR(20), "+ + " publish_date DATE, category"+ + " VARCHAR(20), location VARCHAR(20), status VARCHAR(15),"+ + " book_details XML)"+ + " DISTRIBUTE BY HASH(book_id)"+ + " PARTITION BY RANGE(publish_date)"+ + " (STARTING FROM ('01-01-2007')"+ + " ENDING ('12-12-2008') EVERY 3 MONTHS)"+ + " ORGANIZE BY DIMENSIONS (category, location, status)"); + + cmd = "CREATE TABLE books_mdc (book_id VARCHAR(20), "+ + " publish_date DATE, category"+ + " VARCHAR(20), location VARCHAR(20), status VARCHAR(15),"+ + " book_details XML)"+ + " DISTRIBUTE BY HASH(book_id)"+ + " PARTITION BY RANGE(publish_date)"+ + " (STARTING FROM ('01-01-2007')"+ + " ENDING ('12-12-2008') EVERY 3 MONTHS)"+ + " ORGANIZE BY DIMENSIONS (category, location, status)"; + stmt.executeUpdate(cmd); + + System.out.println("Move the book details data from 'books' table and "+ + "insert them into 'books_mdc' table"); + + cmd = "INSERT INTO books_mdc (book_id, publish_date, category, "+ + "location, status) SELECT book_id, publish_date, "+ + "category, location, status FROM books"; + stmt.executeUpdate(cmd); + + cmd = "UPDATE books_mdc SET book_details = "+ + "' "+ + "Communication skills"+ + "Peter Sharon"+ + "120"+ + "Wroxa"+ + "'"+ + "WHERE book_id='BK101'"; + stmt.executeUpdate(cmd); + + cmd = "UPDATE books_mdc SET book_details = "+ + "'"+ + "Blue moon"+ + "Paul Smith"+ + "100"+ + "Orellier"+ + "'"+ + "WHERE book_id='BK102'"; + stmt.executeUpdate(cmd); + + cmd = "UPDATE books_mdc SET book_details = "+ + "'"+ + "Paint your house"+ + "Roger Martin"+ + "120"+ + "BPBH"+ + "'"+ + "WHERE book_id='BK103'"; + stmt.executeUpdate(cmd); + + cmd = "UPDATE books_mdc SET book_details = "+ + "'"+ + "Ramayan"+ + "Eric Mathews"+ + "90"+ + "Tata Ho"+ + "'"+ + "WHERE book_id = 'BK104'"; + stmt.executeUpdate(cmd); + stmt.executeUpdate("COMMIT"); + + cmd = "SELECT book_id, publish_date, "+ + "category, location, status FROM books_mdc"; + ResultSet rs = stmt.executeQuery(cmd); + + System.out.println("\n\nSELECT book_id, publish_date, "+ + "category, location, status FROM books_mdc"); + String bk_id, cat, loc, stat; + java.util.Date dt; + + System.out.println("bookid publish_date category location status"); + System.out.println("--------------------------------------------------"); + + while (rs.next()) + { + bk_id = rs.getString(1); + dt = rs.getDate(2); + cat = rs.getString(3); + loc = rs.getString(4); + stat = rs.getString(5); + + System.out.println(""+bk_id+" "+dt+" "+cat+" "+loc+""+ + "" +stat+" "); + } + + rs.close(); + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // moveFromNonMdcToMdc + + static void mdcWithRangepartition(Connection con) + { + Statement stmt = null; + try + { + System.out.println("-------------------------------------------------"); + System.out.println("2. MDC table with partition"); + System.out.println("-------------------------------------------------"); + + System.out.println("\nThis query gets the details of list of 'Management'"+ + " books available in 'Tasman' branch whose published "+ + " date is 10-01-2008 "); + + stmt = con.createStatement(); + String str = "SELECT book_id, publish_date, category, location, status "+ + " FROM books_mdc "+ + " WHERE location='Tasman' and category='Management' and"+ + " publish_date='10-01-2008' and "+ + " XMLEXISTS ('$b/book_details[author=\"Peter Sharon\"]' "+ + " PASSING book_details as \"b\")"; + System.out.println(str); + + ResultSet rs = stmt.executeQuery(str); + String bk_id, cat, loc, stat; + java.util.Date dt; + + System.out.println("\nbookid publish_date category location status"); + System.out.println("----------------------------------------------------"); + + while (rs.next()) + { + bk_id = rs.getString(1); + dt = rs.getDate(2); + cat = rs.getString(3); + loc = rs.getString(4); + stat = rs.getString(5); + + System.out.println(""+bk_id+" "+dt+" "+cat+" "+loc+""+ + ""+stat+" "); + } + rs.close(); + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + } // mdcWithRangepartition + + static void mdcFasterInsert(Connection con) throws Exception + { + Statement stmt = null; + String tableName = "BOOKS_MDC"; + String schemaName = getSchemaName(con, tableName); + String fullTableName = schemaName +"."+ tableName; + + try + { + System.out.println("\n-------------------------------------------------"); + System.out.println("3. Faster inserts into MDC table containing "+ + "an XML column."); + System.out.println("-------------------------------------------------\n"); + + System.out.println("\n Enable the LOCKSIZE BLOCKINSERT option for "); + System.out.println("faster insert on MDC table "); + + stmt = con.createStatement(); + String str = "ALTER TABLE books_mdc LOCKSIZE BLOCKINSERT"; + stmt.executeUpdate(str); + System.out.println(str); + + System.out.println("Insert data into Block 0"); + + str = "INSERT INTO books_mdc VALUES('BK105', '12-10-2007', 'Management', "+ + "'Schaumberg', "+ + "'available',' "+ + "How to Sell or Market "+ + "Rusty Harold "+ + "450"+ + "Orellier"+ + "')"; + stmt.executeUpdate(str); + + str = "INSERT INTO books_mdc VALUES('BK106', '03-12-2007', 'Management', "+ + "'Schaumberg', "+ + "'available','"+ + "How to become CEO"+ + "Booster Hoa"+ + "150"+ + "wroxa"+ + "')"; + stmt.executeUpdate(str); + + str = "INSERT INTO books_mdc VALUES('BK107', '06-25-2008', 'Management', "+ + "'Schaumberg',"+ + "'available','"+ + "Effective Email communication"+ + "Sajer Menon"+ + "100"+ + "PHPB"+ + "')"; + stmt.executeUpdate(str); + stmt.executeUpdate("commit"); + + System.out.println("Insert data into block 1"); + str = "INSERT INTO books_mdc VALUES('BK108', '04-23-2008', "+ + "'Management', 'Cupertino',"+ + "'Not available','"+ + "Presentation skills"+ + "Martin Lither"+ + "125"+ + "PHPB"+ + "')"; + stmt.executeUpdate(str); + + str = "INSERT INTO books_mdc VALUES('BK109', '09-25-2007', "+ + "'Management', 'Cupertino',"+ + "'Not available','"+ + "Assertive Skills"+ + "Robert Steve"+ + "250"+ + "wroxa"+ + "')"; + stmt.executeUpdate(str); + + str = "INSERT INTO books_mdc VALUES('BK110', '05-29-2007', "+ + "'Management', 'Cupertino',"+ + "'Not available','"+ + "Relationship building"+ + "Bunting Mexa"+ + "190"+ + "Tata Ho"+ + "')"; + stmt.executeUpdate(str); + stmt.executeUpdate("commit"); + + System.out.println("Insert data in block 2"); + + str = "INSERT INTO books_mdc VALUES('BK111', '08-14-2008', "+ + "'Management', 'Tasman',"+ + "'available','"+ + "Manage your Time"+ + "Pankaj Singh"+ + "125"+ + "Orellier"+ + "')"; + stmt.executeUpdate(str); + + str = "INSERT INTO books_mdc VALUES('BK112', '07-25-2008', "+ + "'Management', 'Tasman',"+ + "'available','"+ + "Be in the Present"+ + "Hellen Sinki"+ + "200"+ + "Orellier"+ + "')"; + stmt.executeUpdate(str); + + str = "INSERT INTO books_mdc VALUES('BK113', '06-23-2008', "+ + "'Management', 'Tasman',"+ + "'available', '"+ + "How to become Rich"+ + "Booster Hoa"+ + "200"+ + "wroxa"+ + "')"; + stmt.executeUpdate(str); + stmt.executeUpdate("commit"); + + System.out.println("Insert data into block 3"); + + str = "INSERT INTO books_mdc VALUES('BK114', '08-08-2008',"+ + " 'Fantasy', 'Schaumberg',"+ + "'available','"+ + "Dream home"+ + "Hellen Sinki"+ + "250"+ + "wroxa"+ + "')"; + stmt.executeUpdate(str); + + str = "INSERT INTO books_mdc VALUES('BK115', '05-12-2008', "+ + "'Fantasy', 'Schaumberg',"+ + "'available', '"+ + "Dream world"+ + "Hellen Sinki"+ + "100"+ + "wroxa"+ + "')"; + stmt.executeUpdate(str); + stmt.executeUpdate("commit"); + + System.out.println("Insert data into block 4"); + str = "INSERT INTO books_mdc VALUES('BK116', '09-10-2007', "+ + "'Fantasy', 'Cupertino',"+ + "'Not available','"+ + "Mothers Island"+ + "Booster Hoa"+ + "250"+ + "wroxa"+ + "')"; + stmt.executeUpdate(str); + + str = "INSERT INTO books_mdc VALUES('BK117', '03-11-2007', "+ + " 'Fantasy', 'Cupertino',"+ + "'Not available','"+ + "The destiny "+ + "Marran"+ + "250"+ + "Orellier"+ + "')"; + stmt.executeUpdate(str); + + stmt.executeUpdate("commit"); + + System.out.println("Insert data into block 5"); + + str = "INSERT INTO books_mdc VALUES('BK118', '03-12-2007', "+ + "'Spiritual', 'Tasman',"+ + "'available','"+ + "Mahabharat"+ + "Narayana Murthy"+ + "250"+ + "PHPB"+ + "')"; + stmt.executeUpdate(str); + + str = "INSERT INTO books_mdc VALUES('BK119', '09-09-2008', "+ + " 'Spiritual', 'Tasman',"+ + "'available','"+ + "Bhagavat Gita"+ + "Narayana Murthy"+ + "250"+ + "PHPB"+ + "')"; + stmt.executeUpdate(str); + + stmt.executeUpdate("commit"); + + System.out.println("Run Runstats command on MDC table to "+ + "update statistics in the catalog tables."); + + try + { + File outputFile = new File("RunstatsCmd.db2"); + FileWriter out = new FileWriter(outputFile); + + String cmd = "RUNSTATS ON TABLE "+fullTableName +" WITH DISTRIBUTION "+ + " AND DETAILED INDEXES ALL"; + out.write("CONNECT TO SAMPLE;\n"); + out.write(cmd+";\n"); + out.close(); + + Process p = Runtime.getRuntime().exec("db2 -vtf RunstatsCmd.db2"); + + // open streams for the process's input and error + BufferedReader stdInput = new BufferedReader(new + InputStreamReader(p.getInputStream())); + BufferedReader stdError = new BufferedReader(new + InputStreamReader(p.getErrorStream())); + String s; + + // read the output from the command and set the output variable with + // the value + while ((s = stdInput.readLine()) != null) + { + System.out.println(s); + } + + // read any errors from the attempted command and set the error + // variable with the value + while ((s = stdError.readLine()) != null) + { + System.out.println(s); + } + + // destroy the process created + p.destroy(); + + // delete the temporary file created + outputFile.deleteOnExit(); + + //stmt.executeUpdate(str); + } + catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + + System.out.println("Change the locksize to default "); + stmt.executeUpdate("ALTER TABLE books_mdc LOCKSIZE ROW"); + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // mdcFasterInsert + + static void mdcFasterDelete(Connection con) + { + Statement stmt = null; + try + { + System.out.println("\n-------------------------------------------------"); + System.out.println("4. Faster delete on MDC table containing an XML "+ + "column."); + System.out.println("-------------------------------------------------\n"); + + stmt = con.createStatement(); + System.out.println("Set MDC ROLLOUT option to make the delete "+ + "operation faster.\n"); + String str = "SET CURRENT MDC ROLLOUT MODE IMMEDIATE"; + stmt.executeUpdate(str); + System.out.println(str); + + System.out.println("Delete all 'Fantasy' category books from "+ + "'books_mdc' table \n"); + str = "DELETE from books_mdc "+ + "WHERE category='Fantasy' AND location = 'Cupertino'"; + stmt.executeUpdate(str); + System.out.println(str); + + stmt.close(); + } + catch(Exception e) + { + System.out.println("Could not delete" + e); + } + } // mdcFasterDelete + + static void mdcWithXmlAndBlockIndexes(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + + System.out.println("\n-------------------------------------------------"); + System.out.println("5. Exploiting block indexes and XML indexes in a query"); + System.out.println("-------------------------------------------------\n"); + + + System.out.println("For faster retrieval of data the DBA creates "+ + "an XML index on the author element of book_details"+ + " XML document. \n"); + + String str = "CREATE INDEX auth_ind on books_mdc (book_details)"+ + " GENERATE KEY USING XMLPATTERN '/book_details/author' AS SQL "+ + " VARCHAR(20)"; + stmt.executeUpdate(str); + System.out.println(str); + + + System.out.println("Query the table to get all 'Management' books"+ + " available in the store by author 'Booster Ho'. "+ + " This query exploits both block index and XML index.\n"); + + str = "SELECT book_id, publish_date, category, location, status "+ + " FROM books_mdc "+ + " WHERE category='Management' and status='available' "+ + " and XMLEXISTS('$b/book_details[author=\"Booster Hoa\"]' "+ + " PASSING book_details as \"b\")"; + + ResultSet rs = stmt.executeQuery(str); + System.out.println(); + System.out.println(str); + + String bk_id, cat, loc, stat; + java.util.Date dt; + + System.out.println("\nbookid publish_date category location status"); + System.out.println("--------------------------------------------------"); + + while (rs.next()) + { + bk_id = rs.getString(1); + dt = rs.getDate(2); + cat = rs.getString(3); + loc = rs.getString(4); + stat = rs.getString(5); + + System.out.println(""+bk_id+" "+dt+" "+cat+" "+loc+""+ + " "+stat+" "); + } + rs.close(); + stmt.close(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // mdcWithXmlAndBlockIndexes + + // function to get the schema name for a particular table + static String getSchemaName(Connection conn, String tableName) throws Exception + { + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT tabschema "+ + " FROM syscat.tables "+ + " WHERE tabname = '"+ tableName + "'"); + + boolean result = rs.next(); + String schemaName = rs.getString("tabschema"); + rs.close(); + stmt.close(); + + // remove the trailing white space characters from schemaName before + // returning it to the calling function + return schemaName.trim(); + } // getSchemaName + + static void cleanUp(Connection con) + { + Statement stmt = null; + try + { + stmt=con.createStatement(); + String str = "DROP TABLE books"; + System.out.println(str); + stmt.executeUpdate(str); + + str = "DROP TABLE books_mdc"; + stmt.executeUpdate(str); + System.out.println(str); + stmt.executeUpdate("commit"); + + stmt.close(); + + db.disconnect(); + } + catch(Exception e) + { + System.out.println("Cleanup failed"); + } + } // cleanUp +} // XmlMdc diff --git a/xml/java/jdbc/XmlRead.java b/xml/java/jdbc/XmlRead.java new file mode 100644 index 0000000..1e0ebfc --- /dev/null +++ b/xml/java/jdbc/XmlRead.java @@ -0,0 +1,356 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlRead.java +// +// SAMPLE: How to read table data +// +// SQL Statements USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// OUTPUT FILE: XmlRead.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.util.*; +import java.io.*; +import java.lang.*; +import java.sql.*; + + +class XmlRead +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO READ TABLE DATA."); + + // connect to the 'sample' database + db.connect(); + + // different ways to read table data + execQuery(db.con); + execPreparedQuery(db.con); + execPreparedQueryWithParam(db.con); + ReadClobData(db.con); + ReadBlobData(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + static void execQuery(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " Statement\n" + + "TO EXECUTE A QUERY."); + + Statement stmt = con.createStatement(); + + // execute the query + System.out.println(); + System.out.println( + " Execute Statement:\n" + + " SELECT cid,XMLSERIALIZE(info as varchar(600) " + + " FROM customer WHERE cid < 1005 ORDER BY cid"); + + ResultSet rs = stmt.executeQuery( + " SELECT cid,XMLSERIALIZE(info as varchar(600)) " + + "FROM customer WHERE cid < 1005 ORDER BY cid"); + + System.out.println(); + System.out.println(" Results:\n" + + " CUSTOMERID CUSTOMERINFO \n" + + " ---------- --------------"); + + int customerid = 0; + String customerInfo = ""; + + while (rs.next()) + { + customerid = rs.getInt(1); + customerInfo= rs.getString(2); + + System.out.println(" " + + Data.format(customerid,10) + " " + + Data.format(customerInfo, 1024)); + } + + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } // execQuery + + static void execPreparedQuery(Connection con) + { + try + { + System.out.println(); + System.out.println( + "-----------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " PreparedStatement\n" + + "TO EXECUTE A PREPARED QUERY."); + + Statement stmt = con.createStatement(); + + // prepare the query + System.out.println(); + System.out.println( + " Prepare Statement:\n" + + " SELECT cid,XMLSERIALIZE(info as varchar(600)"+ + " FROM customer WHERE cid < 1005 ORDER BY cid"); + + PreparedStatement pstmt = con.prepareStatement( + " SELECT cid,XMLSERIALIZE(info as varchar(600)) "+ + " FROM customer WHERE cid < 1005 ORDER BY cid"); + + System.out.println(); + System.out.println(" Execute prepared statement"); + ResultSet rs = pstmt.executeQuery(); + + System.out.println(); + System.out.println(" Results:\n" + + " CUSTOMERID CUSTOMERINFO\n" + + " ---------- --------------"); + + int customerid = 0; + String customerInfo = ""; + + while (rs.next()) + { + customerid = rs.getInt(1); + customerInfo= rs.getString(2); + + System.out.println(" " + + Data.format(customerid,10) + " " + + Data.format(customerInfo, 1024)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } //execPreparedQuery + + static void execPreparedQueryWithParam(Connection con) + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------\n" + + "USE THE JAVA 2 CLASS:\n" + + " PreparedStatement\n" + + "TO EXECUTE A PREPARED QUERY WITH PARAMETERS."); + + Statement stmt = con.createStatement(); + + // prepare the query + System.out.println(); + System.out.println( + " Prepare Statement:\n" + + " SELECT cid,XMLSERIALIZE(info as varchar(600)"+ + " FROM customer WHERE cid < ? ORDER BY cid"); + + PreparedStatement pstmt = con.prepareStatement( + " SELECT cid,XMLSERIALIZE(info as varchar(600))" + + " FROM customer WHERE cid < ? ORDER BY cid"); + + + System.out.println(); + System.out.println(" Set parameter value: parameter 1 = 1005"); + + pstmt.setInt(1, 1005); + + System.out.println(); + System.out.println(" Execute prepared statement"); + ResultSet rs = pstmt.executeQuery(); + + System.out.println(); + System.out.println(" Results:\n" + + " CUSTOMERID CUSTOMERINFO\n" + + " ---------- --------------"); + + int customerid = 0; + String customerInfo = ""; + + while (rs.next()) + { + customerid = rs.getInt(1); + customerInfo= rs.getString(2); + + System.out.println(" " + + Data.format(customerid,10) + " " + + Data.format(customerInfo, 1024)); + } + rs.close(); + stmt.close(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e, con); + jdbcExc.handle(); + } + } //execPreparedQueryWithParam + + static void ReadClobData(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + String cursorName = ""; + String xmlData = ""; + // Create a CLOB object + java.sql.Clob clobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createClob(xmlData); + + System.out.println(); + System.out.println(" READ CLOB DATA FROM XML COLUMN\n"); + + System.out.println("SELECT cid, XMLSERIALIZE(info as clob)" + + " from customer where cid < 1005 ORDER BY cid"); + + Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT cid, XMLSERIALIZE(info as Clob)" + + " from customer where cid < 1005 ORDER BY cid"); + //cursorName = rs.getCursorName(); + + String temp_clob = null; + + while(rs.next()) + { + customerid = rs.getInt(1); + + System.out.println(" " + + Data.format(customerid, 10) + " "); + + Clob clob = rs.getClob(2); + long clob_length = clob.length(); + temp_clob = clob.getSubString(1,(int) clob_length);; + //String temp_blob = clobData.getString(2); + System.out.println(temp_clob); + } + } + catch( Exception e) + { + System.out.println(e); + } + } //ReadClobData + + static void ReadBlobData(Connection con) + { + try + { + int customerid = 0; + Blob blobData = null; + + System.out.println(); + System.out.println(" READ BLOB DATA FROM XML COLUMN\n"); + + + System.out.println("SELECT cid, " + + "XMLSERIALIZE(info as blob)" + + " from customer where cid < 1005 ORDER BY cid"); + + PreparedStatement pstmt = con.prepareStatement( + " SELECT cid, XMLSERIALIZE(info as blob)"+ + " from customer where cid < 1005 ORDER BY cid"); + ResultSet rs = pstmt.executeQuery(); + + while(rs.next()) + { + + customerid = rs.getInt(1); + + System.out.println(" " + + Data.format(customerid, 10) + " "); + + Blob blob = rs.getBlob(2); + byte[] Array=blob.getBytes(1, (int) blob.length()); + String temp_string = ""; + for (int i =0; i < Array.length; i++ ) + { + char temp_char; + temp_char = (char)Array[i]; + temp_string += temp_char; + } + + System.out.println(temp_string); + System.out.println(); + + + } + } + catch (Exception e) + { + System.out.println(e); + } + } //ReadBlobData +} diff --git a/xml/java/jdbc/XmlRunstats.java b/xml/java/jdbc/XmlRunstats.java new file mode 100644 index 0000000..46814f0 --- /dev/null +++ b/xml/java/jdbc/XmlRunstats.java @@ -0,0 +1,205 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlRunstats.java +// +// SAMPLE: How to perform RUNSTATS on a table containing XML type columns. +// +// SQL STATEMENTS USED: +// SELECT +// CONNECT +// RUNSTATS +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// File +// FileWriter +// Process +// BufferedReader +// InputStreamReader +// +// Classes used from Util.java are: +// Db +// JdbcException +// +// +// OUTPUT FILE: XmlRunstats.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; +import java.lang.*; +import java.io.*; + +public class XmlRunstats +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + // connect to the 'sample' database + db.connect(); + + // call xmlRunstats that updates the statistics of customer table + xmlRunstats(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + JdbcException jdbcExc = new JdbcException(e); + jdbcExc.handle(); + } + } // main + + // call runstats on 'customer' table to update its statistics + static void xmlRunstats(Connection conn) throws Exception + { + System.out.print( + "\n-----------------------------------------------------------\n" + + "\nUSE THE SQL STATEMENT:\n"+ + " RUNSTATS\n" + + "TO UPDATE TABLE STATISTICS.\n"); + + // get fully qualified name of the table + String tableName = "CUSTOMER"; + String schemaName = getSchemaName(conn, tableName); + String fullTableName = schemaName + "." + tableName; + + try + { + // store the CLP commands in a file and execute the file + File outputFile = new File("RunstatsCmd.db2"); + FileWriter out = new FileWriter(outputFile); + + // perform runstats on table customer for all columns including XML columns + String cmd1 = "RUNSTATS ON TABLE "+ fullTableName ; + + // perform runstats on table customer for XML columns + String cmd2 = "RUNSTATS ON TABLE "+ fullTableName + + " ON COLUMNS (Info, History) "; + + // perform runstats on table customer for XML columns + // with the following options: + // + // Distribution statistics for all partitions + // Frequent values for table set to 30 + // Quantiles for table set to -1 (NUM_QUANTILES as in DB Cfg) + // Allow others to have read-only while gathering statistics + String cmd3 = "RUNSTATS ON TABLE "+ fullTableName + + " ON COLUMNS(Info, History LIKE STATISTICS)" + + " WITH DISTRIBUTION ON KEY COLUMNS" + + " DEFAULT NUM_FREQVALUES 30 NUM_QUANTILES -1" + + " ALLOW READ ACCESS"; + + // perform runstats on table customer + // with the following options: + // + // EXCLUDING XML COLUMNS. + // This option allows the user to exclude all XML type columns from + // statistics collection. Any XML type columns that have been specified + // in the cols-list will be ignored and no statistics will be collected + // from them. This clause facilitates the collection of statistics + // on non XML columns. + String cmd4 = "RUNSTATS ON TABLE "+ fullTableName + + " ON COLUMNS(Info, History LIKE STATISTICS)" + + " WITH DISTRIBUTION ON KEY COLUMNS" + + " EXCLUDING XML COLUMNS "; + + out.write("CONNECT TO SAMPLE;\n"); + out.write(cmd1 + ";\n"); + out.write(cmd2 + ";\n"); + out.write(cmd3 + ";\n"); + out.write(cmd4 + ";\n"); + out.write("CONNECT RESET;\n"); + + out.close(); + + Process p = Runtime.getRuntime().exec("db2 -vtf RunstatsCmd.db2"); + + // open streams for the process's input and error + BufferedReader stdInput = new BufferedReader(new + InputStreamReader(p.getInputStream())); + BufferedReader stdError = new BufferedReader(new + InputStreamReader(p.getErrorStream())); + String s; + + // read the output from the command and set the output variable with + // the value + while ((s = stdInput.readLine()) != null) + { + System.out.println(s); + } + + // read any errors from the attempted command and set the error + // variable with the value + while ((s = stdError.readLine()) != null) + { + System.out.println(s); + } + + // destroy the process created + p.destroy(); + + // delete the temporary file created + outputFile.deleteOnExit(); + } + catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + } // xmlRunstats + + // function to get the schema name for a particular table + static String getSchemaName(Connection conn, String tableName) throws Exception + { + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT tabschema "+ + " FROM syscat.tables "+ + " WHERE tabname = '"+ tableName + "'"); + + boolean result = rs.next(); + String schemaName = rs.getString("tabschema"); + rs.close(); + stmt.close(); + + // remove the trailing white space characters from schemaName before + // returning it to the calling function + return schemaName.trim(); + } // getSchemaName +} // XmlRunstats diff --git a/xml/java/jdbc/XmlSchema.java b/xml/java/jdbc/XmlSchema.java new file mode 100644 index 0000000..533f951 --- /dev/null +++ b/xml/java/jdbc/XmlSchema.java @@ -0,0 +1,308 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlSchema.java +// +// SAMPLE: How to registere XML Schema +// SAMPLE: How to register an XML Schema +// SAMPLE USAGE SCENARIO: Consider a user who needs to insert an XML type value +// into the table. The user would like to ensure that the XML value conforms to a +// deterministic XML schema. +// +// PROBLEM: User has schema's for all the XML values and like to validate the values +// as per schema while inserting it to the tables. +// +// SOLUTION: +// To achieve the goal, the sample will follow the following steps: +// a) Register the primary XML schema +// b) Add the XML schema documents to the primary XML schema to ensure that the +// schema is deterministic +// c) Insert an XML value into an existing XML column and perform validation +// +// SQL Statements USED: +// INSERT +// +// Stored Procedure USED +// SYSPROC.XSR_REGISTER +// SYSPROC.XSR_ADDSCHEMADOC +// SYSPROC.XSR_COMPLETE +// +// SQL/XML Function USED +// XMLVALIDATE +// XMLPARSE +// +// PREREQUISITE: copy product.xsd, order.xsd, +// customer.xsd, header.xsd Schema files, order.xml XML +// document from xml/data directory to working +// directory. +// OUTPUT FILE: XmlSchema.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; + +class XmlSchema +{ + private static String relSchema=new String("POSAMPLE"); + private static String schemaName=new String("order");; + private static String schemaLocation= new String("http://www.test.com/order"); + private static String primaryDocument= new String("order.xsd"); + private static String multipleSchema1= new String("header.xsd"); + private static String multipleSchema2= new String("customer.xsd"); + private static String multipleSchema3= new String("product.xsd"); + private static String xmlDoc = new String("order.xml"); + private static int shred = 0; + private static int poid=10; + private static String status=new String("shipped"); + + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + System.out.println(); + + // register the XML Schema + registerXmlSchema(con); + + // Select the information about the registered schema from catalog table + selectInfo(con); + + // insert the XML value validating according to the registered schema + insertValidatexml(con); + + // drop the registered the schema + cleanUp(con); + con.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// main + + // This function will register the Primary XML Schema + static void registerXmlSchema(Connection con) + { + try + { + // register primary XML Schema + System.out.println("Registering main schema "+ primaryDocument +"..."); + CallableStatement callStmt = con.prepareCall("CALL SYSPROC.XSR_REGISTER(?,?,?,?,NULL)"); + File xsdFile = new File(primaryDocument); + FileInputStream xsdData = new FileInputStream(xsdFile); + callStmt.setString(1, relSchema); + callStmt.setString(2, schemaName); + callStmt.setString(3, schemaLocation ); + callStmt.setBinaryStream(4, xsdData, (int)xsdFile.length() ); + callStmt.execute(); + xsdData.close(); + + // add XML Schema document to the primary schema + System.out.println(" Adding XML Schema document "+ multipleSchema1 +"..."); + addXmlSchemaDoc(con,multipleSchema1); + System.out.println(" Adding XML Schema document "+ multipleSchema2 +"..."); + addXmlSchemaDoc(con,multipleSchema2); + System.out.println(" Adding XML Schema document " + multipleSchema3 +"..."); + addXmlSchemaDoc(con,multipleSchema3); + + // complete the registeration + System.out.println(" Completing XML Schema registeration"); + callStmt=con.prepareCall("CALL SYSPROC.XSR_COMPLETE(?,?,NULL,?)"); + callStmt.setString(1,relSchema); + callStmt.setString(2, schemaName); + callStmt.setInt(3, shred); + callStmt.execute(); + System.out.println("Schema registered successfully"); + callStmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(IOException ioe) + { + System.out.println("Error opening file " + primaryDocument); + } + }// registerXmlSchema + + // This function will ADD the Schema document to already registered schema. + // The Schema documents referred in the primary XML schema (using Import or include) + // should be added to the registered schema before completing the registeration. + static void addXmlSchemaDoc(Connection con,String schemaDocName) + { + try + { + File xsdFile = new File(schemaDocName); + FileInputStream xsdData = new FileInputStream(xsdFile); + CallableStatement callStmt = con.prepareCall("CALL SYSPROC.XSR_ADDSCHEMADOC(?,?,?,?,NULL)"); + callStmt.setString(1, relSchema); + callStmt.setString(2, schemaName); + callStmt.setString(3, schemaLocation ); + callStmt.setBinaryStream(4, xsdData, (int)xsdFile.length() ); + callStmt.execute(); + xsdData.close(); + callStmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(IOException ioe) + { + System.out.println("Error opening file " + schemaDocName); + } + }// addXmlSchemaDoc + + // this function will insert the XML value in the table validating it according + // to the registered schema + static void insertValidatexml(Connection con) + { + try + { + PreparedStatement prepStmt=con.prepareStatement("INSERT INTO PURCHASEORDER(poid,status,porder) VALUES(?,?,xmlvalidate(cast(? as XML) ACCORDING TO XMLSCHEMA ID posample.order))"); + File xmlFile = new File(xmlDoc); + FileInputStream xmlData = new FileInputStream(xmlFile); + prepStmt.setInt(1,poid); + prepStmt.setString(2,status); + prepStmt.setBinaryStream(3, xmlData, (int)xmlFile.length() ); + prepStmt.executeUpdate(); + prepStmt.close(); + xmlData.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(IOException ioe) + { + System.out.println("Error opening file " + xmlDoc); + } + }// insertValidatexml + + // This function will select the information about the registered schema + static void selectInfo(Connection con) + { + try + { + Statement stmt=con.createStatement(); + String query="SELECT OBJECTSCHEMA, OBJECTNAME FROM syscat.xsrobjects WHERE OBJECTNAME= '" + schemaName.toUpperCase() +"'"; + System.out.println(query); + ResultSet rs=stmt.executeQuery(query); + System.out.println("RELATIONAL SCHEMA XML SCHEMA ID"); + rs.next(); + System.out.println(); + System.out.println(rs.getString(1)+" "+ rs.getString(2)); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // selectInfo + + // This function will drop the registered schema and delete the inserted row + static void cleanUp(Connection con) + { + try + { + Statement stmt=con.createStatement(); + String query1="DROP XSROBJECT posample." + schemaName; + String query2="DELETE FROM purchaseorder WHERE poid="+poid; + System.out.println(query1); + stmt.executeUpdate(query1); + System.out.println(query2); + stmt.executeUpdate(query2); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // cleanUp +} // XmlSchema + diff --git a/xml/java/jdbc/XmlToTable.java b/xml/java/jdbc/XmlToTable.java new file mode 100644 index 0000000..3e723a4 --- /dev/null +++ b/xml/java/jdbc/XmlToTable.java @@ -0,0 +1,336 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlToTable.java +// +// SAMPLE USAGE SCENARIO:Purchase order XML document contains detailed +// information about all the orders. It will also have the detail of the +// customer with each order. +// +// PROBLEM: The document has some redundant information as customer info +// and product info is repeated in each order for example +// Customer info is repeated for each order from same customer. +// Product info will be repeated for each order of same product from different customers. +// +// SOLUTION: The sample database has tables with both relational and XML data to remove +// this redundant information. These relational tables will be used to store +// the customer info and product info in the relational table having XML data +// and id value. Purchase order will be stored in another table and it will +// reference the customerId and productId to refer the customer and product +// info respectively. +// +// To achieve the above goal this sample will shred the data for purchase order XML +// document and insert it into the tables. +// +// The sample will follow the following steps +// +// 1. Get the relevant data in XML format from the purchase order XML document (use XMLQuery) +// 2. Shred the XML doc into the relational table. (Use XMLTable) +// 3. Select the relevant data from the table and insert into the target relational table. +// +// EXTERNAL DEPENDENCIES: +// For successful precompilation, the sample database must exist +// (see DB2's db2sampl command). +// XML Document purchaseorder.xml must exist in the same directory as of this sample +// +// SQL Statements USED: +// SELECT +// INSERT +// +// XML Functions USED: +// XMLCOLUMN +// XMLELEMENT +// XMLTABLE +// XMLDOCUMENT +// XMLATTRIBTES +// XMLCONCAT +// XQUERY +// +// Classes used from Util.java are: +// Db +// SqljException +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; + +class XmlToTable +{ + static int num_record_customer=0; + static int num_record_po=0; + public static void main(String argv[]) + { + String url = "jdbc:db2:sample"; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection( url ); + System.out.println(); + // connect to the 'sample' database + PO_shred(con); + displayContent(con); + cleanUp(con); + + } catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// main + + static void displayContent(Connection con) + { + try + { + String stmt="SELECT cid, info FROM customer ORDER BY cid"; + Statement stmt1 = con.createStatement(); + Statement stmt2 = con.createStatement(); + + // Execute the select statement + ResultSet rs = stmt1.executeQuery(stmt); + + while (rs.next()) + { + int cid=rs.getInt(1); + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(2); + + // Print the result + System.out.println(); + System.out.println("CID :"+ cid +" INFO :" + data.getDB2XmlString()); + } + + // Close the result set + rs.close(); + + // Close the statement + stmt1.close(); + + stmt= "SELECT poid, porder FROM purchaseorder ORDER BY poid"; + rs=stmt2.executeQuery(stmt); + + while (rs.next()) + { + int poid=rs.getInt(1); + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(2); + + // Print the result + System.out.println(); + System.out.println("POID :"+ poid +" PORDER :" + data.getDB2XmlString()); + } + + // Close the result set + rs.close(); + + // Close the statement + stmt2.close(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // displayContent + + static void cleanUp(Connection con) + { + try + { + String stmt="DELETE FROM CUSTOMER WHERE CID IN (10,11)"; + Statement stmt1 = con.createStatement(); + + // delete from customer + System.out.println(stmt); + stmt1.executeUpdate(stmt); + + stmt="DELETE FROM PURCHASEORDER WHERE POID IN (110,111)"; + // delete from purchaseorder + System.out.println(stmt); + stmt1.executeUpdate(stmt); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // cleanUp + + static void PO_shred(Connection con) + { + String data=new String(); + String custInsert = new String(); + String POInsert = new String(); + + try + { + Statement stmt1 = con.createStatement(); + Statement stmt2 = con.createStatement(); + + // create PO table + stmt1.executeUpdate("CREATE TABLE PO (id INT GENERATED ALWAYS AS IDENTITY,purchaseorder XML)"); + PreparedStatement pstmt2; + PreparedStatement pstmt1=con.prepareStatement("insert into PO(purchaseorder) values(?)"); + pstmt1.setString(1,returnFileValues("purchaseorder.xml")); + pstmt1.executeUpdate(); + + // run the XQuery to find out the purchaseorder with status shipped + ResultSet rs=stmt1.executeQuery("XQUERY db2-fn:xmlcolumn('PO.PURCHASEORDER')/PurchaseOrders/PurchaseOrder[@Status='shipped']"); + + custInsert="INSERT INTO customer(CID,info,history)"+ + " SELECT T.CustID,xmldocument" + + "(XMLELEMENT(NAME \"customerinfo\",XMLATTRIBUTES (T.CustID as \"Cid\"),"+ + " XMLCONCAT(" + + " XMLELEMENT(NAME \"name\", T.Name ), T.Addr,"+ + " XMLELEMENT(NAME \"phone\", XMLATTRIBUTES(T.type as \"type\"), T.Phone)"+ + " ))), xmldocument(T.History)"+ + " FROM XMLTABLE( '$d/PurchaseOrder' PASSING cast(? as XML) AS \"d\""+ + " COLUMNS CustID BIGINT PATH '@CustId',"+ + " Addr XML PATH './Address',"+ + " Name VARCHAR(20) PATH './name',"+ + " Country VARCHAR(20) PATH './Address/@country',"+ + " Phone VARCHAR(20) PATH './phone',"+ + " Type VARCHAR(20) PATH './phone/@type',"+ + " History XML PATH './History') as T"+ + " WHERE T.CustID NOT IN (SELECT CID FROM customer)"; + + System.out.println("INSERT INTO CUSTOMER TABLE USING FOLLOWING QUERY FOR EACH PURCHASEORDER SELECTED\n"); + System.out.println(custInsert); + + POInsert = "INSERT INTO purchaseOrder(poid, orderdate, custid,status, porder, comments)"+ + " SELECT poid, orderdate, custid, status,xmldocument(XMLELEMENT(NAME \"PurchaseOrder\","+ + " XMLATTRIBUTES(T.Poid as \"PoNum\", T.OrderDate as \"OrderDate\","+ + " T.Status as \"Status\"),"+ + "T.itemlist)), comment"+ + " FROM XMLTable ('$d/PurchaseOrder' PASSING cast(? as XML) as \"d\""+ + " COLUMNS poid BIGINT PATH '@PoNum',"+ + " orderdate date PATH '@OrderDate',"+ + " CustID BIGINT PATH '@CustId',"+ + " status varchar(10) PATH '@Status',"+ + " itemlist XML PATH './itemlist',"+ + " comment varchar(1024) PATH './comments') as T"; + + System.out.println("\n INSERT INTO PURCHASE ORDER USING FOLLOWING QUERY FOR EACH PURCHASEORDER SELECTED\n"); + System.out.println(POInsert); + + // iterate for all the rows, insert the data into the relational table + while(rs.next()) + { + data=rs.getString(1); + // insert into customer table + System.out.println("Inserting into customer table ...."); + pstmt2=con.prepareStatement(custInsert); + + // bind the parameter value + pstmt2.setString(1,data); + pstmt2.executeUpdate(); + num_record_customer++; + + // insert into purchaseorder table + System.out.println("Inserting into purchaseorder table .....\n"); + pstmt2=con.prepareStatement(POInsert); + pstmt2.setString(1,data); + pstmt2.executeUpdate(); + num_record_po++; + + }// while loop + + // drop table po + stmt2.executeUpdate("DROP TABLE PO"); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + System.out.println("\nNumber of record inserted to customer table = " +num_record_customer); + System.out.println("Number of record inserted to purchaseorder table = " +num_record_po); + + }// PO_shred + + public static String returnFileValues(String fileName) + { + String record = null; + try + { + FileReader fr = new FileReader(fileName); + BufferedReader br = new BufferedReader(fr); + + record = new String(); + + record = br.readLine(); + String descReturn=record; + while ((record = br.readLine()) != null) + descReturn=descReturn+record; + return descReturn; + } + catch (IOException e) + { + // catch possible io errors from readLine() + System.out.println(" file " + fileName + "doesn't exist"); + System.out.println(" Can not continue with insert, please verify "+fileName+" and try again."); + System.out.println(" Quitting program!"); + System.out.println(); + System.exit(-1); + } + return null; + }// returnFileValues +}// XmlToTable diff --git a/xml/java/jdbc/XmlTrig.java b/xml/java/jdbc/XmlTrig.java new file mode 100644 index 0000000..97fa674 --- /dev/null +++ b/xml/java/jdbc/XmlTrig.java @@ -0,0 +1,566 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: XmlTrig.java +// +// PURPOSE: This sample shows how triggers are used to enforce automatic +// validation while inserting/updating XML documents +// +// USAGE SCENARIO: When a customer places a purchase order request an entry +// is made in the "customer" table by inserting customer +// information and his history details. If the customer is +// new, and is placing request for the first time with this +// supplier,then the history column in the "customer" table +// will be NULL. If he's an old customer, data in "customer" +// table info and history columns are inserted. +// +// PREREQUISITE: +// On Unix: copy boots.xsd file from /sqllib +// /samples/xml/data directory to current directory. +// On Windows: copy boots.xsd file from \sqllib\samples\ +// xml\data directory to current directory +// +// EXECUTION: javac XmlTrig.java +// java XmlTrig +// +// INPUTS: NONE +// +// OUTPUTS: The last trigger statement which uses XMLELEMENT on transition +// variable will fail. All other trigger statements will succeed. +// +// OUTPUT FILE: XmlTrig.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// CREATE TRIGGER +// INSERT +// DELETE +// DROP +// +// SQL/XML FUNCTIONS USED: +// XMLDOCUMENT +// XMLPARSE +// XMLVALIDATE +// XMLELEMENT +// +// +//*************************************************************************** +// For more information about the command line processor (CLP) scripts, +// see the README file. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, building, and running DB2 +// applications, visit the DB2 application development website: +// http://www.software.ibm.com/data/db2/udb/ad +// +//*************************************************************************** +// SAMPLE DESCRIPTION +// +//*************************************************************************** +// 1. Register boots.xsd schema with http://posample1.org namespace. +// +// 2. This sample consists of four different cases of create trigger +// statements to show automatic validation of xml documents with +// triggers. +// +// Case1: This first trigger statement shows how to assign values to +// non-xml transition variables, how to validate XML documents and +// also to show that NULL values can be assigned to XML transition +// variables in triggers. +// +// Case2: Create a BEFORE INSERT trigger to validate info column in +// "customer" table and insert a value for history column without +// any validation +// +// Case3: Create a BEFORE UPDATE trigger with ACCORDING TO clause used +// with WHEN clause.This trigger statement shows that only when WHEN +// condition is satisfied, the action part of the trigger will be +// executed.WHEN conditions are used with BEFORE UPDATE triggers. +// +// Case4: Create a BEFORE INSERT trigger with XMLELEMENT function being +// used on a transition variable. This case results in a failure as only +// XMLVALIDATE function is allowed on transition variables. +// +// NOTE: In a typical real-time scenario, DBAs will create triggers and users +// will insert records using multiple insert/update statements, not just +// one insert statement as shown in this sample. +//*************************************************************************** +// +// IMPORT ALL PACKAGES AND CLASSES +// +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.util.*; +import java.io.*; + + +class XmlTrig +{ + private static String relSchema=new String("POSAMPLE1"); + private static String schemaName=new String("boots");; + private static String schemaLocation= new String("http://www.test.com/order"); + private static String primaryDocument= new String("boots.xsd"); + private static int shred = 0; + + public static void main(String argv[]) + { + String url="jdbc:db2:sample"; + Connection con = null; + + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection(url); + con.setAutoCommit(false); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println("sth wrong her tooooooo"); + System.out.println(e); + } + + System.out.println("THIS SAMPLE SHOWS HOW TO AUTOMATIC XML DOCUMENTS"); + System.out.println(" VALIDATION USING BEFORE TRIGGERS\n\n"); + + registerXmlSchema(con); + validateXmlDocCase1(con); + validateXmlDocCase2andCase3(con); + validateXmlDocCase4(con); + clearCustomerInfo(con); + + } // main + + static void validateXmlDocCase1(Connection con) + { + Statement stmt = null; + try + { + //********************************************************************* + // Case1: This first trigger statement shows how assign values to + // non-xml transition variables, how to validate XML documents and + // also to show that NULL values can be assigned to XML transition + // variables in triggers. + //********************************************************************* + + System.out.println("CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON " + + " CUSTOMER EFERENCING NEW AS n " + + "FOR EACH ROW MODE DB2SQL " + + "BEGIN ATOMIC "+ + " set n.Cid = 5000" + + " set n.info = XMLVALIDATE(n.info ACCORDING TO " + + "XMLSCHEMA ID CUSTOMER) " + + " set n.history = NULL "+ + "END"); + + stmt = con.createStatement(); + stmt.executeUpdate( "CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON" + + " customer REFERENCING NEW AS n " + + "FOR EACH ROW MODE DB2SQL " + + "BEGIN ATOMIC "+ + " set n.Cid = 5000;" + + " set n.info = XMLVALIDATE(n.info ACCORDING TO " + + "XMLSCHEMA ID CUSTOMER); " + + " set n.history = NULL ;"+ + "END"); + + System.out.println(); + System.out.println(); + System.out.println("INSERT info and history values in customer table"); + // insert xml document into customer table + String str = "INSERT INTO customer VALUES (1008,xmlparse(document " + + "'"+ + "Larry Menard"+ + "223 Koramangala ring Road"+ + "TorontoOntario"+ + "M4C 5K8"+ + "905-555-9146416-555-6121 "+ + "Goose Defender416-555-1943"+ + "' preserve whitespace), NULL)"; + stmt.executeUpdate(str); + + displayCustomerInfo(con, 5000); + + // Drop trigger tr1 + str = "DROP TRIGGER TR1"; + stmt.executeUpdate(str); + + // close all statement connections + stmt.close(); + con.commit(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // validateXmlDocCase1 + + static void validateXmlDocCase2andCase3(Connection con) + { + Statement stmt = null; + try + { + //********************************************************************* + // Case2: Create a BEFORE INSERT trigger to validate info column in + // "customer" table and insert a value for history column without + // any validation + //********************************************************************* + + System.out.println("CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON " + + " customer REFERENCING NEW AS n " + + "FOR EACH ROW MODE DB2SQL " + + "BEGIN ATOMIC "+ + " set n.Cid = 5001" + + " set n.info = XMLVALIDATE(n.info ACCORDING TO " + + "XMLSCHEMA ID CUSTOMER) " + + " set n.history = \'suzan" + + "\';" + + "END"); + + stmt = con.createStatement(); + String str = "CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON customer "+ + "REFERENCING NEW AS n " + + "FOR EACH ROW MODE DB2SQL " + + "BEGIN ATOMIC "+ + " set n.Cid = 5001;" + + " set n.info = XMLVALIDATE(n.info ACCORDING TO " + + "XMLSCHEMA ID CUSTOMER); " + + " set n.history = \'suzan" + + "\';" + + "END"; + stmt.executeUpdate(str); + + System.out.println(); + System.out.println(); + System.out.println("INSERT info, history values into customer table"); + str = "INSERT INTO customer VALUES (1009, xmlparse(document "+ + "'"+ + "Larry Menard223 Koramangala ring Road"+ + "BangaloreOntario"+ + "M4C 5K8"+ + "905-555-9146416-555-6121 "+ + "Tim Luther416-555-1943"+ + "'), NULL)"; + stmt.executeUpdate(str); + + displayCustomerInfo(con, 5001); + + + //*********************************************************************** + // Case3: Create a BEFORE UPDATE trigger with ACCORDING TO clause used + // with WHEN clause.This trigger statement shows that only when WHEN + // condition is satisfied, the action part of the trigger will be + // executed.WHEN conditions are used with BEFORE UPDATE triggers. + //*********************************************************************** + + System.out.println("CREATE TRIGGER TR2 NO CASCADE BEFORE UPDATE"+ + "ON customer REFERENCING NEW AS n "+ + "FOR EACH ROW MODE DB2SQL "+ + "WHEN (n.info is not validated ACCORDING TO XMLSCHEMA "+ + "ID CUSTOMER)"+ + "BEGIN ATOMIC"+ + " set (n.cid) = (5002); " + + " set (n.info) = xmlvalidate(n.info ACCORDING TO " + + "XMLSCHEMA ID CUSTOMER);"+ + " set (n.history) = \'"+ + "madhavi';" + + "END"); + + // create a BEFORE UPDATE trigger + str = "CREATE TRIGGER TR2 NO CASCADE BEFORE UPDATE ON customer " + + "REFERENCING NEW AS n "+ + "FOR EACH ROW MODE DB2SQL "+ + "WHEN (n.info is not validated ACCORDING TO XMLSCHEMA"+ + " ID CUSTOMER)"+ + "BEGIN ATOMIC"+ + " set (n.cid) = (5002); " + + " set (n.info) = xmlvalidate(n.info ACCORDING TO " + + "XMLSCHEMA ID CUSTOMER);"+ + " set (n.history) = \'"+ + "madhavi';" + + "END"; + stmt.executeUpdate(str); + + System.out.println(); + System.out.println(); + System.out.println("UPDATE customer info where Cid = 5001"); + str = "UPDATE CUSTOMER SET customer.info = XMLPARSE(document "+ + "'"+ + " Russel223 Koramangala ring Road"+ + "BangaloreKarnataka"+ + "M4C 5K8"+ + "905-555-9146416-555-6121 "+ + "Vincent luther416-555-1943"+ + "' preserve whitespace) WHERE Cid=5001"; + stmt.executeUpdate(str); + + displayCustomerInfo(con, 5002); + + // drop triggers + str = "DROP TRIGGER TR1"; + stmt.executeUpdate(str); + + str = "DROP TRIGGER TR2"; + stmt.executeUpdate(str); + + // close all the statement connections + stmt.close(); + con.commit(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // validateXmlDocCase2andCase3 + + static void validateXmlDocCase4(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + + String str = "CREATE TABLE boots (Cid int, doc1 XML, doc2 XML)"; + stmt.executeUpdate(str); + + //********************************************************************* + // Case4: Create a BEFORE INSERT trigger with XMLELEMENT function being + // used on a transition variable. This case results in a failure as + // only XMLVALIDATE function is allowed on transition variables. + //******************************************************************** + + System.out.println("CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT "+ + "ON boots REFERENCING NEW AS n "+ + "FOR EACH ROW MODE DB2SQL "+ + "BEGIN ATOMIC "+ + "set (n.Cid) = (5004); "+ + "set (n.doc1) = xmlvalidate(n.doc1 ACCORDING TO XMLSCHEMA "+ + "URI 'http://posample.org');"+ + "set (n.doc2) = XMLDOCUMENT(XMLELEMENT(name Red Tape,n.doc2));"+ + "END;"); + + System.out.println("This create trigger statement will fail as " + + " XMLELEMENT is not allowed on transition variable. " + + " Only XMLVALIDATE is allowed"); + + str = "CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON boots "+ + "REFERENCING NEW AS n "+ + "FOR EACH ROW MODE DB2SQL "+ + "BEGIN ATOMIC "+ + "set (n.Cid) = (5004); "+ + "set (n.doc1) = xmlvalidate(n.doc1 ACCORDING TO XMLSCHEMA "+ + "URI 'http://posample1.org'); "+ + "set (n.doc2) = XMLDOCUMENT(XMLELEMENT(name RedTape,"+ + " n.doc2));"+ + "END"; + stmt.executeUpdate(str); + con.rollback(); + + } + catch (SQLException sqle) + { + + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // validateXmlDocCase4 + + static void displayCustomerInfo(Connection con, int custid) + { + try + { + String info = null; + int cid = 0; + String history = null; + + // Display contents of customer table + PreparedStatement pstmt = con.prepareStatement( + "SELECT Cid, info, history FROM customer WHERE Cid = ?"); + + // Set the customer id parameter marker value + pstmt.setInt(1, custid); + + //execute the query + ResultSet rs = pstmt.executeQuery(); + rs.next(); + cid = rs.getInt(1); + info = rs.getString(2); + history = rs.getString(3); + + // When history column value is not null + if (rs.getString(3) != null) + { + System.out.println("--------------------------------------------"); + System.out.println(" Cid info history "); + System.out.println("--------------------------------------------"); + System.out.println(" " + Data.format(cid, 10) + + " " + Data.format(info, 1024) + + " " + Data.format(history,1024)); + } + else + // When history column value is null + { + System.out.println("--------------------------------------------"); + System.out.println(" Cid info history "); + System.out.println("--------------------------------------------"); + System.out.println(" " + Data.format(cid, 10) + + " " + Data.format(info, 1024)); + } + + // close result set and statement connections + rs.close(); + pstmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // displayCustomerInfo + + static void clearCustomerInfo(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + String str = "DELETE FROM CUSTOMER WHERE Cid > 1005"; + stmt.executeUpdate(str); + + str = "DROP XSROBJECT POSAMPLE1.BOOTS"; + stmt.executeUpdate(str); + + stmt.close(); + con.commit(); + } + catch(Exception e) + { + System.out.println(e); + } + } + + // This function will register the Primary XML Schema + static void registerXmlSchema(Connection con) + { + try + { + // register primary XML Schema + System.out.println("--------------------------------------------------"); + System.out.println("Registering main schema "+ primaryDocument +"..."); + CallableStatement callStmt = + con.prepareCall("CALL SYSPROC.XSR_REGISTER(?,?,?,?,NULL)"); + File xsdFile = new File(primaryDocument); + FileInputStream xsdData = new FileInputStream(xsdFile); + callStmt.setString(1, relSchema); + callStmt.setString(2, schemaName); + callStmt.setString(3, schemaLocation ); + callStmt.setBinaryStream(4, xsdData, (int)xsdFile.length() ); + callStmt.execute(); + xsdData.close(); + + // complete the registeration + System.out.println(" Completing XML Schema registeration"); + callStmt=con.prepareCall("CALL SYSPROC.XSR_COMPLETE(?,?,NULL,?)"); + callStmt.setString(1,relSchema); + callStmt.setString(2, schemaName); + callStmt.setInt(3, shred); + callStmt.execute(); + System.out.println("Schema registered successfully"); + callStmt.close(); + System.out.println("-------------------------------------------------"); + System.out.println("\n\n"); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(IOException ioe) + { + System.out.println("Error opening file " + primaryDocument); + } + }// registerXmlSchema +} // XmlTrig class diff --git a/xml/java/jdbc/XmlUdfs.java b/xml/java/jdbc/XmlUdfs.java new file mode 100644 index 0000000..c1df73e --- /dev/null +++ b/xml/java/jdbc/XmlUdfs.java @@ -0,0 +1,795 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2008 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: XmlUdfs.java +// +// PURPOSE: The purpose of this sample is to show extended support of XML for +// sourced UDF and SQL bodied UDF in serial and DPF environment +// for DB2 Cobra. +// +// USAGE SCENARIO: The scenario is for a Book Store that has two types of +// customers, retail customers and corporate customers. Corporate +// customers do bulk purchases of books for their company libraries. +// The Book Store also maintains list of registered customers +// who are frequent buyers from the store and have registered +// themselves with the store. The store has a DBA, sales clerk and a +// manager for maintaining the database and to run queries on different +// tables to view the book sales. +// +// The store manager frequently queries various tables to get +// information such as contact numbers of different departments, +// location details, location manager details, employee details +// in order to perform various business functions like promoting +// employees, analysing sales, giving awards and bonus to employees +// based on their sales. +// +// The manager is frustrated writing the same queries every time to +// get the information and observes performance degradation as well. +// So he decides to create a user-defined function and a stored +// procedure for each of his requirements. +// +// PREREQUISITE: None +// +// EXECUTION: javac XmlUdfs.java +// java XmlUdfs username password servername portnumber +// +// INPUTS: NONE +// +// OUTPUTS: Successfull execution of all UDFs and stored procedures. +// +// OUTPUT FILE: XmlUdfs.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// CREATE TABLE +// INSERT +// DELETE +// DROP +// SQL/XML FUNCTIONS USED: +// XMLEXISTS +// XMLPARSE +// XMLQUERY +// +//*************************************************************************** +// For more information about the command line processor (CLP) scripts, +// see the README file. +// +// For information on using SQL statements, see the SQL Reference. +// +//*************************************************************************** +// SAMPLE DESCRIPTION +// +//*************************************************************************** +// 1. UDF Scalar function which takes an XML variable as input the parameter +// and returns XML value as output. +// +// 2. UDF Table function which takes an XML variable as input the parameter +// and returns table with XML values as output. +// +// 3. Sourced UDF which takes an XML variable as the input parameter +// and returns XML value as output. +// +// 4. SQL bodied UDF which takes an XML variable as the input parameter +// and returns a table with XML values as output. This UDF +// internally calls a stored procedure which takes an XML variable +// as the input parameter and returns an XML value as output. +// +//*************************************************************************** +// +// IMPORT ALL PACKAGES AND CLASSES +// +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.util.*; +import java.io.*; + +class XmlUdfs +{ + public static void main(String argv[]) + { + String url="jdbc:db2:sample"; + Connection con = null; + ResultSet rs = null; + javax.sql.DataSource ds = null; + try + { + String port=argv[3]; + int port1=Integer.parseInt(port); + ds=new com.ibm.db2.jcc.DB2SimpleDataSource(); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setServerName(argv[2]); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setPortNumber(port1); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setDatabaseName("sample"); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setDriverType(4); + ((com.ibm.db2.jcc.DB2BaseDataSource) ds). + setTraceFile("jcctrace.txt"); + } + catch (Exception e) + { + System.out.println(" Error loading DB2 Driver...\n"); + System.out.println(e); + System.exit(1); + } + try + { + con = ds.getConnection(argv[0], argv[1]); + + } + catch (SQLException e) + { + System.out.println("Connection to sample db can't be established."); + System.err.println(e) ; + System.exit(1); + } + + System.out.println("This sample shows how to pass "+ + " XML type variables as input parameters, return type "+ + " or local variables in SQL bodied UDFs "); + + try + { + setUpTables(con); + scalarUDF(con); + tableUDF(con); + sourcedUDF(con); + invokeSpFromUDF(con); + cleanUpTables(con); + } + catch(Exception e) + { + System.out.println("Error..."+e); + } + + } // main + + static void setUpTables(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + + System.out.println("Setting up tables for the sample"); + System.out.println("---------------------------------"); + System.out.println(); + String str = "CREATE TABLE sales_department(dept_id CHAR(10), "+ + "dept_info XML)"; + stmt.executeUpdate(str); + System.out.println(str); + System.out.println(); + + str = "CREATE TABLE sales_employee (emp_id INTEGER, "+ + " total_sales INTEGER, emp_details XML)"; + stmt.executeUpdate(str); + System.out.println(str); + System.out.println(); + + str = "CREATE TABLE performance_bonus_employees(bonus_info XML)"; + stmt.executeUpdate(str); + System.out.println(str); + + System.out.println(); + str = "INSERT INTO sales_employee VALUES (5001, 40000, "+ + "XMLPARSE(document "+ + "'"+ + "Lethar Kessy"+ + "
"+ + "555 M G Road"+ + "Bangalore"+ + "Karnataka"+ + "India"+ + "411004"+ + "
"+ + ""+ + "9435344354"+ + ""+ + "DS02"+ + "7"+ + "40000"+ + "25500"+ + "Sr. Manager"+ + "Harry"+ + "
'))"; + stmt.executeUpdate(str); + System.out.println(str); + + System.out.println(); + str = "INSERT INTO sales_employee VALUES (5002, 50000, "+ + "XMLPARSE(document "+ + "'"+ + "Mathias Jessy"+ + "
"+ + "Indra Nagar Road No. 5"+ + "Bangalore"+ + "Karnataka"+ + "India"+ + "411004"+ + "
"+ + ""+ + "9438884354"+ + ""+ + "DS02"+ + "6"+ + "50000"+ + "22500"+ + "Manager"+ + "Harry"+ + "
'))"; + stmt.executeUpdate(str); + System.out.println(str); + + System.out.println(); + str = "INSERT INTO sales_employee VALUES (5003, 40000, "+ + "XMLPARSE(document "+ + "'"+ + "Mohan Kumar"+ + "
"+ + "Vijay Nagar Road No. 5"+ + "Bangalore"+ + "Karnataka"+ + "India"+ + "411004"+ + "
"+ + ""+ + "9438881234"+ + ""+ + "DS02"+ + "5"+ + "40000"+ + "15500"+ + "Associate Manager"+ + "Harry"+ + "
'))"; + stmt.executeUpdate(str); + System.out.println(str); + + System.out.println(); + str = "INSERT INTO sales_department VALUES ('DS02', XMLPARSE(document "+ + "'"+ + "sales"+ + ""+ + "Harry Thomas"+ + ""+ + "9732432423"+ + ""+ + ""+ + ""+ + "080-23464879"+ + "080-56890728"+ + "080-45282976"+ + ""+ + "'))"; + stmt.executeUpdate(str); + System.out.println(str); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // setUpTables + + //-------------------------------------------------------------------------- + // 1. UDF Scalar function which takes an XML variable as input parameter + // and returns an XML value as output. + //-------------------------------------------------------------------------- + + static void scalarUDF(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + System.out.println("------------------------------------------"); + System.out.print("Create a scalar function 'getDeptContactNumbers' "); + System.out.println(" which returns a list of department phone numbers "); + System.out.println("------------------------------------------"); + + System.out.println(); + String str = "CREATE FUNCTION getDeptContactNumbers(dept_info_p XML)"+ + "RETURNS XML "+ + "LANGUAGE SQL "+ + "SPECIFIC contactNumbers "+ + "NO EXTERNAL ACTION "+ + "BEGIN ATOMIC "+ + "RETURN XMLQuery('document "+ + "{{$dep/department/phone}}' "+ + "PASSING dept_info_p as \"dep\");"+ + "END"; + stmt.executeUpdate(str); + System.out.println(str); + + System.out.println("Call scalar UDF 'getDeptContactNumbers' to get "); + System.out.println(" contact numbers of the department \"DS02\" "); + + str = "SELECT getDeptContactNumbers(sales_department.dept_info) "+ + "FROM sales_department where dept_id = 'DS02'"; + ResultSet rs = stmt.executeQuery(str); + System.out.println(); + System.out.println(str); + + String result = null; + while(rs.next()) + { + result = rs.getString(1); + System.out.println(" " + + Data.format(result, 1024) + " " ); + } + + rs.close(); + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + + } // scalarUDF + + //------------------------------------------------------------------------ + // 2. UDF Table function which takes an XML variable as input parameter + // and returns a table with XML values as output. + //------------------------------------------------------------------------- + + static void tableUDF(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + + System.out.println("-------------------------------"); + System.out.println("The store opens new branches in different "); + System.out.print(" parts of the city. The book store manager "); + System.out.print("wants to promote senior managers and associate "); + System.out.print("managers and designate them to manage these new "); + System.out.print("branches. He wants to update the skill level and "); + System.out.print("salaries of all the promoted managers in the "); + System.out.print("sales_employee table. He asks the DBA to create "); + System.out.print("a table function for this requirement. The DBA "); + System.out.print("creates the 'updatePromotedEmployeesInfo' "); + System.out.print("table function. This function updates the skill "); + System.out.print("level and salaries of the promoted managers in "); + System.out.print("sales_employee table and returns details of "); + System.out.println("all the managers who got promoted."); + System.out.println("-------------------------------"); + + System.out.println(); + String str = "CREATE FUNCTION updatePromotedEmployeesInfo(emp_id_p INTEGER) "+ + "RETURNS TABLE (name VARCHAR(50), emp_id integer, skill_level integer, "+ + "salary double, address XML) "+ + "LANGUAGE SQL "+ + "MODIFIES SQL DATA "+ + "SPECIFIC func1 "+ + "BEGIN ATOMIC "+ + "UPDATE sales_employee SET emp_details = XMLQuery('transform "+ + "copy $emp_info := $emp "+ + " modify if ($emp_info/employee[skill_level = 7 and "+ + " designation = \"Sr. Manager\"]) "+ + "then "+ + "( "+ + "do replace value of $emp_info/employee/skill_level with 8, "+ + "do replace value of $emp_info/employee/salary with "+ + " $emp_info/employee/salary * 9.5 "+ + ") "+ + "else if ($emp_info/employee[skill_level = 6 and "+ + " designation = \"Manager\"])"+ + "then "+ + "( "+ + "do replace value of $emp_info/employee/skill_level with 7, "+ + " do replace value of $emp_info/employee/salary with "+ + " $emp_info/employee/salary * 7.5 "+ + ") "+ + "else if ($emp_info/employee[skill_level = 5 and "+ + " designation = \"Associate Manager\"]) "+ + "then "+ + "( "+ + " do replace value of $emp_info/employee/skill_level with 6, "+ + " do replace value of $emp_info/employee/salary with "+ + " $emp_info/employee/salary * 5.5 "+ + ")"+ + "else ()"+ + "return $emp_info' PASSING emp_details as \"emp\") "+ + " WHERE emp_id = emp_id_p; "+ + " RETURN SELECT X.* "+ + "FROM sales_employee, XMLTABLE('$e_info/employee' PASSING "+ + " emp_details as \"e_info\" "+ + "COLUMNS "+ + "name VARCHAR(50) PATH 'name', "+ + "emp_id integer PATH '@id', "+ + "skill_level integer path 'skill_level', "+ + "salary double path 'salary', "+ + "addr XML path 'address') AS X WHERE sales_employee.emp_id = emp_id_p; "+ + "END"; + + stmt.executeUpdate(str); + System.out.println(str); + System.out.println(); + + System.out.println("Call the 'updatePromotedEmployeesInfo' table "); + System.out.println("function to update the details of promoted employees"); + System.out.println(" in 'sales_employee' table "); + + str = "SELECT A.* FROM sales_employee AS E, "+ + "table(updatePromotedEmployeesInfo(E.emp_id)) AS A"; + System.out.println(str); + + ResultSet rs = stmt.executeQuery(str); + String name = null; + int emp_id = 0; + int skill_level = 0; + int salary = 0; + String addr = null; + + System.out.println(); + System.out.println("name, emp_id, skill_level, salary, address"); + System.out.println("-----------------------------------------"); + while(rs.next()) + { + name = rs.getString(1); + emp_id = rs.getInt(2); + skill_level = rs.getInt(3); + salary = rs.getInt(4); + addr = rs.getString(5); + + System.out.println(" "+Data.format(name, 20)+" "+ + Data.format(emp_id, 10)+" "+Data.format(skill_level, 5)+" "+ + Data.format(salary, 20)+" "+Data.format(addr, 1024)+" "); + } + + rs.close(); + stmt.close(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // tableUDF + + //------------------------------------------------------------------------ + // 3. Sourced UDF which takes an XML variable as the input parameter + // and returns an XML value as output. + //------------------------------------------------------------------------ + + + static void sourcedUDF(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + + System.out.println("------------------------------------"); + System.out.println("The store manager would like to get a "); + System.out.println("particular dept manager name and his "); + System.out.println("contact numbers. The DBA then creates a "); + System.out.println("'getManagerDetails' UDF to get a particular "); + System.out.println("department manager name and manager contact details."); + System.out.println("------------------------------------"); + + System.out.println(); + String str = "CREATE FUNCTION getManagerDetails(dept_info_p XML, "+ + " dept_p VARCHAR(5)) "+ + "RETURNS XML "+ + "LANGUAGE SQL "+ + "SPECIFIC getManagerDetails "+ + "BEGIN ATOMIC "+ + "RETURN XMLQuery('for $dt in "+ + "$info/department[name=$dept_name] "+ + "return ({$dt/manager})' "+ + "PASSING dept_info_p as \"info\", dept_p as \"dept_name\");"+ + "END"; + + stmt.executeUpdate(str); + System.out.println(str); + + System.out.println("---------------------------------------------"); + System.out.println("Create a sourced UDF 'getManagerInfo' "); + System.out.println("based on 'getManagerDetails'user defined function "); + + + str = "CREATE FUNCTION getManagerInfo(XML, CHAR(10))"+ + "RETURNS XML "+ + "SOURCE getManagerDetails(XML, VARCHAR(5)) "; + stmt.executeUpdate(str); + System.out.println(str); + + System.out.println(); + System.out.println("Call the sourced UDF 'getManagerInfo' to get "); + System.out.println(" 'sales' department manager details "); + System.out.println("---------------------------------------------"); + + str = "SELECT getManagerInfo(sales_department.dept_info, 'sales') "+ + "FROM sales_department WHERE dept_id='DS02'"; + ResultSet rs = stmt.executeQuery(str); + System.out.println(str); + + String manager_details = null; + while(rs.next()) + { + manager_details = rs.getString(1); + System.out.println(" "+Data.format(manager_details, 1024)+" "); + } + + rs.close(); + stmt.close(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // sourcedUDF + + // ------------------------------------------------------------------------- + // 4. SQL bodied UDF which takes an XML variable as the input parameter + // and returns a table with XML values as output. This UDF + // calls a stored procedure which takes an XML variable + // as the input parameter and returns an XML value as output. + //-------------------------------------------------------------------------- + + + static void invokeSpFromUDF(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + System.out.println("---------------------------------------"); + System.out.println("Create a function which calculates an employee "); + System.out.println("gift cheque amount and adds this value as a new "); + System.out.println("element into the employee information document"); + System.out.println("---------------------------------------"); + + System.out.println(); + String str = "CREATE PROCEDURE calculateGiftChequeAmount( "+ + "INOUT emp_info_p XML, "+ + "IN emp_name_p VARCHAR(20)) "+ + "LANGUAGE SQL "+ + "MODIFIES SQL DATA "+ + "SPECIFIC giftcheque "+ + "BEGIN "+ + "DECLARE emp_bonus_info_v XML; "+ + "IF XMLEXISTS('$e_info/employee[name = $emp1]' PASSING "+ + "emp_info_p as \"e_info\","+ + "emp_name_p as \"emp1\")"+ + "THEN "+ + "SET emp_bonus_info_v = XMLQuery('copy $bonus := $info "+ + "modify "+ + "do insert {"+ + " $bonus/employee/salary * 0.50 + 25000} "+ + " into $bonus/employee "+ + "return $bonus' PASSING emp_info_p as \"info\"); "+ + "END IF; "+ + "SET emp_info_p = emp_bonus_info_v; "+ + "END "; + stmt.executeUpdate(str); + System.out.println(str); + + + System.out.println("----------------------------------------"); + System.out.print("Some employees who got customer appreciation "); + System.out.println("awards and whose total sales are greater "); + System.out.println("than expected sales were given gift cheques "); + System.out.println("by the store. The DBA creates "); + System.out.println("'calculatePerformanceBonus' function to "); + System.out.println("calculate employee performance bonus along with "); + System.out.println("customer gift cheque amount and update the "); + System.out.println("employee information in sales_employee table."); + System.out.println("----------------------------------------"); + + str = "CREATE FUNCTION calculatePerformanceBonus(sales_info_p XML) "+ + "RETURNS table(info XML) "+ + "LANGUAGE SQL "+ + "SPECIFIC awardedemployees "+ + "MODIFIES SQL DATA "+ + "BEGIN ATOMIC "+ + "DECLARE awarded_emp_info_v XML; "+ + "DECLARE emp_name VARCHAR(20); "+ + "DECLARE min_sales_v INTEGER; "+ + "DECLARE avg_sales_v INTEGER; "+ + "SET min_sales_v = XMLCAST(XMLQuery('$info/sales_per_annum/min_sales' "+ + "PASSING sales_info_p as \"info\") AS INTEGER); "+ + "SET avg_sales_v = XMLCAST(XMLQuery('$info/sales_per_annum/avg_sales' "+ + "PASSING sales_info_p as \"info\") AS INTEGER); "+ + "FOR_LOOP: FOR EACH_ROW AS "+ + "SELECT XMLCAST(XMLQuery('$info/employee/name' PASSING awarded_emp_info_v "+ + "as \"info\") AS VARCHAR(20)) as name, "+ + "XMLQuery('copy $e_info := $inf "+ + "modify "+ + "do insert {$e_info/employee/salary "+ + "* 0.25 + 5000} "+ + " into $e_info/employee "+ + "return $e_info' PASSING emp_details as \"inf\") "+ + "as info "+ + "FROM sales_employee "+ + "WHERE total_sales between min_sales_v and avg_sales_v "+ + "DO "+ + "SET awarded_emp_info_v = EACH_ROW.info; "+ + "SET emp_name = EACH_ROW.name; "+ + "CALL calculateGiftChequeAmount(awarded_emp_info_v, emp_name); "+ + "INSERT INTO performance_bonus_employees "+ + "VALUES (EACH_ROW.info); "+ + "END FOR; "+ + "RETURN SELECT * FROM performance_bonus_employees; "+ + "END "; + + + + stmt.executeUpdate(str); + System.out.println(str); + System.out.println("---------------------------------------------"); + System.out.println("Call the table function "); + System.out.println("'calculatePerformanceBonus' to get the "); + System.out.println("information of all the employees who got gift "); + System.out.println("cheques and performance bonus."); + System.out.println("---------------------------------------------"); + + str = "SELECT * FROM table(calculatePerformanceBonus(XMLPARSE(document "+ + "' "+ + "80000 "+ + "70000 "+ + "35000 "+ + "')))"; + ResultSet rs = stmt.executeQuery(str); + System.out.println(str); + System.out.println(); + + String bonus_info = null; + while(rs.next()) + { + bonus_info = rs.getString(1); + System.out.println(" "+Data.format(bonus_info, 1024)+" "); + } + + rs.close(); + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + } + catch(Exception e) + { + System.out.println(e); + } + } // invokeSpFromUdf + + + static void cleanUpTables(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + + String str = "DROP FUNCTION getDeptContactNumbers"; + stmt.executeUpdate(str); + + str = "COMMIT"; + stmt.executeUpdate(str); + + str = "DROP FUNCTION updatePromotedEmployeesInfo"; + stmt.executeUpdate(str); + + str = "COMMIT"; + stmt.executeUpdate(str); + + str = "DROP FUNCTION getManagerInfo"; + stmt.executeUpdate(str); + + str = "COMMIT"; + stmt.executeUpdate(str); + + str = "DROP FUNCTION calculatePerformanceBonus"; + stmt.executeUpdate(str); + + str = "COMMIT"; + stmt.executeUpdate(str); + + str = "DROP PROCEDURE calculateGiftChequeAmount"; + stmt.executeUpdate(str); + + str = "COMMIT"; + stmt.executeUpdate(str); + + str = "DROP TABLE sales_employee"; + stmt.executeUpdate(str); + + str = "COMMIT"; + stmt.executeUpdate(str); + + str = "DROP TABLE sales_department"; + stmt.executeUpdate(str); + + str = "COMMIT"; + stmt.executeUpdate(str); + + str = "DROP TABLE performance_bonus_employees"; + stmt.executeUpdate(str); + + str = "COMMIT"; + stmt.executeUpdate(str); + + str = "DROP FUNCTION getManagerDetails"; + stmt.executeUpdate(str); + + str = "COMMIT"; + stmt.executeUpdate(str); + + } + catch(Exception e) + { + System.out.println(e); + } + } // cleanUpTables +} // XmlUdfs + diff --git a/xml/java/jdbc/XmlUpDel.java b/xml/java/jdbc/XmlUpDel.java new file mode 100644 index 0000000..bbfb332 --- /dev/null +++ b/xml/java/jdbc/XmlUpDel.java @@ -0,0 +1,888 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlUpDel.java +// +// SAMPLE: How to update and delete XML data from table +// +// SQL Statements USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// Classes used from Util.java are: +// Db +// Data +// JdbcException +// +// PREREQUISITE : copy the files cust1021.xml, cust1022.xml and +// cust1023.xml to working directory before running the +// sample. These files can be found in xml/data +// directory. +// OUTPUT FILE: XmlUpDel.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.*; +import java.lang.*; +import java.sql.*; + +class XmlUpDel +{ + public static void main(String argv[]) + { + Connection con = null; + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO UPDATE AND DELETE XML TABLE DATA."); + + // connect to the 'sample' database + db.connect(); + + preRequisites(db.con); + mostSimpleUpdatewithConstantString(db.con); + UpdatewhereSourceisAnotherXmlColumn(db.con); + UpdatewhereSourceisAnotherStringColumn(db.con); + UpdateAnotherStringColumnWithImplicitParsing(db.con); + UpdateUsingVarcharWithImplicitParsing(db.con); + UpdatewhereSourceisBlobWithImplicitParsing(db.con); + UpdatewhereSourceisBlob(db.con); + UpdatewhereSourceisClob(db.con); + DeleteofRowwithXmlData(db.con); + rollbackChanges(db.con); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // main + + static void mostSimpleUpdatewithConstantString(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM A SIMPLE UPDATE."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=XMLPARSE(document'"+ + " rohitpark street\n" + + " delhi'"+ + " preserve whitespace)\n" + + " WHERE cid=1008\n" + + "\n"); + + + PreparedStatement stmt1 = con.prepareStatement( + "UPDATE customer" + + " SET info=XMLPARSE(document'rohit"+ + "park street" + + "delhi'preserve " + + "whitespace) WHERE cid=1008"); + + stmt1.execute(); + stmt1.close(); + + System.out.println(); + System.out.println(); + + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + // rs.close(); + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // mostSimpleUpdatewithConstantString + + static void UpdatewhereSourceisAnotherXmlColumn(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + // System.out.println(); + System.out.println( + "----------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + " TO PERFORM AN UPDATE WHERE SOURCE IS FROM ANOTHER XML COLUMN."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=(SELECT information FROM oldcustomer p\n" + + " WHERE p.ocid=1009)\n" + + " WHERE cid=1008\n" + + "\n"); + + PreparedStatement stmt1 = con.prepareStatement( + "UPDATE customer" + + " SET info=(SELECT information " + + " FROM oldcustomer p" + + " WHERE p.ocid=1009)" + + " WHERE cid=1008"); + stmt1.execute(); + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + // rs.close(); + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // UpdatewhereSourceisAnotherXmlColumn + + static void UpdatewhereSourceisAnotherStringColumn(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "-----------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM AN UPDATE WHERE SOURCE IS FROM ANOTHER STRING COLUMN."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=(SELECT XMLPARSE(document " + + " addr preserve whitespace)\n" + + " FROM oldcustomer p\n" + + " WHERE p.ocid=1009)\n" + + " WHERE cid=1008\n" + + "\n"); + + PreparedStatement stmt1 = con.prepareStatement( + "UPDATE customer" + + " SET info=(SELECT XMLPARSE(document addr preserve whitespace)" + + " FROM oldcustomer p" + + " WHERE p.ocid=1009)" + + " WHERE cid=1008"); + stmt1.execute(); + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + // rs.close(); + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // UpdatewhereSourceisAnotherStringColumn + + static void UpdateAnotherStringColumnWithImplicitParsing(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "--------------------------------------------\n\n" + + " USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + " TO PERFORM AN UPDATE WHERE SOURCE IS FROM "+ + " ANOTHER STRING COLUMN" + + " WITH IMPLICIT PARSING."); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=SELECT addr " + + " FROM oldcustomer p\n" + + " WHERE p.ocid=1009)\n" + + " WHERE cid=1008\n" + + "\n"); + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE customer " + + "SET info=(SELECT addr " + + "FROM oldcustomer p " + + "WHERE p.ocid=1009) " + + "WHERE cid=1008"); + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con, 1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } //UpdateAnotherStringColumnWithImplicitParsing + + static void UpdateUsingVarcharWithImplicitParsing(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM A UPDATE USING VARCHAR WITH IMPLICIT PARSING."); + + // display the content of the 'customer' table + // CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info='"+ + " rohitpark street\n" + + " delhi'" + + " WHERE cid=1008\n" + + " \n"); + + + Statement stmt = con.createStatement(); + stmt.executeUpdate( + "UPDATE customer " + + "SET info = ' "+ + "rohitpark street"+ + "delhi' "+ + "WHERE cid=1008"); + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } //UpdateUsingVarcharWithImplicitParsing + + static void UpdatewhereSourceisBlobWithImplicitParsing(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + String xsdData = new String(); + xsdData=returnFileValues("cust1021.xml"); + byte[] Array=xsdData.getBytes(); + + // Create a BLOB object + java.sql.Blob blobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(Array); + + System.out.println(); + System.out.println( + "-------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM AN UPDATE WHERE SOURCE IS A BLOB VARIABLE"+ + " WITH IMPLICIT PARSING \n"); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET INFO= :blobData " + + " WHERE cid=1008\n" + + "\n"); + + PreparedStatement pstmt = con.prepareStatement( + " UPDATE customer SET INFO = " + + " cast(? as Blob)" + + " WHERE cid=1008"); + pstmt.setBlob(1, blobData); + pstmt.execute(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con, 1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } //UpdatewhereSourceisBlobWithImplicitParsing + + static void UpdatewithValidation(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "-----------------------------------------------\n\n" + + " USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + " TO PERFORM AN UPDATE WITH VALIDATION WHERE " + + " SOURCE IS TYPED OF VARCHAR."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=(SELECT XMLVALIDATE(XMLPARSE"+ + " (document addr preserve whitespace)\n" + + " according to XMLSCHEMA ID customer)\n" + + " FROM oldcustomer p\n" + + " WHERE p.ocid=1009)\n" + + " WHERE cid=1008\n" + + "\n"); + + PreparedStatement stmt1 = con.prepareStatement( + "UPDATE customer" + + " SET info=(SELECT XMLVALIDATE(XMLPARSE(document " + + " addr preserve whitespace)" + + " according to XMLSCHEMA ID customer)" + + " FROM oldcustomer p" + + " WHERE p.ocid=1009)" + + " WHERE cid=1008"); + stmt1.execute(); + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + // rs.close(); + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // UpdatewithValidation + + static void UpdatewhereSourceisBlob(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + String xsdData = new String(); + xsdData=returnFileValues("cust1022.xml"); + byte[] Array=xsdData.getBytes(); + // Create a BLOB object + + java.sql.Blob blobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(Array); + + System.out.println(); + System.out.println( + "------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM AN UPDATE WHERE SOURCE IS A BLOB VARIABLE."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET INFO= XMLPARSE(document " + + " cast(? as Blob) strip whitespace)\n" + + " WHERE cid=1008\n" + + "\n"); + + + PreparedStatement pstmt = con.prepareStatement( + "UPDATE customer " + + "SET INFO=XMLPARSE(document cast(? as Blob) strip whitespace)" + + " WHERE cid=1008"); + + System.out.println(); + + pstmt.setBlob(1, blobData); + + System.out.println(" Execute prepared statement"); + pstmt.execute(); + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + pstmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // UpdatewhereSourceisBlob + + static void UpdatewhereSourceisClob(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + String Data = new String(); + Data=returnFileValues("cust1023.xml"); + + // Create a CLOB object + + java.sql.Clob clobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createClob(Data); + + System.out.println(); + System.out.println( + "------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM AN UPDATE WHERE SOURCE IS A CLOB VARIABLE."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + System.out.println(); + + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET INFO= XMLPARSE(document " + + " cast(? as Clob) strip whitespace)\n" + + " WHERE cid=1008\n" + + "\n"); + + PreparedStatement pstmt = con.prepareStatement( + "UPDATE customer " + + "SET INFO=XMLPARSE(document cast(? as Clob) strip whitespace)" + + " WHERE cid=1008"); + + System.out.println(" Set parameter value: parameter 1 = " + "clobData" ); + + pstmt.setClob(1, clobData); + + System.out.println(" Execute prepared statement"); + pstmt.execute(); + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + pstmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // UpdatewhereSourceisClob + + // helping function + static void preRequisites(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + // create table 'oldcustomer' + stmt.executeUpdate( + "CREATE TABLE oldcustomer(ocid integer," + + "firstname varchar(15)," + + "lastname varchar(15)," + + "addr varchar(300)," + + "information XML)"); + + stmt.close(); + + // populate table oldcustomer with data + Statement stmt3 = con.createStatement(); + stmt3.executeUpdate( + "INSERT INTO oldcustomer " + + "VALUES(1009,'Rahul','kumar'," + + "'Rahul25Markham" + + " OntarioN9C-3T6" + + " 905-555-7258" + + "'," + + "XMLPARSE(document '" + + "
25 Westend" + + "MarkhamOntario"+ + "
'preserve whitespace))"); + + stmt3.close(); + + // populate table customer with data + Statement stmt2 = con.createStatement(); + stmt2.executeUpdate( + "INSERT INTO customer(cid,info) " + + "VALUES(1008,XMLPARSE(document '" + + "divya' preserve whitespace))"); + + stmt2.close(); + + // Commit + con.commit(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // PreRequisites + + // helping function + static void CustomerTbContentDisplay(Connection con,int Cid) + { + try + { + int customerid = 0; + String customerInfo = ""; + + // prepare the query + System.out.println(); + System.out.println( + " Prepare Statement:\n" + + " SELECT cid,XMLSERIALIZE(info as varchar(600))\n" + + " FROM customer WHERE cid=" + "Cid"); + + PreparedStatement pstmt = con.prepareStatement( + "SELECT cid,XMLSERIALIZE(info as varchar(600)) " + + "FROM customer WHERE cid = ?"); + + System.out.println(); + System.out.println(" Set parameter value: parameter 1 = " + Cid); + + pstmt.setInt(1, Cid); + + System.out.println(); + System.out.println(" Execute prepared statement"); + ResultSet rs = pstmt.executeQuery(); + + + System.out.println( + " CUSTOMERID CUSTOMERINFO \n" + + " ---------- -------------- "); + + + // retrieve and display the result from the SELECT statement + while (rs.next()) + { + customerid = rs.getInt(1); + customerInfo = rs.getString(2); + + System.out.println( + " " + + Data.format(customerid, 10) + " " + + Data.format(customerInfo, 600)); + } + + rs.close(); + pstmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // CustomerTableContentDisplay + + + // this function will Read a file in a buffer and + // return the String value to cal + public static String returnFileValues(String fileName) + { + String record = null; + try + { + FileReader fr = new FileReader(fileName); + BufferedReader br = new BufferedReader(fr); + record = new String(); + record = br.readLine(); + String descReturn=record; + while ((record = br.readLine()) != null) + descReturn=descReturn+record; + return descReturn; + } + catch (IOException e) + { + // catch possible io errors from readLine() + System.out.println(" file " + fileName + "doesn't exist"); + + System.out.println(" Quitting program!"); + System.out.println(); + System.exit(-1); + } + return null; + }// returnFileValues + + static void DeleteofRowwithXmlData(Connection con) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "-------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO PERFORM A DELETION OF ROWS WITH XML DATA."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " DELETE FROM customer\n" + + " WHERE cid=1008\n" + + "\n"); + + PreparedStatement stmt1 = con.prepareStatement( + "DELETE FROM customer" + + " WHERE cid=1008"); + stmt1.execute(); + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(con,1008); + + // rs.close(); + stmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // DeleteofRowwithXmlData + + static void rollbackChanges(Connection con) + { + try + { + PreparedStatement stmt1 = con.prepareStatement( + "DROP TABLE oldcustomer"); + stmt1.execute(); + stmt1.close(); + + // Commit + con.commit(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try {con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(Exception e) + {} + } // rollbackChanges +} diff --git a/xml/java/jdbc/XsUpdate.java b/xml/java/jdbc/XsUpdate.java new file mode 100644 index 0000000..653d2c9 --- /dev/null +++ b/xml/java/jdbc/XsUpdate.java @@ -0,0 +1,310 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: XsUpdate.java +// +// PURPOSE: To demonstrate how to update an existing XML schema with +// a new schema that is compatible with the original schema. +// +// USAGE SCENARIO: A store manager maintains product details in an XML +// document that conforms to an XML schema. The product +// details are: Name, SKU and Price. The store manager +// wants to add a product description for each of the +// products along with the existing product details. +// +// PREREQUISITE: The original schema and the new schema should be +// present in the same directory as the sample. +// Copy prod.xsd, newprod.xsd from directory +// /xml/data to the working directory. +// +// EXECUTION: i) javac XsUpdate.java (compile the sample) +// ii) java XsUpdate.class (run the sample) +// +// INPUTS: NONE +// +// OUTPUTS: Updated schema and successful insertion of XML +// documents with the new product descriptions. +// +// OUTPUT FILE: XsUpdate.out (available in the online documentation) +// +// SQL Statements USED: +// CREATE +// INSERT +// DROP +// +// Stored Procedures USED: +// SYSPROC.XSR_REGISTER +// SYSPROC.XSR_COMPLETE +// SYSPROC.XSR_UPDATE +// +// SQL/XML Functions USED: +// XMLVALIDATE +// XMLPARSE +// +// ************************************************************************* +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +// *************************************************************************/ +// +// SAMPLE DESCRIPTION +// +// /************************************************************************* +// 1. Register the original schema with product details:Name, SKU and Price. +// 2. Register the new schema containing the product description element +// along with the existing product details. +// 3. Call the XSR_UPDATE stored procedure to update the original schema. +// 4. Insert an XML document containing the product description elements. +// *************************************************************************/ + +// import the required classes +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; + +class XsUpdate +{ + + // /************************************************************************* + // SETUP + // **************************************************************************/ + public static String relSchema=new String("STORE"); + public static String schemaName=new String("PROD");; + public static String schemaLocation= new String("http://product"); + public static String primaryDocument= new String("prod.xsd"); + + public static String newSchemaName=new String("NEWPROD");; + public static String newSchemaLocation= new String("http://newproduct"); + public static String newPrimaryDocument= new String("newprod.xsd"); + + public static int shred = 0; + + public static String xmlData1 = new String("Ice Scraper, Windshield 4 inchstores999Ice Scraper, Windshield 8 inchstores1999Ice Scraper, Windshield 5 inchstores1299"); + + public static String xmlData2 = new String("Ice Scraper, Windshield 4 inchstores999A new prodIce Scraper, Windshield 8 inchstores1999A new prodIce Scraper, Windshield 5 inchstores1299"); + + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the Sample database + con = DriverManager.getConnection( url ); + System.out.println("\n Connected to Sample database \n"); + + // create a table for storing product details + Statement create1 = con.createStatement(); + create1.executeUpdate("CREATE TABLE store.products(id INT GENERATED ALWAYS AS IDENTITY,plist XML)"); + + // /************************************************************************* + // 1. Register the original schema with product details: Name, SKU and Price. + // *************************************************************************/ + + // register the XML Schema + registerXmlSchema(con,schemaName,schemaLocation,primaryDocument); + + // insert data into the table validating against the schema STORE.PROD + PreparedStatement prepStmt=con.prepareStatement("INSERT INTO store.products(plist) " + + "VALUES(xmlvalidate(cast(? as XML) ACCORDING TO XMLSCHEMA ID store.prod))"); + prepStmt.setString(1,xmlData1); + System.out.println("Inserting data into table validating against the schema: STORE.PROD"); + prepStmt.executeUpdate(); + + // select data from the table + com.ibm.db2.jcc.DB2Xml outData = null; + PreparedStatement stmt1 = con.prepareStatement("SELECT * FROM STORE.PRODUCTS"); + ResultSet rs1 = stmt1.executeQuery(); + System.out.println("\n Inserted Data is: "); + while(rs1.next()) + { + outData = (DB2Xml) rs1.getObject(2); + System.out.println(outData.getDB2XmlString()); + } + rs1.close(); + + // /************************************************************************** + // 2. Register the new schema containing the product description element + // along with the existing product details. + // **************************************************************************/ + + // register the new XML Schema + registerXmlSchema(con,newSchemaName,newSchemaLocation,newPrimaryDocument); + + // /************************************************************************* + // 3. Call the XSR_UPDATE stored procedure to update the original schema. + // **************************************************************************/ + + // update the original schema to reflect the changes in the new schema + updateXmlSchema(con,schemaName,newSchemaName); + + // /************************************************************************* + // 4. Insert an XML document containing the product description elements. + // **************************************************************************/ + + // insert data into the table validating against the updated XML schema STORE.PROD + System.out.println("Inserting data into table validating against the " + + "updated schema: STORE.PROD"); + prepStmt.setString(1,xmlData2); + prepStmt.executeUpdate(); + prepStmt.close(); + + // check whether data is inserted or not + ResultSet rs2 = stmt1.executeQuery(); + System.out.println("\n Inserted Data is: "); + while(rs2.next()) + { + outData = (DB2Xml) rs2.getObject(2); + System.out.println(outData.getDB2XmlString()); + } + rs2.close(); + // drop the created objects + cleanUp(con); + con.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// main + + // Method to register an XML Schema + static void registerXmlSchema(Connection con,String schName,String schLoc,String schDoc) + { + try + { + // register XML Schema + System.out.println("\nRegistering Schema "+ relSchema + "." +schName +"..."); + CallableStatement callStmt = con.prepareCall("CALL SYSPROC.XSR_REGISTER(?,?,?,?,NULL)"); + File xsdFile = new File(schDoc); + FileInputStream xsdData = new FileInputStream(xsdFile); + callStmt.setString(1, relSchema); + callStmt.setString(2, schName); + callStmt.setString(3, schLoc); + callStmt.setBinaryStream(4, xsdData, (int)xsdFile.length() ); + callStmt.execute(); + xsdData.close(); + + // complete the registration + System.out.println("Completing XML Schema registration..."); + callStmt=con.prepareCall("CALL SYSPROC.XSR_COMPLETE(?,?,NULL,?)"); + callStmt.setString(1, relSchema); + callStmt.setString(2, schName); + callStmt.setInt(3, shred); + callStmt.execute(); + System.out.println("Schema "+ relSchema + "." +schName +" registered successfully \n\n"); + callStmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch(IOException ioe) + { + System.out.println("Error opening file " + schDoc); + } + }// registerXmlSchema + + // Method to update an XML schema + static void updateXmlSchema(Connection con,String schName,String newSchName) + { + try + { + System.out.println(" Updating the Schema "+ relSchema + "." +schName +"..."); + CallableStatement callStmt = con.prepareCall("CALL SYSPROC.XSR_UPDATE(?,?,?,?,1)"); + callStmt.setString(1,relSchema); + callStmt.setString(2,schName); + callStmt.setString(3,relSchema); + callStmt.setString(4,newSchName); + callStmt.execute(); + System.out.println(" Updated the schema "+ relSchema + "." + schName + " successfully \n\n"); + callStmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } //updateXmlSchema + + // Method to drop the created objects + static void cleanUp(Connection con) + { + try + { + Statement stmt=con.createStatement(); + String query1="DROP XSROBJECT STORE." + schemaName; + String query2="DROP TABLE STORE.PRODUCTS"; + System.out.println("\n\n"+query1); + stmt.executeUpdate(query1); + System.out.println(query2); + stmt.executeUpdate(query2); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // cleanUp +} // XsUpdate + diff --git a/xml/java/jdbc/makefile b/xml/java/jdbc/makefile new file mode 100644 index 0000000..aa5b859 --- /dev/null +++ b/xml/java/jdbc/makefile @@ -0,0 +1,204 @@ +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# +# MAKEFILE for XML JDBC samples on Unix +# +# Enter one of the following commands +# +# make - Builds the program designated by . +# +# make all - Builds all supplied sample programs except GSS API +# plugin samples. +# +# make srv - Builds samples that can only be run on the server, +# includes stored procedures. +# +# make call_srv - Builds all client programs that call stored +# procedures. +# +# make all_client - Builds all client samples (all programs in the +# 'call_srv' and 'client_run' categories). +# +# make client_run - Builds all programs that run completely on the +# client (not ones that call stored procedures). +# +# make clean - Erases all intermediate files produced in the +# build process. +# +# make cleanall - Erases all files produced in the build process +# (all files except the original source files). +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +############################################################################## +# 1 -- VARIABLES +############################################################################## + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +COPY=cp +ERASE=rm -f + +############################################################################# +# Generic rule to make a class from a java source file +############################################################################# + +.SUFFIXES : .class .java + +.java.class : + javac $< + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all (srv + all_client) +# 2b - make all_client +# 2c - make srv +# 2d - make call_srv +# 2e - make client_run +# 2f - make clean +# 2g - make cleanall +############################################################################# + +#**************************************************************************** +# 2a - make all (srv + all_client) +#**************************************************************************** + +all : \ + srv \ + all_client + +#**************************************************************************** +# 2b - make all_client (call_srv + client_run) +#**************************************************************************** + +all_client : \ + call_srv \ + client_run + +#**************************************************************************** +# 2c - make srv +#**************************************************************************** + +srv : \ + Simple_XmlProc + +#**************************************************************************** +# 2d - make call_srv +#**************************************************************************** + +call_srv : \ + Simple_XmlProc_Client + +#**************************************************************************** +# 2e - make client_run +#**************************************************************************** + +client_run : \ + XmlSchema XmlRunstats XmlIndex XmlConst XmlInsert XmlUpDel \ + XmlRead RelToXmlDoc RelToXmlType XmlToTable \ + XmlDecomposition XsUpdate RecXmlDecomp XmlCheckConstraint \ + XmlTrig XmlUdfs XmlMdc + +#**************************************************************************** +# 2f - make clean +#**************************************************************************** + +clean : + $(ERASE) *.class + +#**************************************************************************** +# 2g - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) $(DB2PATH)/function/Simple_XmlProc.class + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - standalone applications +# 3b - client/server applications +############################################################################# + + +#**************************************************************************** +# 3a - standalone applications +#**************************************************************************** + +XmlSchema : XmlSchema.class + +XmlRunstats : Util.class XmlRunstats.class + +XmlIndex : Util.class XmlIndex.class + +XmlConst : Util.class XmlConst.class + +XmlInsert : Util.class XmlInsert.class + +XmlUpDel : Util.class XmlUpDel.class + +XmlToTable : Util.class XmlToTable.class + +XmlRead : Util.class XmlRead.class + +RelToXmlDoc : Util.class RelToXmlDoc.class + +RelToXmlType : Util.class RelToXmlType.class + +XmlDecomposition : Util.class XmlDecomposition.class + +XsUpdate : Util.class XsUpdate.class + +RecXmlDecomp : Util.class RecXmlDecomp.class + +XmlCheckConstraint : Util.class XmlCheckConstraint.class + +XmlTrig : Util.class XmlTrig.class + +XmlUdfs: Util.class XmlUdfs.class + +XmlMdc: Util.class XmlMdc.class + +#**************************************************************************** +# 3b - client/server applications +#**************************************************************************** + +#-----------------Simple_XmlProc_Client / Simple_XmlProc--------------------------# +# Note: before you execute Simple_XmlProc_Client for the first time, you must call the +# Simple_XmlProc_Create.db2 CLP script to catalog the methods in Simple_XmlProc as stored +# procedures. Call Simple_XmlProc_Drop.db2 to uncatalog the methods in Simple_XmlProc. + +SpCat : + spcat_xml + +Simple_XmlProc_Client : Util.class Simple_XmlProc_Client.class + +Simple_XmlProc : Simple_XmlProc.class + $(ERASE) $(DB2PATH)/function/Simple_XmlProc.class + $(COPY) Simple_XmlProc.class $(DB2PATH)/function + spcat_xml + diff --git a/xml/java/jdbc/reltoxmlproc.db2 b/xml/java/jdbc/reltoxmlproc.db2 new file mode 100644 index 0000000..50846a3 --- /dev/null +++ b/xml/java/jdbc/reltoxmlproc.db2 @@ -0,0 +1,79 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: reltoxmlproc.db2 +-- +-- SAMPLE: This stored procedure uses the constructor functions to create an XML +-- document with all the purchase order details. The input to the constructor +-- function will be the relational data stored in the tables. The final +-- output of the constructor functions will be a well formed XML document having +-- all the purchase orders. The stored procedure will return the purchase order +-- XML document back to the application. +-- +-- This stored procedure will be called by samples +-- a)reltoxmldoc.db2 +-- b)reltoxmldoc.sqc +-- +-- SQL STATEMENTS USED: +-- CREATE PROCEDURE +-- OPEN +-- +-- OUTPUT FILE: NA +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CONNECT TO SAMPLE@ +CREATE PROCEDURE reltoxmlproc() +RESULT SETS 1 +LANGUAGE SQL +BEGIN +DECLARE C1 CURSOR WITH RETURN FOR +SELECT po.PoNum, po.CustID, po.OrderDate, XMLCONCAT( XMLPI(NAME "pi", 'MESSAGE("valid, well-formed d +ocument")'), +XMLELEMENT (NAME "PurchaseOrder", XMLNAMESPACES( 'http://www.example.org' AS "e"), +XMLATTRIBUTES (po.CustID as "CustID", po.PoNum as "PoNum", po.OrderDate as "OrderDate", po.Status as "Status" ), + XMLELEMENT (NAME "CustomerAddress", XMLCONCAT( + XMLELEMENT (NAME "e.Name", c.Name ), + XMLELEMENT (NAME "e.Street", c.Street ), + XMLELEMENT (NAME "e.City", c.City ), + XMLELEMENT (NAME "e.Province", c.Province ), + XMLELEMENT (NAME "e.PostalCode", c.PostalCode ) ) ), + XMLELEMENT (NAME "ItemList" , +XMLELEMENT (NAME "Item", +XMLELEMENT (NAME "PartId", l.ProdID ), +XMLELEMENT (NAME "Description", p.Description ), +XMLELEMENT (NAME "Quantity", l.Quantity ), +XMLELEMENT (NAME "Price", p.Price ) , +XMLCOMMENT(po.comment) ) ) ) ) +FROM PurchaseOrder_Relational as Po, CustomerInfo_Relational AS c, Lineitem_Relational AS l, Products_Relational AS p +WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID +ORDER BY po.PoNum; +OPEN C1; +END@ + diff --git a/xml/java/jdbc/spcat_xml b/xml/java/jdbc/spcat_xml new file mode 100644 index 0000000..2306ebf --- /dev/null +++ b/xml/java/jdbc/spcat_xml @@ -0,0 +1,31 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: spcat_xml +# To catalog JDBC stored procedures on UNIX +# Catalogs the stored procedures in the Simple_XmlProc library +# Simple_XmlProc_Drop.db2 uncatalogs the stored procedures if previously cataloged +# Simple_XmlProc_Create.db2 catologs the stored procedures +# Both CLP scripts can be run on their own +# Usage: spcat_xml + +db2 -td@ -vf Simple_XmlProc_Drop.db2 +db2 -td@ -vf Simple_XmlProc_Create.db2 + diff --git a/xml/java/sqlj/README b/xml/java/sqlj/README new file mode 100644 index 0000000..41106ee --- /dev/null +++ b/xml/java/sqlj/README @@ -0,0 +1,463 @@ +******************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +******************************************************************************** +* +* README for SQLj XML Samples +* +* For windows, the \sqllib\samples\xml\java\sqlj directory +* contains this README file. +* For unix, /sqllib/samples/xml/java/sqlj directory contain +* this README file. +* This README describes how to build and run sqlj sample code for DB2 9.7. +* The DB2 9.7 sqlj sample are located in the +* \sqllib\samples\xml\java\sqlj directory for windows platform +* and /sqllib/samples/xml/java/sqlj for unix based platforms. +* where is the location of DB2 9.7 on your hard drive. The +* default location for is C:\Program Files\IBM for windows +* and $HOME for unix based platform. +* +* Copy the files from this directory to your working directory prior to +* building the sample programs. The sample programs directory is +* typically read-only on most platforms and some samples produce output +* files that require write permissions on the directory. +* +* WARNINGS: +* 1. Some of these samples may change your database or database +* manager configuration. Execute the samples against a test database +* only, such as the DB2 SAMPLE database. +* +******************************************************************************* +* +* Prepare your DB2 sample development environment +* +* 1) Copy the files in \sqllib\samples\xml\java\sqlj\* (for +* windows platform) or /sqllib/samples/xml/java/sqlj/* +* (for UNIX based platform) to your working directory and ensure that +* directory has write permission. +* +* 2) Modify the CLASSPATH. +* For Windows include +* \sqllib\java\db2java.zip +* \sqllib\java\db2jcc.jar +* \sqllib\java\db2jcc_license_cu.jar +* \sqllib\java\jdk\lib +* \sqllib\lib +* \sqllib\function +* \sqllib\java\sqlj.zip +* +* For UNIX based platform include +* /sqllib/java/db2java.zip +* /sqllib/java/db2jcc.jar +* /sqllib/java/db2jcc_license_cu.jar +* /sqllib/java/jdk/lib +* /sqllib/lib +* /sqllib/function +* /sqllib/java/sqlj.zip +* +* Modify the PATH. +* For Windows include +* \sqllib\java\\bin +* \sqllib\lib +* where is the name of the java directory. +* +* For UNIX include +* /sqllib/java//bin +* /sqllib/lib +* where is the name of the java directory. +* +* Please make sure that JDK_PATH( db2 +* database manager configuration parameter) is +* pointing to the \sqllib\java\ for windows +* and /sqllib/java/ for unix platform. +* +* To see the dbm cfg parameter value, run the following from db2 +* command window (open the db2 command window from +* Start -> Run -> db2cmd for windows platform) and look for the value +* of JDK_PATH +* +* db2 "get dbm cfg" +* +* 3). Enable tcpip: +* db2set DB2COMM=tcpip +* db2stop +* db2start +* +* 4). By default, your database configuration parameter SVCENAME is +* set to an available port_number. If it is not, update the database +* configuration with an available port number using the following +* command: +* db2 update dbm cfg using SVCENAME +* where is an available port_number. +* +* After you have updated the database configuration manually, you have +* to restart DB2 using the following commands: +* db2 terminate +* db2stop +* db2start +* +* 5) Create the sample database with the following command: +* db2sampl -xml +* +* 6) Connect to the database with the following command: +* db2 "connect to sample" +* +* 7) cd to the directory containing the files copied in step 1. +* +* +******************************************************************************* +* +* Building DB2 Samples +* +* There are two ways to build DB2 samples: using a nmake utility for windows +* (make utility for unix based platform) or using the SQLj precompiler and +* java compiler which comes along with the DB2 installation +* +* o To build samples using the nmake utility for windows see +* 'BUILDING SAMPLES USING nmake UTILITY on WINDOWS'. +* o To build samples using the make utility for unix see +* 'BUILDING SAMPLES USING make UTILITY on UNIX'. +* o To build samples using the java compiler or when you do not +* have a compatible nmake utility see 'BUILDING +* SAMPLES USING SQLj PRECOMPILER AND JAVA COMPILER'. +* +* NOTE : +* +* 1. Some of the samples might need one or more data files at runtime. +* some of the samples may also need setup script to be run before +* running the sample.See the specific sample descriptions in +* "File Descriptions" section for more details. +* +* +* 2. There are utility files available in this directory that are used +* by these samples for error checking. Please make sure that these +* files are present in you working directory. The information +* about these files can be found in "File Descriptions" section of this +* README. +* +* 3. Refer to the "File Descriptions" section in this README for +* information on specific samples and any special considerations +* relevant for each. The HEADER sections of these samples also provide +* further details on each sample. +* +******************************************************************************* +* +* *** BUILDING SAMPLES USING nmake UTILITY on WINDOWS *** +* +* If you have a compatible nmake utility on your system, you +* can use the makefile provided. Such a nmake utility may be +* provided by another language compiler.Modify the PATH +* variable to include the directory containing the nmake +* utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'nmake' command in your working +* directory: +* +* nmake - Builds the program designated by . +* +* nmake all - Builds all supplied sample programs +* +* nmake clean - Erases all intermediate files produced in the +* build process. +* +* nmake cleanall - Erases all files produced in the build process +* (all files except the original source files). +* +******************************************************************************* +* +* *** BUILDING SAMPLES USING make UTILITY on UNIX *** +* +* If you have a compatible make utility on your system, you +* can use the makefile provided. Modify the PATH +* variable to include the directory containing the make +* utility. +* +* Depending on your environment, the makefile might have to be +* modified.For more details refer to the 'VARIABLES' section +* in the makefile. +* +* Execute the appropriate 'make' command in your working +* directory: +* +* make - Builds the program designated by . +* +* make all - Builds all supplied sample programs +* +* make clean - Erases all intermediate files produced in the +* build process. +* +* make cleanall - Erases all files produced in the build process +* (all files except the original source files). +* +******************************************************************************* +* +* *** BUILDING SAMPLES USING SQLj PRECOMPILER AND JAVA COMPILER *** +* +* If you do not have a compatible make utility you can use +* the SQLj precompiler and javac bytecode compiler to build SQLj +* programs. +* +* These samples use classes in Util.sqlj. Build the Util.sqlj program +* using the following command. +* +* bldsqlj Util +* +* Note: +* When you build SQLj programs with the build files, do not +* include the file extension for the program name. +* +* Like the SQLj makefile, the SQLj build files need to be +* updated with a valid user ID, password and an available +* port number. +* +* bldsqlj - Builds an SQLj program. Here is the usage of +* this build file: +* +* bldsqlj (requires hardcoding user ID and +* password in the bldsqlj.bat file) +* bldsqlj +* bldsqlj +* bldsqlj +* +* bldsqlj +* +* +* Where, +* o - the name of the sample program without the +* .sqlj extension. +* o - user ID needed connect to the database. +* o - password needed to connect to the +* database. +* o - server's name that you work with. +* o - an available port_number on the server. +* o - the name of the database where the SQL +* package will be created. The default is +* "sample". +* +* To build a individual sqlj sample, use the following command +* +* sqlj .sqlj +* +* To run the sample, use the following command +* +* java +* +******************************************************************************* +* +* Common file Descriptions +* +* The following are the common files for SQLj samples. For more +* information on these files, refer to the program source files. +* +******************************************************************************* +* +* Common file Descriptions +* +* bldsqlj - build file for application programs +* Util.sqlj - utilities used by most programs. +* README - This file +* makefile - makefile for all files +* +******************************************************************************* +* +* SQLj Sample Descriptions +* +* The following are the SQLj sample files included with DB2. For more +* information on the sample programs, refer to the program source files. +* +******************************************************************************* +* +* Sample Files +* +* XmlSchema.sqlj - How to register an XML schema to a database using +* stored procedures. How to use this registered schema +* to validate an XML value before inserting into +* a table. +* +* PREREQUISITE: copy product.xsd, order.xsd, +* customer.xsd, header.xsd Schema files, order.xml XML +* document from xml/data directory to working +* directory. +* +* XmlRead.sqlj - How to read XML data stored in tables. +* +* XmlInsert.sqlj - How to insert XML data into tables having an XML +* column. +* +* PREREQUISITE: copy the files expPrg1.xml and +* expPrg.xml to working directory before running the +* sample. These files can be found in xml/data +* directory. +* Run the script XmlInsert_setup.db2 before +* running this sample. Run the XmlInsert_cleanup.db2 +* script to cleanup the database objects after running +* the sample. +* +* XmlUpDel.sqlj - How to update and delete XML documents in tables. +* +* PREREQUISITE: copy the files expPrg1.xml and +* expPrg.xml to working directory before running the +* sample. These files can be found in xml/data +* directory. +* Run the script XmlUpDel_setup.db2 before +* running this sample. Run the XmlUpDel_cleanup.db2 +* script to cleanup the database objects after running +* the sample. +* +* XmlConst.sqlj - How to put constraints on an XML column. +* NOTE : This sample demonstrate the how to enforce the +* constraints on an XML value. There are some statement +* in the samples which are expected to fail because of +* constraint violation so The sql error SQL803N, +* SQL20305N and SQL20306N are expected. +* +* XmlIndex.sqlj - How to create an index on a table with XML type +* columns and how to query using XQUERY on the +* index created. +* +* RelToXmlDoc.sqlj - How to create XML object from data stored in +* relational tables using various SQL/XML Constructor +* functions. The XML object is created using stored +* procedure. +* +* PREREQUISITE: This sample uses a stored procedure. +* Stored procedure should be registered before running +* the sample. Follow the step given in the header of +* the sample for more details. +* Run the scripts cleanupscript.db2 and +* setupscript.db2 before running this sample. +* Run the cleanupscript.db2 script to cleanup the +* database objects after running the sample. +* These scripts can be found in xml/data directory. +* +* RelToXmlType.sqlj - How to create XML object from data stored in +* relational tables using various SQL/XML Constructor +* functions. +* +* PREREQUISITE: Run the script setupscript.db2 before +* running this simple. Run the cleanupscript.db2 +* script to cleanup the database objects after running +* the sample. These scripts can be found in xml/data +* directory. +* +* XmlToTable.sqlj - How to insert the data from XML document to a +* relational table using XML Constructor function and +* SQL/XML functions. +* +* PREREQUISITE: copy purchaseorder.xml XML document +* from xml/data directory to the working directory. +* Run the script XmlToTable_setup.db2 before running +* this sample. +* Run the XmlToTable_cleanup.db2 script +* to cleanup the database objects after running the +* sample. +* +* XmlXslt.sqlj - How to convert XML document from one form to another +* using XSL stylesheets. +* +* PREREQUISITE: Run the script XmlXslt_setup.db2 before +* running this sample. Run the XmlXslt_cleanup.db2 +* script to cleanup the database objects after running +* the sample. +* +* +* XmlIntegrate.sqlj - How to use XMLROW and XMLGROUP functions to publish +* relational information as XML. Also,to show XMLQuery +* default passing mechanism and default column +* specification for XMLTABLE. +* +* PREREQUISITE: Run the script XmlIntegrate_setup.db2 +* before running this sample. Run the +* XmlIntegrate_cleanup.db2 script to cleanup the +* database objects after running the sample. +* +******************************************************************************* +* Setup and Cleanup Scripts Used +******************************************************************************* +* +* RelToXmlScrpt - CLP script present in the xml/data directory that +* calls two scripts cleanupscript.db2 and +* setupscript.db2 respectively also present in the +* xml/data directory +* +* setupscript.db2 - CLP script that issues CREATE TABLE and INSERT TABLE +* statements for the samples RelToXmlDoc.sqlj and +* RelToXmlType.sqlj +* +* cleanupscript.db2 - CLP script that issues DROP TABLE statements for the +* samples RelToXmlDoc.sqlj and RelToXmlType.sqlj +* +* XmlInsertScrpt - CLP script that calls two scripts XmlInsert_cleanup.db2 +* and XmlInsert_setup.db2 respectively +* +* XmlInsert_setup.db2 - CLP script that issues CREATE TABLE statements for the +* sample XmlInsert.sqlj +* +* XmlInsert_cleanup.db2 - CLP script that issues DROP TABLE statements for the +* sample XmlInsert.sqlj +* +* XmlIntegrateScrpt - CLP script that calls two scripts XmlIntegrate_cleanup.db2 +* and XmlIntegrate_setup.db2 respectively +* +* XmlIntegrate_setup.db2 - CLP script that issues CREATE TABLE statements for the +* sample XmlIntegrate.sqlj +* +* XmlIntegrate_cleanup.db2 - CLP script that issues DROP TABLE statements for the +* sample XmlIntegrate.sqlj +* +* XmlToTableScrpt - CLP script that calls two scripts XmlToTable_cleanup.db2 +* and XmlToTable_setup.db2 respectively +* +* XmlToTable_setup.db2 - CLP script that issues CREATE TABLE statements for the +* sample XmlToTable.sqlj +* +* XmlToTable_cleanup.db2 - CLP script that issues DROP TABLE statements for the +* sample XmlToTable.sqlj +* +* XmlUpDelScrpt - CLP script that calls two scripts XmlUpDel_cleanup.db2 +* and XmlUpDel_setup.db2 respectively +* +* XmlUpDel_setup.db2 - CLP script that issues CREATE TABLE statements for the +* sample XmlUpDel.sqlj +* +* XmlUpDel_cleanup.db2 - CLP script that issues DROP TABLE statements for the +* sample XmlUpDel.sqlj +* +* XmlXsltScrpt - CLP script that calls two scripts XmlXslt_cleanup.db2 +* and XmlXslt_setup.db2 respectively +* +* XmlXslt_setup.db2 - CLP script that issues CREATE TABLE statements for +* the sample XmlXslt.sqlj +* +* XmlXslt_cleanup.db2 - CLP script that issues DROP TABLE statements for the +* sample XmlXslt.sqlj +* +* reltoxmlprocScrpt - CLP script that calls two scripts reltoxmlprocdrop.db2 +* and reltoxmlproc.db2 respectively +* +* reltoxmlproc.db2 - CLP script that issues CREATE PROCEDURE statement for +* the sample RelToXmlDoc.sqlj +* +* reltoxmlprocdrop.db2 - CLP script that issues DROP PROCEDURE statement for +* the sample RelToXmlDoc.sqlj +******************************************************************************* diff --git a/xml/java/sqlj/RelToXmlDoc.sqlj b/xml/java/sqlj/RelToXmlDoc.sqlj new file mode 100644 index 0000000..731c731 --- /dev/null +++ b/xml/java/sqlj/RelToXmlDoc.sqlj @@ -0,0 +1,318 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: RelToXmlDoc.sqlj +// +// SAMPLE USER SCENARIO : Purchase order database uses relational tables to store the +// orders of different customers. This data can be returned as an XML object +// to the application. The XML object can be created using the XML constructor +// functions on the server side. +// To achieve this, the user can +// 1. Create a stored procedure to implement the logic to create the XML +// object using XML constructor functions. +// 2. Register the above stored procedure to the database. +// 3. Call the procedure whenever all the PO data is needed as XML +// instead of using complex joins. +// +// SAMPLE : This sample basically demonstrates two things +// 1. Using joins on relational data +// 2. Using constructor function to get purchaseorder data as an XML object +// +// PREQUISITES : 1. Create the sample database with the following command: +// db2sampl -xml +// 2. Copy setupscript.db2 and cleanupscript.db2 from +// the samples/xml/data directory to the current working directory +// 3. Connect to sample database. +// Create the pre-requisite tables by running the command: +// RelToXmlScrpt +// Alternatively,you can run the command: +// db2 -tvf setupscript.db2 +// 4. Create the stored procedure reltoxmlproc by running the command: +// reltoxmlprocScrpt +// Alternatively, you can run the command: +// db2 -td@ -f reltoxmlproc.db2 +// +// EXECUTION : 1. Follow the steps in the README to setup your SQLJ environment. +// 2. This sample uses classes in Util.sqlj. +// Compile the Util.sqlj program using the following : +// bldsqlj Util +// 3. Compile the sample using: +// bldsqlj RelToXmlDoc +// 4. Run the sample as: +// java RelToXmlDoc +// 5. Perform a clean up once the sample has been executed using: +// db2 -tvf cleanupscript.db2 +// +// SQL Statements USED: +// SELECT +// +// SQL/XML Functions Used : +// XMLELEMENT +// XMLATTRIBUTES +// XMLCONCAT +// XMLNAMESPACES +// XMLCOMMENT +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.sqlj are: +// Db +// Data +// +// OUTPUT FILE: RelToXmlDoc.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + + +#sql iterator Tb_cursor(int, + int, + String, + String, + int, + double, + String, + String, + String, + String, + String, + int); + +class RelToXmlDoc +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CONVERT DATA IN RELATIONAL TABLES\n" + + "INTO A XML DOCUMENT USING THE XML CONSTRUCTOR FUNCTIONS"); + + // connect to the 'sample' database + DefaultContext ctx = db.getDefaultContext(); + + // select the purchaseorder data using joins + execQuery(); + + // function to call the stored procedure which will + // select purchaseorder data using XMLconstructors + callRelToXmlProc(ctx); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + System.out.println(e); + } + } // main + + static void execQuery() + { + try + { + Tb_cursor cur1; + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE SQL SELECT:\n" + + " Statement\n" + + "TO EXECUTE THE QUERY WITH XML CONSTRUCTORS."); + + // execute the query + System.out.println(); + System.out.println( + " Execute Statement:\n" + + "SELECT po.CustID, po.PoNum, po.OrderDate, po.Status,\n" + + " count(l.ProdID) as Items, sum(p.Price) as total,\n" + + " po.Comment, c.Name, c.Street, c.City, c.Province, c.PostalCode\n" + + " FROM PurchaseOrder_relational as po, CustomerInfo_relational as c,\n" + + " Lineitem_relational as l, Products_relational as p\n" + + " WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID\n" + + " GROUP BY po.PoNum,po.CustID,po.OrderDate,po.Status,c.Name,\n" + + " c.Street, c.City,c.Province, c.PostalCode,po.Comment\n" + + " ORDER BY po.CustID,po.OrderDate\n"); + + #sql cur1 = { + SELECT po.CustID, po.PoNum, po.OrderDate, po.Status, + count(l.ProdID) as Items, sum(p.Price) as total, + po.Comment, c.Name, c.Street, c.City, c.Province, c.PostalCode + FROM PurchaseOrder_relational as po, CustomerInfo_relational as c, + Lineitem_relational as l, Products_relational as p + WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID + GROUP BY po.PoNum,po.CustID,po.OrderDate,po.Status,c.Name, + c.Street, c.City,c.Province, c.PostalCode,po.Comment + ORDER BY po.CustID,po.OrderDate}; + + System.out.println(); + System.out.println(" Results:\n" + + " CustId PoNum OrderDate Status" + + " \t Items Total_Price Comment\n" + + " \t\t Name \t\t Street \t City \t Province \t PostalCode\n" + + " -----------------------------------------------------------------------------\n"); + + int CustID = 0; + int PoNum = 0; + String OrderDate = ""; + String Status = ""; + int Items = 0; + double Price = 0; + String Comment = ""; + String Name = ""; + String Street= ""; + String City = ""; + String Province = ""; + int PostalCode = 0; + + // Read the data + #sql {FETCH :cur1 INTO :CustID, :PoNum, :OrderDate, :Status, :Items, + :Price, :Comment, :Name, :Street, :City, :Province, :PostalCode}; + + while (true) + { + if (cur1.endFetch()) + { + break; + } + System.out.println(" " + + Data.format(CustID, 8) + " " + + Data.format(PoNum, 8) + " " + + Data.format(OrderDate, 11) + " " + + Data.format(Status, 50) + " " + + Data.format(Items, 5) + " " + + Data.format(Price,6,2) + " " + + Data.format(Comment, 200) + " " + + Data.format(Name, 20) + " " + + Data.format(Street, 20) + " " + + Data.format(City, 20) + " " + + Data.format(Province, 20) + " " + + Data.format(PostalCode, 8)); + #sql {FETCH :cur1 INTO :CustID, :PoNum, :OrderDate, :Status, :Items, + :Price, :Comment, :Name, :Street, :City, :Province, :PostalCode}; + } + // close the cursor + cur1.close(); + } + catch (Exception e) + { + System.out.println(e); + } + } //execQuery + + public static void callRelToXmlProc(ConnectionContext ctx) + { + ResultSet rs; + ExecutionContext execCtx = ctx.getExecutionContext(); + + String procName = "RELTOXMLPROC"; + + try + { + // call the stored procedure + System.out.println(); + System.out.println("Call stored procedure named " + procName); + #sql{ CALL RELTOXMLPROC()}; + + System.out.println(procName + " completed successfully"); + if ((rs = execCtx.getNextResultSet()) != null) + { + fetchAll(rs); + + // close ResultSet + rs.close(); + } + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + } + } // callRelToXmlProc + + public static void fetchAll(ResultSet rs) + { + try + { + System.out.println( + "============================================================="); + + // retrieve the number, types and properties of the + // resultset's columns + ResultSetMetaData stmtInfo = rs.getMetaData(); + + String PurchaseOrder = ""; + int numOfColumns = stmtInfo.getColumnCount(); + int r = 0; + + while (rs.next()) + { + r++; + System.out.println("Row: " + r + ": \n"); + for (int i = 1; i <= numOfColumns; i++) + { + if (i == 1 || i == 2) + { + System.out.print(Data.format(rs.getInt(i), 8)); + } + if (i == 3) + { + System.out.print(rs.getString(i)); + } + if (i == 4) + { + PurchaseOrder = rs.getString(i); + System.out.print(Data.format(PurchaseOrder, 600)); + } + if (i != numOfColumns) + { + System.out.print(", "); + } + } + System.out.print("\n\n"); + } + } + catch (Exception e) + { + System.out.println("Error: fetchALL: exception"); + System.out.println(e.getMessage()); + } + } // fetchAll +} // RelToXmlDoc + + diff --git a/xml/java/sqlj/RelToXmlScrpt b/xml/java/sqlj/RelToXmlScrpt new file mode 100644 index 0000000..ca8947f --- /dev/null +++ b/xml/java/sqlj/RelToXmlScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: RelToXmlScrpt +# cleanupscript.db2 drops tables created by setupscript.db2 for the +# samples RelToXmlDoc.sqlj and RelToXmlType.sqlj +# setupscript.db2 creates tables necessary for execution of the samples +# RelToXmlDoc.sqlj and RelToXmlType.sqlj +# Both CLP scripts can be run on their own +# Usage: RelToXmlScrpt + +db2 -tvf cleanupscript.db2 +db2 -tvf setupscript.db2 diff --git a/xml/java/sqlj/RelToXmlType.sqlj b/xml/java/sqlj/RelToXmlType.sqlj new file mode 100644 index 0000000..e650990 --- /dev/null +++ b/xml/java/sqlj/RelToXmlType.sqlj @@ -0,0 +1,240 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: RelToXmlType.sqlj +// +// SAMPLE : Purchase order database uses relational tables to store the orders of +// different customers. This data can be returned as an XML object to the +// application. The XML object can be created using the XML constructor +// functions on the server side. +// To achieve this, the user can +// 1. Create new tables having XML columns. (Done in set up script) +// 2. Change the relational data to XML type using constructor functions. +// 3. Insert the data in new tables +// 4. Use the query to select all PO data. +// +// PREQUISITES : 1. Copy the RelToXmlScrpt, setupscript.db2 and cleanupscript.db2 from +// the xml/data directory to the current working directory +// 2. Create the pre-requisite tables by running the command: +// RelToXmlScrpt +// Alternatively,you can run the command: +// db2 -tvf setupscript.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj RelToXmlDoc +// 2. Run the sample as: +// java RelToXmlDoc +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf cleanupscript.db2 +// +// SQL Statements USED: +// SELECT +// INSERT +// +// SQL/XML FUNCTION USED: +// XMLDOCUMENT +// XMLELEMENT +// XMLATTRIBUTES +// +// JAVA 2 CLASSES USED: +// Statement +// ResultSet +// +// Classes used from Util.sqlj are: +// Db +// Data +// +// OUTPUT FILE: RelToXmlType.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator TbRead_cursor(int, int, String, String, String, String); + +class RelToXmlType +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CONVERT DATA IN RELATIONAL TABLES\n" + + "INTO A XML DOCUMENT USING THE XML CONSTRUCTOR FUNCTIONS"); + + // connect to the 'sample' database + db.getDefaultContext(); + + // execute the Query to Select data from relation tables + // and insert into tables as XML data type. + execQuery(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + static void execQuery() + { + try + { + TbRead_cursor cur1; + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL:\n" + + " Statement\n" + + "TO EXECUTE THE QUERY WITH XML CONSTRUCTORS."); + + // execute the query + System.out.println(); + System.out.println( + " Execute Statement:\n" + + "INSERT INTO Customerinfo_New (Custid, Address)\n" + + "(SELECT Custid, \n" + + "XMLDOCUMENT( \n" + + "XMLELEMENT(NAME \"Address\", \n" + + "XMLELEMENT(NAME \"Name\", c.Name), \n" + + "XMLELEMENT(NAME \"Street\", c.Street), \n" + + "XMLELEMENT(NAME \"City\", c.City), \n" + + "XMLELEMENT(NAME \"Province\", c.Province), \n" + + "XMLELEMENT(NAME \"PostalCode\", c.PostalCode))) \n" + + "FROM CustomerInfo_relational AS C)\n"); + + #sql{ + INSERT INTO Customerinfo_New (Custid, Address) + (SELECT Custid, + XMLDOCUMENT( + XMLELEMENT(NAME "Address", + XMLELEMENT(NAME "Name", c.Name), + XMLELEMENT(NAME "Street", c.Street), + XMLELEMENT(NAME "City", c.City), + XMLELEMENT(NAME "Province", c.Province), + XMLELEMENT(NAME "PostalCode", c.PostalCode))) + FROM CustomerInfo_relational AS C)}; + + System.out.println( + "Execute Statement:\n" + + "INSERT INTO purchaseorder_new(PoNum, OrderDate, CustID, Status, LineItems)\n" + + "(SELECT Po.PoNum, OrderDate, CustID, Status,\n" + + "XMLDOCUMENT(\n" + + "XMLELEMENT(NAME \"itemlist\", \n" + + "XMLELEMENT(NAME \"PartID\", l.ProdID),\n" + + "XMLELEMENT(NAME \"Description\", p.Description ),\n" + + "XMLELEMENT(NAME \"Quantity\", l.Quantity),\n" + + "XMLELEMENT(NAME \"Price\", p.Price)))\n" + + "FROM purchaseorder_relational AS po, lineitem_relational AS l,\n" + + "products_relational AS P\n" + + "WHERE l.PoNum=po.PoNum AND l.ProdID=P.ProdID)\n"); + + #sql{ + INSERT INTO purchaseorder_new(PoNum, OrderDate, CustID, Status, LineItems) + (SELECT Po.PoNum, OrderDate, CustID, Status, + XMLDOCUMENT( + XMLELEMENT(NAME "itemlist", + XMLELEMENT(NAME "PartID", l.ProdID), + XMLELEMENT(NAME "Description", p.Description ), + XMLELEMENT(NAME "Quantity", l.Quantity), + XMLELEMENT(NAME "Price", p.Price))) + FROM purchaseorder_relational AS po, lineitem_relational AS l, + products_relational AS P + WHERE l.PoNum=po.PoNum AND l.ProdID=P.ProdID)}; + + System.out.println(); + + + #sql cur1 = { + SELECT po.PoNum, po.CustId, po.OrderDate, + XMLELEMENT(NAME "PurchaseOrder", + XMLATTRIBUTES(po.CustID AS "CustID", po.PoNum AS "PoNum", + po.OrderDate AS "OrderDate", po.Status AS "Status")), + XMLELEMENT(NAME "Address", c.Address), + XMLELEMENT(NAME "lineitems", po.LineItems) + FROM PurchaseOrder_new AS po, CustomerInfo_new AS c + WHERE po.custid = c.custid + ORDER BY po.custID}; + + int PoNum = 0; + int CustId = 0; + String OrderDate = ""; + String PurchaseOrder = ""; + String Address = ""; + String LineItem = ""; + + #sql {FETCH :cur1 INTO :PoNum, :CustId, :OrderDate, :PurchaseOrder, + :Address, :LineItem}; + + while (true) + { + if (cur1.endFetch()) + { + break; + } + System.out.println(" " + + "\n Customer ID : " + + Data.format(CustId, 8) + " " + + "\n Purchase Order Number : " + + Data.format(PoNum, 8) + " " + + "\n Purchase Order Date : " + + Data.format(OrderDate, 11) + " " + + "\n Purchase Order Document : \n" + + Data.format(PurchaseOrder, 600) + " " + + "\n Address in XML Format: \n" + + Data.format(Address, 500) + " " + + "\n Line Item in XML Format\n" + + Data.format(LineItem, 500)); + + #sql {FETCH :cur1 INTO :PoNum, :CustId, :OrderDate, :PurchaseOrder, + :Address, :LineItem}; + } + // Rollback all the changes made to the sample Database + #sql{ROLLBACK}; + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } //execQuery +} // RelToXmlType + + diff --git a/xml/java/sqlj/Util.sqlj b/xml/java/sqlj/Util.sqlj new file mode 100644 index 0000000..0698946 --- /dev/null +++ b/xml/java/sqlj/Util.sqlj @@ -0,0 +1,319 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Util.sqlj +// +// SAMPLE: Utilities for SQLJ sample programs +// +// This sample has 3 classes: +// 1. Data - Display the data in the table +// 2. Db - Connect to or disconnect from the 'sample' database +// 3. SqljException - Handle Java Exceptions +// +// JAVA 2 CLASSES USED: +// DriverManager +// Connection +// Exception +// +// OUTPUT FILE: None +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.util.*; +import java.sql.*; +import java.math.BigDecimal; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class Data +{ + public static String format(String strData, int finalLen) + throws Exception + { + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = strData; + for (int i = strData.length(); i < finalLen; i++) + { + finalStr = finalStr + " "; + } + } + return (finalStr); + } // format(String, int) + + public static String format(int intData, int finalLen) + throws Exception + { + String strData = String.valueOf(intData); + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + return (finalStr); + } // format(int, int) + + public static String format(Integer integerData, int finalLen) + throws Exception + { + int intData; + String finalStr; + + intData = integerData.intValue(); + finalStr = format(intData, finalLen); + + return finalStr; + } // format(Integer, int) + + public static String format(double doubData, int precision, int scale) + throws Exception + { + BigDecimal decData = new BigDecimal(doubData); + decData = decData.setScale(scale, BigDecimal.ROUND_HALF_EVEN); + String strData = decData.toString(); + + // prepare the final string + int finalLen = precision + 1; + String finalStr; + if (finalLen <= strData.length()) + { + finalStr = strData.substring(0, finalLen); + } + else + { + finalStr = ""; + for (int i = 0; i < finalLen - strData.length(); i++) + { + finalStr = finalStr + " "; + } + finalStr = finalStr + strData; + } + return (finalStr); + } // format(double, int, int) + + public static String format(Double doubleData, int precision, int scale) + throws Exception + { + double doubData; + String finalStr; + + doubData = doubleData.doubleValue(); + return (format(doubData, precision, scale)); + } // format(Double, int, int) +} // Data + +class Db +{ + public String alias; + public String server; + public int portNumber = -1; // < 0 use universal type 2 connection + // > 0 use universal type 4 connection + public String userId; + public String password; + private Connection con; + private DefaultContext ctx; + + public Db() + { + } + + public Db(String argv[]) throws Exception + { + if( argv.length > 5 || + ( argv.length == 1 && + ( argv[0].equals( "?" ) || + argv[0].equals( "-?" ) || + argv[0].equals( "/?" ) || + argv[0].equalsIgnoreCase( "-h" ) || + argv[0].equalsIgnoreCase( "/h" ) || + argv[0].equalsIgnoreCase( "-help" ) || + argv[0].equalsIgnoreCase( "/help" ) ) ) ) + { + throw new Exception( + "Usage: prog_name [dbAlias] [userId passwd] (use universal JDBC type 2 driver)\n" + + " prog_name [dbAlias] server portNum userId passwd (use universal JDBC type 4 driver)" ); + } + + switch (argv.length) + { + case 0: // Type 2, use all defaults + alias = "sample"; + userId = ""; + password = ""; + break; + case 1: // Type 2, dbAlias specified + alias = argv[0]; + userId = ""; + password = ""; + break; + case 2: // Type 2, userId & passwd specified + alias = "sample"; + userId = argv[0]; + password = argv[1]; + break; + case 3: // Type 2, dbAlias, userId & passwd specified + alias = argv[0]; + userId = argv[1]; + password = argv[2]; + break; + case 4: // Type 4, use default dbAlias + alias = "sample"; + server = argv[0]; + portNumber = Integer.valueOf( argv[1] ).intValue(); + userId = argv[2]; + password = argv[3]; + break; + case 5: // Type 4, everything specified + alias = argv[0]; + server = argv[1]; + portNumber = Integer.valueOf( argv[2] ).intValue(); + userId = argv[3]; + password = argv[4]; + break; + } + } // Db constructor + + public Connection connect() throws Exception + { + String url = null; + + // In Partitioned Database environment, set this to the node number + // to which you wish to connect (leave as "0" in non-Partitioned Database environment) + String nodeNumber = "0"; + + Properties props = new Properties(); + + if ( portNumber < 0 ) + { + url = "jdbc:db2:" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 2 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + else + { + url = "jdbc:db2://" + server + ":" + portNumber + "/" + alias; + System.out.println( + " Connect to '" + alias + "' database using JDBC Universal type 4 driver." ); + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + + if( null != userId ) + { + props.setProperty("user", userId); + props.setProperty("password", password); + } + + props.setProperty("CONNECTNODE", nodeNumber); + + con = DriverManager.getConnection( url, props ); + + // enable transactions + con.setAutoCommit(false); + return con; + } // connect + + public DefaultContext getDefaultContext() throws Exception + { + ctx = new DefaultContext( connect() ); + DefaultContext.setDefaultContext(ctx); + return( ctx ); + } // connect + + public void disconnect() throws Exception + { + System.out.println(); + System.out.println(" Disconnect from '" + alias + "' database."); + + // makes all changes made since the previous commit/rollback permanent + // and releases any database locks currrently held by the Connection. + con.commit(); + + // releases a Connection's database and JDBC resources immediately + if( ctx != null ) + { + ctx.close(); + } + else + { + con.close(); + } + } // disconnect +} // Db + +class SqljException extends Exception +{ + public SqljException(Exception e) + { + super(e.getMessage()); + } + + public void handle() + { + try + { + System.out.println(getMessage()); + System.out.println(); + System.out.println("--Rollback the transaction-----"); + #sql {ROLLBACK}; + System.out.println(" Rollback done!"); + } + catch (Exception e) + { + }; + } // handle + + public void handleExpectedErr() + { + System.out.println(); + System.out.println( + "**************** Expected Error ******************\n"); + System.out.println(getMessage()); + System.out.println( + "**************************************************"); + } // handleExpectedErr +} // SqljException + diff --git a/xml/java/sqlj/XmlConst.sqlj b/xml/java/sqlj/XmlConst.sqlj new file mode 100644 index 0000000..e35095f --- /dev/null +++ b/xml/java/sqlj/XmlConst.sqlj @@ -0,0 +1,448 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlConst.sqlj +// +// SAMPLE: How to create unique index on XML column +// +// NOTE : +// 1) This sample demonstrate the how to enforce the +// constraints on an XML value. There are some statement +// in the samples which are expected to fail because of +// constraint violation so The sql error SQL803N and +// SQL20305N are expected. +// +// 2) Primary key, unique constraint, or unique index are not +// supported for XML column in the Database Partitioning Feature +// available with DB2 Enterprise Server Edition for Linux, UNIX, +// and Windows. +// +// SQL Statements USED: +// SELECT +// FETCH +// +// Classes used from Util.sqlj are: +// Db +// Data +// SqljException +// +// OUTPUT FILE: XmlConst.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class XmlConst +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO CREATE UNIQUE INDEX ON XML COLUMNS"); + + // Connect to 'sample' database + db.getDefaultContext(); + + TbUniqueIndexConstraint1(); + dropall(); + TbUniqueIndexConstraint2(); + dropall(); + TbVarcharIndexConstraint(); + dropall(); + TbVarcharIndexConstraint1(); + + //Disconnect from sample database + db.disconnect(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } + +static void TbUniqueIndexConstraint1() +{ + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE SQL statement: \n" + + "CREATE TABLE " + + "TO CREATE A TABLE. " ); + + //execute the query + + System.out.println(); + System.out.println( + "Execute Statement:" + + " CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"); + + #sql {CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)}; + + System.out.println("create unique index using 'UNIQUE' CONSTRAINT.\n"); + + System.out.println("CREATE UNIQUE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'"+ + "AS SQL DOUBLE"); + + #sql {CREATE UNIQUE INDEX empindex on company(doc) GENERATE KEY + USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE}; + + System.out.println("Insert row1 into table \n"); + + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse"+ + "(document ' "+ + "Laura Brown"+ + "Finance"+ + " '))\n"); + + #sql { + INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura Brown + Finance + '))}; + + System.out.println("Insert row2 into table \n"); + System.out.println("Unique violation error because of id=\"31201\"\n"); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse"+ + "(document ' "+ + "Laura Brown"+ + "Finance"+ + "'))"); + + #sql { + INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura Brown + Finance + '))}; + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + //try { DefaultContext.getDefaultContext().getConnection().rollback(); } + //catch (Exception e) + // { + //} + } + catch(Exception e) + {} + +} + +static void TbUniqueIndexConstraint2() +{ + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE SQL statement: \n" + + "CREATE TABLE " + + "TO CREATE A TABLE. " ); + + //execute the query + + System.out.println(); + System.out.println( + "Execute Statement:" + + " CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"); + + #sql {CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)}; + + System.out.println("create unique index using 'UNIQUE' CONSTRAINT.\n"); + + System.out.println("CREATE UNIQUE INDEX empindex on company(doc)" + + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'" + + " AS SQL DOUBLE\n"); + + #sql {CREATE UNIQUE INDEX empindex on company(doc) GENERATE KEY + USING XMLPATTERN '/company/emp/@id' AS SQL DOUBLE}; + + System.out.println("Insert rowr3 into table \n"); + System.out.println("No index entry is inserted because \"ABCDE\" cannot be cast"+ + " the DOUBLE data type \n"); + System.out.println(" INSERT INTO company values (1, 'doc1', xmlparse"+ + "(document ' " + + " Laura Brown" + + "Finance" + + "'))\n"); + #sql { + INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura Brown + Finance + '))}; + + System.out.println("Insert row4 into table \n"); + + System.out.println("The insert succeeds because no index entry is" + + " inserted since \"ABCDE\" cannot be cast to the DOUBLE data type.\n"); + + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse"+ + "(document ' Laura Brown"+ + "Finance"+ + "'))\n"); + #sql { + INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura Brown + Finance + '))}; + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + //try { DefaultContext.getDefaultContext().getConnection().rollback(); } + //catch (Exception e) + // { + // } + } + catch(Exception e) + {} + +} + +static void TbVarcharIndexConstraint() +{ + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE SQL statement: \n" + + "CREATE TABLE " + + "TO CREATE A TABLE. " ); + + //execute the query + + System.out.println(); + System.out.println( + "Execute Statement:" + + "CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"); + + #sql {CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)}; + + System.out.println("create unique index using 'UNIQUE' CONSTRAINT.\n"); + + System.out.println("CREATE UNIQUE INDEX empindex on company(doc) "+ + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'"+ + "AS SQL VARCHAR(4)\n"); + + #sql {CREATE UNIQUE INDEX empindex on company(doc) GENERATE KEY + USING XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(4)}; + + System.out.println("Insert row5 into table \n"); + + System.out.println("Insert statement succeeds because the length of \"312\" < 4.\n"); + + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse"+ + "(document ' "+ + "Finance" + + "'))\n"); + + #sql { + INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura Brown + Finance + '))}; + + System.out.println("Insert row6 into table \n"); + System.out.println("Insert statement fails because the length of \"31202\" > 4.\n"); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse"+ + "(document ' "+ + "Laura Brown"+ + "Finance"+ + "'))\n"); + + #sql { + INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura Brown + Finance + '))}; + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + //try { DefaultContext.getDefaultContext().getConnection().rollback(); } + //catch (Exception e) + // { + //} + } + catch(Exception e) + {} + +} + +static void TbVarcharIndexConstraint1() +{ + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE SQL statement: \n" + + "CREATE TABLE " + + "TO CREATE A TABLE. " ); + + //execute the query + + System.out.println(); + System.out.println( + "Execute Statement:" + + "CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"); + + #sql {CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)}; + System.out.println("Insert row7 into table \n"); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse"+ + "(document ' "+ + "Finance" + + "'))\n"); + + #sql { + INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura Brown + Finance + '))}; + + System.out.println("Insert row8 into table \n"); + System.out.println("INSERT INTO company values (1, 'doc1', xmlparse"+ + "(document ' "+ + "Laura Brown"+ + "Finance"+ + "'))\n"); + + #sql { + INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura Brown + Finance + '))}; + + System.out.println("create index with Varchar constraint " + + "fails because the length of \"31202\" > 4\n"); + + System.out.println("CREATE UNIQUE INDEX empindex on company(doc) "+ + "GENERATE KEY USING XMLPATTERN '/company/emp/@id'"+ + "AS SQL VARCHAR(4)\n"); + + #sql {CREATE UNIQUE INDEX empindex on company(doc) GENERATE KEY + USING XMLPATTERN '/company/emp/@id' AS SQL VARCHAR(4)}; + + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + } + catch(Exception e) + {} + +} +static void dropall() +{ + try + { + System.out.println("drop index and table\n"); + #sql {DROP index "EMPINDEX"}; + #sql {DROP table "COMPANY"}; + #sql {COMMIT}; + } + catch (Exception e) + { + System.out.println(e); + } +} +} diff --git a/xml/java/sqlj/XmlIndex.sqlj b/xml/java/sqlj/XmlIndex.sqlj new file mode 100644 index 0000000..82745ee --- /dev/null +++ b/xml/java/sqlj/XmlIndex.sqlj @@ -0,0 +1,708 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlIndex.sqlj +// +// SAMPLE: How to create index on xml columns in different ways. +// +// SQL Statements USED: +// SELECT +// FETCH +// +// Classes used from Util.sqlj are: +// Db +// Data +// SqljException +// +// OUTPUT FILE: XmlIndex.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; +import com.ibm.db2.jcc.DB2Xml; + +// Define the iterator to use in the functions +#sql iterator Positioned_Iterator(Object); + +class XmlIndex +{ + public static void main(String argv[]) + { + + int rc = 0; + String url = "jdbc:db2:sample"; + Connection con = null; + DefaultContext ctx = null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + + // get the default context + ctx = new DefaultContext(con); + + // set the default context for the sample + DefaultContext.setDefaultContext(ctx); + System.out.println(); + } + catch(Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + System.exit(1); + } + + System.out.println( + "THIS SAMPLE SHOWS HOW TO CREATE INDEX ON XML COLUMNS"); + + + //Different ways to create an index on XML columns + createAndInsertIntoTable(); + createIndex(); + createIndexwithSelf(); + createIndexonTextnode(); + createIndexwith2Paths(); + createIndexwithNamespace(); + createIndexwith2Datatypes(); + createIndexuseAnding(); + createIndexuseAndingOrOring(); + createIndexwithDateDatatype(); + createIndexWithCommentNode(); + + // drop all tables and indices + dropall(); + } // main + + // This function creates a table and inserts rows + // having xml data into table + static void createAndInsertIntoTable() + { + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE SQL statement: \n" + + "CREATE TABLE " + + "TO CREATE A TABLE. " ); + + + System.out.println(); + System.out.println( + "Execute Statement:" + + " CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)"); + + // create table called 'company' + #sql {CREATE TABLE COMPANY(id INT, docname VARCHAR(20), doc XML)}; + + + // insert row1 into table + System.out.println(); + System.out.println("INSERT row1 into table \n"); + #sql { + INSERT INTO company values (1, 'doc1', xmlparse + (document ' + Laura Brown + Finance + '))}; + + //insert row2 into table + System.out.println("INSERT row2 into table \n"); + #sql { + INSERT INTO company values (2, 'doc2', xmlparse ( + document ' + ChrisMurphy + Marketing + NicoleMurphy + Sales ')) }; + + } + catch(Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + System.exit(1); + } + } // createAndInsertIntoTable + + // This function creates an index on an xml attribute + // and shows how to use XQUERY on the index + static void createIndex() + { + try + { + + Object data = null; + + // declare an iterator + Positioned_Iterator cur1 = null; + + // create index on xml column + System.out.println("create index on attribute \n"); + System.out.println("CREATE INDEX empindex1 ON company(doc) "+ + "GENERATE KEY USING XMLPATTERN '/company/emp/@*'"+ + "AS SQL VARCHAR(25). \n"); + #sql { + CREATE INDEX empindex1 ON company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@*' AS SQL VARCHAR(25)} ; + + + // example query using above index + System.out.println("for $i in db2-fn:xmlcolumn('COMPANY.DOC')" + + "/company/emp[@id='42366'] return $i/name\n"); + #sql cur1 = + {SELECT XMLQUERY('for $i in db2-fn:xmlcolumn("COMPANY.DOC") + /company/emp[@id = "42366"] return $i/name' passing + company.doc as "doc") from company}; + + #sql {FETCH :cur1 into :data}; + + System.out.println("---------------------------------------------"); + while (true) + { + #sql {FETCH :cur1 into :data}; + + if (cur1.endFetch()) + { + break; + } + + // print the result as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + System.out.println(); + } + System.out.println("---------------------------------------------"); + cur1.close(); + } + catch (SQLException sqle) + { + System.err.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // createIndex + + // This function creates an index with self or descendent forward axis + // and shows how XQUERY uses an index + static void createIndexwithSelf() + { + try + { + Object data = null; + + // declare an iterator + Positioned_Iterator cur1 = null; + + System.out.println("create index with self or descendent " + + "forward axis \n"); + System.out.println("CREATE INDEX empindex2 ON company(doc) GENERATE"+ + "KEY USINGXMLPATTERN '//@salary' AS SQL DOUBLE\n"); + #sql { + CREATE INDEX empindex2 ON company(doc) GENERATE KEY USING + XMLPATTERN '//@salary' AS SQL DOUBLE }; + System.out.println("---------------------------------------------"); + + #sql cur1 = {SELECT XMLQUERY('for $i in db2-fn:xmlcolumn + ("COMPANY.DOC") /company/emp[@salary > 35000] return + {$i/@salary}' passing by ref + company.doc as "doc") from company}; + + #sql {FETCH :cur1 into :data}; + while (true) + { + #sql {FETCH :cur1 into :data}; + + if (cur1.endFetch()) + { + break; + } + + // print the resulr as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + System.out.println(); + } + System.out.println("---------------------------------------------"); + cur1.close(); + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexwithSelf + + // This function creates an index on a text mode and + // shows how to use XQUERY on the index + static void createIndexonTextnode() + { + try + { + + Object data = null; + + // declare an iterator + Positioned_Iterator cur1 = null; + + System.out.println("create index on a text mode\n"); + System.out.println("CREATE INDEX empindex3 ON company(doc) GENERATE"+ + "KEY USING XMLPATTERN '/company/emp/dept/text()'" + + " AS SQL VARCHAR(30)\n"); + System.out.println("---------------------------------------------"); + + #sql { + CREATE INDEX empindex3 ON company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/dept/text()' AS SQL VARCHAR(30) }; + + #sql cur1 = {SELECT XMLQUERY('for $i in db2-fn:xmlcolumn + ("COMPANY.DOC")/company/emp[dept/text() = "Finance" + or dept/text() = "Marketing"] return $i/name' passing + by ref company.doc as "doc") from company}; + + #sql {FETCH :cur1 into :data}; + + while (true) + { + #sql {FETCH :cur1 into :data}; + if (cur1.endFetch()) + { + break; + } + // print the resulr as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + System.out.println(); + } + System.out.println("---------------------------------------------"); + cur1.close(); + } + catch (Exception e) + { + System.out.println(e); + } + } // createIndexonTextnode + + // This function creates an index when 2 paths are qualified + // by an XML and shows how we can use XQUERY on the index + static void createIndexwith2Paths() + { + try + { + Object data = null; + + // declare an iterator + Positioned_Iterator cur1 = null; + + System.out.println("create index when 2 paths are qualified"+ + " by an XML \n"); + System.out.println("CREATE INDEX empindex4 ON company(doc) GENERATE "+ + "KEY USING XMLPATTERN '//@id' AS SQL VARCHAR(25)\n"); + System.out.println("---------------------------------------------"); + + #sql { + CREATE INDEX empindex4 ON company(doc) GENERATE KEY USING + XMLPATTERN '//@id' AS SQL VARCHAR(25) }; + + #sql cur1 = {SELECT XMLQUERY('for $i in db2-fn:xmlcolumn + ("COMPANY.DOC")/company/emp[@id="31201"] return $i/name' + passing by ref company.doc as "doc") from company}; + + #sql {FETCH :cur1 into :data}; + + while (true) + { + #sql {FETCH :cur1 into :data}; + + if (cur1.endFetch()) + { + break; + } + + // print the resulr as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + System.out.println(); + } + System.out.println("---------------------------------------------"); + cur1.close(); + + #sql cur1 = {SELECT XMLQUERY('for $i in db2-fn:xmlcolumn("COMPANY.DOC") + /company/emp[dept/@id="K55"] return $i/name' passing by + ref company.doc as "doc") from company}; + + #sql {FETCH :cur1 into :data}; + + System.out.println("---------------------------------------------"); + while (true) + { + #sql {FETCH :cur1 into :data}; + + if (cur1.endFetch()) + { + break; + } + + // print the resulr as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + System.out.println(); + } + + System.out.println("---------------------------------------------"); + cur1.close(); + } + catch (Exception e) + { + System.out.println(e); + } + } // createIndexwith2Paths + + // This function creates index with namespace + static void createIndexwithNamespace() + { + try + { + System.out.println("create index with namespace \n"); + System.out.println("CREATE INDEX empindex ON company(doc) GENERATE"+ + "KEY USING XMLPATTERN 'declare default element"+ + "namespace \"http://www.mycompany.com/\";declare"+ + "namespace m=\"http://www.mycompanyname.com/\";"+ + "/company/emp/ @m:id' AS SQL VARCHAR(30)\n"); + System.out.println("---------------------------------------------"); + #sql { + CREATE INDEX empindex ON company(doc) GENERATE KEY USING + XMLPATTERN 'declare default element namespace + "http://www.mycompany.com/";declare namespace + m="http://www.mycompanyname.com/";/company/emp/ + @m:id' AS SQL VARCHAR(30)}; + + } + catch (Exception e) + { + System.out.println(e); + } + } // createIndexwithNamespace + + // This function creates index with different data types + static void createIndexwith2Datatypes() + { + try + { + System.out.println("create same index with different data types \n"); + System.out.println("CREATE INDEX empindex5 ON company(doc)" + + "GENERATE KEY USING XMLPATTERN '/companyt/emp/@id'"+ + "AS SQL VARCHAR(10)\n"); + System.out.println("---------------------------------------------"); + #sql { + CREATE INDEX empindex5 ON company(doc) GENERATE KEY + USING XMLPATTERN '/companyt/emp/@id' AS SQL VARCHAR(10)}; + + + System.out.println("CREATE INDEX empindex6 ON company(doc)" + + "GENERATE KEY USING XMLPATTERN '/companyt/emp/@id'"+ + " AS SQL DOUBLE"); + #sql { + CREATE INDEX empindex6 ON company(doc) GENERATE KEY + USING XMLPATTERN '/companyt/emp/@id' AS SQL DOUBLE}; + + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexwith2Datatypes + + // This function creates an index using joins and also + // shows how to use an XQUERY on the index created + static void createIndexuseAnding() + { + try + { + + Object data = null; + + // declare an iterator + Positioned_Iterator cur1 = null; + + System.out.println("create index using joins (Anding) \n"); + + System.out.println("CREATE INDEX empindex7 ON company(doc) "+ + "GENERATE KEY USING XMLPATTERN '/company/emp/name/last'"+ + "AS SQL VARCHAR(100)\n"); + System.out.println("---------------------------------------------"); + #sql { + CREATE INDEX empindex7 ON company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/name/last' AS SQL VARCHAR(100)}; + + System.out.println("CREATE INDEX deptindex on company(doc)"+ + "GENERATE KEY USING XMLPATTERN '/company/emp/dept/text()'"+ + "AS SQL VARCHAR(30)\n"); + System.out.println("---------------------------------------------"); + + #sql { + CREATE INDEX deptindex on company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/dept/text()' AS SQL VARCHAR(30)}; + + #sql cur1 = {SELECT XMLQUERY('for $i in db2-fn:xmlcolumn + ("COMPANY.DOC")/company/emp[name/last="Murphy" + and dept/text()="Sales"] return $i/name/last' + passing by ref company.doc as "doc") from company}; + + #sql {FETCH :cur1 into :data}; + while (true) + { + #sql {FETCH :cur1 into :data}; + if (cur1.endFetch()) + { + break; + } + + // print the resulr as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + System.out.println(); + } + System.out.println("---------------------------------------------"); + cur1.close(); + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexuseAnding + + // This function creates an index using joins (ANDing or ORing) + // and shows how to use XMLQUERY on the index created + static void createIndexuseAndingOrOring() + { + try + { + Object data = null; + + // declare an iterator + Positioned_Iterator cur1 = null; + + System.out.println("create index using joins (Anding or Oring ) \n"); + + System.out.println("CREATE INDEX empindex8 ON company(doc)"+ + "GENERATE KEY USING XMLPATTERN '/company/emp/@salary'"+ + "AS SQL DOUBLE"); + #sql { + CREATE INDEX empindex8 ON company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@salary' AS SQL DOUBLE}; + + System.out.println("CREATE INDEX empindex9 ON company(doc)"+ + "GENERATE KEY USING XMLPATTERN '/company/emp/dept'"+ + " AS SQL VARCHAR(25)\n"); + + #sql { + CREATE INDEX empindex9 ON company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/dept' AS SQL VARCHAR(25)}; + + System.out.println("CREATE INDEX empindex10 ON company(doc)"+ + "GENERATE KEY USING XMLPATTERN '/company/emp/name/last' "+ + "AS SQL VARCHAR(25)\n"); + + System.out.println("---------------------------------------------"); + #sql { + CREATE INDEX empindex10 ON company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/name/last' AS SQL VARCHAR(25)}; + + #sql cur1 = {SELECT XMLQUERY( + 'for $i in db2-fn:xmlcolumn("COMPANY.DOC")/company/emp + [@salary > 50000 and dept="Finance"]/name[ last = "Brown"] + return $i/last') from company}; + + #sql {FETCH :cur1 into :data}; + while (true) + { + #sql {FETCH :cur1 into :data}; + + if (cur1.endFetch()) + { + break; + } + + // print the resulr as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + System.out.println(); + } + System.out.println("---------------------------------------------"); + cur1.close(); + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexuseAndingOrOring + + // This function create an index with Date datatype and + // shows how to use an XMLQUERY on the index created + static void createIndexwithDateDatatype() + { + try + { + + Object data = null; + + // declare an iterator + Positioned_Iterator cur1 = null; + + System.out.println("create index with Date Data type \n"); + + System.out.println("CREATE INDEX empindex11 ON company(doc)"+ + "GENERATE KEY USING XMLPATTERN '/company/emp/@DOB'"+ + "as SQL DATE\n"); + System.out.println("-----------------------------------------"); + #sql { + CREATE INDEX empindex11 ON company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@DOB' as SQL DATE}; + + #sql cur1 = {SELECT XMLQUERY('for $i in db2-fn:xmlcolumn("COMPANY.DOC") + /company/emp[@DOB < "11-11-78"] return $i/name') from company}; + + #sql {FETCH :cur1 into :data}; + while (true) + { + #sql {FETCH :cur1 into :data}; + + if (cur1.endFetch()) + { + break; + } + // print the resulr as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + System.out.println(); + } + System.out.println("-----------------------------------------"); + cur1.close(); + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexwithDateDatatype + + // This function creates an index with comment node and also + // shows how to use XMLQUERY on the index created + static void createIndexWithCommentNode() + { + try + { + Object data = null; + + // declare an iterator + Positioned_Iterator cur1 = null; + + System.out.println("create index with Comment Node \n"); + + System.out.println("CREATE INDEX empindex12 ON company(doc)"+ + "GENERATE KEY USING XMLPATTERN '/company//comment()'"+ + "as SQL VARCHAR HASHED\n"); + System.out.println("-----------------------------------------"); + #sql { + CREATE INDEX empindex12 ON company(doc) GENERATE KEY USING + XMLPATTERN '/company/emp/@DOB' as SQL DATE}; + + #sql cur1 = {SELECT XMLQUERY('for $i in db2-fn:xmlcolumn("COMPANY.DOC") + /company/emp[comment() = " good "] return $i/name') + from company}; + + #sql {FETCH :cur1 into :data}; + while (true) + { + #sql {FETCH :cur1 into :data}; + if (cur1.endFetch()) + { + break; + } + // print the result as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + System.out.println(); + } + System.out.println("-----------------------------------------"); + cur1.close(); + } + catch(Exception e) + { + System.out.println(e); + } + } // createIndexWithCommentNode + + // This function drops all the indexes created and + // also drops the 'company' table + static void dropall() + { + try + { + System.out.println("drop table \n"); + #sql {DROP INDEX "EMPINDEX1"}; + #sql {DROP INDEX "EMPINDEX2"}; + #sql {DROP INDEX "EMPINDEX3"}; + #sql {DROP INDEX "EMPINDEX4"}; + #sql {DROP INDEX "EMPINDEX5"}; + #sql {DROP INDEX "EMPINDEX6"}; + #sql {DROP INDEX "EMPINDEX7"}; + #sql {DROP INDEX "EMPINDEX8"}; + #sql {DROP INDEX "EMPINDEX9"}; + #sql {DROP INDEX "EMPINDEX10"}; + #sql {DROP INDEX "EMPINDEX11"}; + #sql {DROP INDEX "EMPINDEX12"}; + #sql {DROP TABLE "COMPANY"}; + } + catch (Exception e) + { + System.out.println(e); + } + } // dropall +} diff --git a/xml/java/sqlj/XmlInsert.sqlj b/xml/java/sqlj/XmlInsert.sqlj new file mode 100644 index 0000000..60eb708 --- /dev/null +++ b/xml/java/sqlj/XmlInsert.sqlj @@ -0,0 +1,939 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlInsert.sqlj +// +// SAMPLE: How to insert XML data into a table +// +// SQL Statements USED: +// SELECT +// INSERT +// +// Classes used from Util.sqlj are: +// Db +// Data +// SqljException +// +// PREQUISITES : 1. copy the files cust1021.xml, cust1022.xml and +// cust1023.xml to working directory +// 2. Create the pre-requisite tables by running the command: +// XmlInsertScrpt +// Alternatively,you can run the command: +// db2 -tvf XmlInsert_setup.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj XmlInsert +// 2. Run the sample as: +// java XmlInsert +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf XmlInsert_cleanup.db2 +// +// OUTPUT FILE: XmlInsert.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.util.*; +import java.io.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + + +#sql iterator TbXMLinsert_cursor1(int, String); + +class XmlInsert +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO INSERT XML TABLE DATA."); + + // connect to the 'sample' database + db.getDefaultContext(); + + preRequisites(); + mostSimpleInsert(); + InsertFromAnotherXmlColumn(); + InsertFromAnotherStringColumn(); + InsertwhereSourceisXmlFunction(); + InsertwhereSourceisBlob(); + InsertwhereSourceisClob(); + InsertBlobDataWithImplicitParsing(); + InsertFromStringNotWellFormedXML(); + InsertwhereSourceisTypecastToXML(); + InsertwithValidationSourceisVarchar(); + ValidateXMLDocument(); + DeleteofRowwithXmlData(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// main + + static void mostSimpleInsert() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM A SIMPLE INSERT."); + + // display the content of the 'customer' table + CustomerTbContentDisplay(1006); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1006,XMLPARSE(document "+ + " 'divya" + + " ' preserve whitespace))\n" + + " \n"); + + #sql { + INSERT INTO customer(cid,info) VALUES(1006,XMLPARSE(document + 'divya + ' preserve whitespace))}; + + + // display the content of the 'customer' table + CustomerTbContentDisplay(1006); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }//mostSimpleInsert + + static void InsertFromAnotherXmlColumn() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS FROM ANOTHER XML COLUMN."); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1007); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " SELECT ocid,information FROM oldcustomer p "+ + " WHERE p.ocid=1007\n" + + "\n"); + + #sql { + INSERT INTO customer(cid,info) + SELECT ocid,information + FROM oldcustomer p + WHERE p.ocid=1007}; + + + // display the content of the 'customer' table + CustomerTbContentDisplay(1007); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // InsertFromAnotherXmlColumn + + static void InsertFromAnotherStringColumn() + { + try + { + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS FROM ANOTHER STRING COLUMN."); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " SELECT ocid,XMLPARSE(document addr preserve whitespace) " + + " FROM oldcustomer p " + + " WHERE p.ocid=1008\n" + + " \n"); + + #sql { + INSERT INTO customer(cid,info) + SELECT ocid,XMLPARSE(document addr preserve whitespace) + FROM oldcustomer p + WHERE p.ocid=1008}; + + + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }//InsertFromAnotherStringColumn + + static void InsertAnotherStringWithImplicitParsing() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS FROM " + + "ANOTHER STRING COLUMN WITH IMPLICIT PARSING"); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1011); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " SELECT ocid,addr " + + " FROM oldcustomer p " + + " WHERE p.ocid=1011\n" + + " \n"); + + #sql { + INSERT INTO customer(cid,info) + SELECT ocid,addr + FROM oldcustomer p + WHERE p.ocid=1011}; + + + // display the content of the 'customer' table + CustomerTbContentDisplay(1011); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }//InsertAnotherStringWithImplicitParsing + + static void InsertwithValidationSourceisVarchar() + { + try + { + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + " TO PERFORM AN INSERT WITH VALIDATION WHERE " + + " SOURCE IS OF TYPE VARCHAR."); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1009); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " SELECT ocid,XMLVALIDATE(XMLPARSE(document " + + " addr preserve whitespace)according to " + + " XMLSCHEMA id customer) " + + " FROM oldcustomer p " + + " WHERE p.ocid=1009\n" + + " \n"); + #sql { + INSERT INTO customer(cid,info) + SELECT ocid,XMLVALIDATE(XMLPARSE(document addr preserve + whitespace)according to + XMLSCHEMA id customer) + FROM oldcustomer p + WHERE p.ocid=1009}; + + + // display the content of the 'customer' table + CustomerTbContentDisplay(1009); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }//InsertwithValidationSourceisVarchar + + static void ValidateXMLDocument() + { + try + { + String xmldata = "XMLPARSE(document '
12 gandhimarg " + + "belgaum"+ + "karnataka
" + + "
' preserve whitespace)"; + + System.out.println(); + System.out.println( + "-------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + " TO PERFORM AN INSERT WITH VALIDATION WHEN " + + " DOCUMENT IS NOT AS PER SCHEMA"); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1012); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES (1012, XMLVALIDATE(XMLPARSE(document '
12 gandhimarg"+ + " belgaumkarnataka"+ + "
' preserve whitespace))"+ + " according to XMLSCHEMA ID customer) \n"); + + #sql { + INSERT INTO customer(cid,info) + VALUES (1012, XMLVALIDATE(:xmldata + according to XMLSCHEMA ID CUSTOMER)) }; + + + // display the content of the 'customer' table + CustomerTbContentDisplay(1012); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + } + catch(Exception e) + {} + } //ValidateXMLDocument + + static void InsertwhereSourceisXmlFunction() + { + try + { + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS A XML FUNCTION."); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1010); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " SELECT ocid,XMLPARSE(document XMLSERIALIZE" + + " (content XMLELEMENT(NAME\"oldCustomer\", "+ + " XMLATTRIBUTES(s.ocid,s.firstname||' '||s." + + " lastname AS \"name\")) " + + " as varchar(200)) strip whitespace) " + + " FROM oldcustomer s " + + " WHERE s.ocid=1010\n" + + "\n"); + + #sql { + INSERT INTO customer(cid,info) + SELECT ocid,XMLPARSE(document XMLSERIALIZE(content + XMLELEMENT(NAME "oldCustomer",XMLATTRIBUTES(s.ocid,s. + firstname||' '||s.lastname AS "name")) + as varchar(200)) strip whitespace) + FROM oldcustomer s + WHERE s.ocid=1010}; + + + // display the content of the 'customer' table + CustomerTbContentDisplay(1010); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // InsertwhereSourceisXmlFunction + + static void InsertwhereSourceisBlob() + { + try + { + String xsdData = new String(); + xsdData=returnFileValues("cust1021.xml"); + byte[] byteArray=xsdData.getBytes(); + // Create a BLOB object + java.sql.Blob blobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(byteArray); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS A BLOB VARIABLE."); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1021); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1021,XMLPARSE(document " + + " cast(? as Blob) strip whitespace))\n" + + "\n"); + #sql { + INSERT INTO customer(cid,info) + VALUES(1021,XMLPARSE(document cast(:blobData as Blob) + strip whitespace))}; + + // display the content of the 'customer' table + CustomerTbContentDisplay(1021); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // InsertwhereSourceisBlob + + static void InsertBlobDataWithImplicitParsing() + { + try + { + String xsdData = new String(); + xsdData=returnFileValues("cust1022.xml"); + byte[] byteArray=xsdData.getBytes(); + // Create a BLOB object + java.sql.Blob blobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(byteArray); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS A BLOB VARIABLE" + + " WITH IMPLICIT PARSING" ); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1022); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1022," + + " cast(? as Blob) strip whitespace)\n" + + "\n"); + + #sql { + INSERT INTO customer(cid,info) + VALUES(1022, :blobData )}; + + + // display the content of the 'customer' table + CustomerTbContentDisplay(1022); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //InsertBlobDataWithImplicitParsing + + static void InsertwhereSourceisClob() + { + try + { + int customerid = 0; + String customerInfo = ""; + + String xsdData = new String(); + xsdData=returnFileValues("cust1023.xml"); + + // Create a CLOB Object + java.sql.Clob clobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createClob(xsdData); + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS A CLOB VARIABLE."); + + // display the content of the 'customer' table + // CustomerTbContentDisplay(1023); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1023,XMLPARSE(document " + + " cast(? as Clob) strip whitespace))\n" + + "\n"); + + #sql { + INSERT INTO customer(cid,info) + VALUES(1023,XMLPARSE(document cast(:clobData as Clob) + strip whitespace))}; + + // display the content of the 'customer' table + CustomerTbContentDisplay(1023); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // InsertwhereSourceisClob + + static void InsertwhereSourceisTypecastToXML() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM AN INSERT WHERE SOURCE IS TYPECAST TO XML."); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1031,XMLCAST(? AS XML))" + + "\n"); + + #sql { + INSERT INTO customer(cid,info) + VALUES(1031,XMLCAST(XMLPARSE(document '
56 hillview + kolarkarnataka
+
' preserve whitespace) as XML))}; + + //display the content of the 'customer' table + CustomerTbContentDisplay(1031); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // InsertwhereSourceisTypecastToXML + + static void InsertFromStringNotWellFormedXML() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n" + + "USE THE SQL STATEMENT:\n" + + " INSERT\n" + + "TO PERFORM INSERT WITH NOT WELL FORMED XML"); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1032); + + System.out.println(); + System.out.println(" Perform:\n" + + " INSERT INTO customer(cid,info)\n" + + " VALUES(1032, "+ + " 'divya" + + " ')\n" + + " \n"); + + #sql { + INSERT INTO customer(cid,info) VALUES(1032, + 'divya + ' )}; + + + // display the content of the 'customer' table + CustomerTbContentDisplay(1032); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + } + catch(Exception e) + {} + } //InsertFromStringNotWellFormedXML + + // helping function + static void preRequisites() + { + try + { + + // create table 'oldcustomer' + System.out.println("\nThe table oldcustomer is created in the setup script \n" + + "XmlInsert_setup.db2 using the command \n" + + "'CREATE TABLE oldcustomer(ocid integer, \n" + + " firstname varchar(15), \n" + + " lastname varchar(15), \n" + + " addr varchar(350), \n" + + " information XML)' \n"); + + // populate table oldcustomer with data + #sql { + INSERT INTO oldcustomer VALUES (1007,'Raghu','nandan', + 'tate>karnatakabangalore + ',XMLPARSE(document' +
24 gulmarg bangalore + karnataka
+
'preserve whitespace))}; + + #sql { + INSERT INTO oldcustomer VALUES(1008,'Rama','murthy','karnatakabelgaum + ',XMLPARSE(document'
12 gandhimarg + belgaumkarnataka +
'preserve whitespace))}; + + + #sql { + INSERT INTO oldcustomer VALUES(1009,'Rahul','kumar', + ' + Rahul25 Westend + MarkhamOntario + N9C-3T6 + 905-555-725 8',XMLPARSE(document + '
25 WestendMarkham + Ontario
' + preserve whitespace))}; + + #sql { + INSERT INTO oldcustomer VALUES(1010,'Sweta','Priya','karnatakakolar + ', XMLPARSE(document'
56 hillview + kolarkarnataka
+
'preserve whitespace))}; + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //preRequisites + + static void CustomerTbContentDisplay(int Cid) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + " SELECT cid,XMLSERIALIZE(info as varchar(600))\n" + + " FROM customer WHERE cid=" + Cid); + + TbXMLinsert_cursor1 cur1; + + #sql cur1 = {SELECT cid,XMLSERIALIZE(info as varchar(600)) + FROM customer WHERE cid = :Cid}; + + System.out.println( + " CUSTOMERID CUSTOMERINFO \n" + + " ---------- -------------- "); + + #sql {FETCH NEXT FROM :cur1 INTO :customerid, :customerInfo}; + + // retrieve and display the result from the SELECT statement + while (true) + { + if (cur1.endFetch()) + { + break; + } + System.out.println( + " " + + Data.format(customerid, 10) + " " + + Data.format(customerInfo, 1024)); + + #sql {FETCH NEXT FROM :cur1 INTO :customerid, :customerInfo}; + } + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // CustomerTableContentDisplay + + static void DeleteofRowwithXmlData() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "---------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO PERFORM A DELETE OF ROWS WITH XML DATA."); + + System.out.println(); + System.out.println(" Perform:\n" + + " DELETE FROM customer\n" + + " WHERE cid>=1007 and cid <= 1032\n" + + "\n"); + #sql { + DELETE FROM customer + WHERE cid>=1006 and cid <= 1032}; + + // display the content of the 'customer' table + CustomerTbContentDisplay(1007); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // DeleteofRowwithXmlData + + // this function will Read a file in a buffer and + // return the String value to called function + public static String returnFileValues(String fileName) + { + String record = null; + try + { + FileReader fr = new FileReader(fileName); + BufferedReader br = new BufferedReader(fr); + record = new String(); + record = br.readLine(); + String descReturn=record; + while ((record = br.readLine()) != null) + descReturn=descReturn+record; + return descReturn; + } + catch (Exception e) + { + // catch possible io errors from readLine() + System.out.println(" file " + fileName + "doesn't exist"); + + System.out.println(" Quitting program!"); + System.out.println(); + System.exit(-1); + } + return null; + }// returnFileValues + +}//XmlInsert diff --git a/xml/java/sqlj/XmlInsertScrpt b/xml/java/sqlj/XmlInsertScrpt new file mode 100644 index 0000000..0de35f0 --- /dev/null +++ b/xml/java/sqlj/XmlInsertScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: XmlInsertScrpt +# XmlInsert_cleanup.db2 drops tables created by XmlInsert_setup.db2 for the +# sample XmlInsert.sqlj +# XmlInsert_setup.db2 creates tables necessary for execution of the sample +# XmlInsert.sqlj +# Both CLP scripts can be run on their own +# Usage: XmlInsertScrpt + +db2 -tvf XmlInsert_cleanup.db2 +db2 -tvf XmlInsert_setup.db2 diff --git a/xml/java/sqlj/XmlInsert_cleanup.db2 b/xml/java/sqlj/XmlInsert_cleanup.db2 new file mode 100644 index 0000000..ff36a39 --- /dev/null +++ b/xml/java/sqlj/XmlInsert_cleanup.db2 @@ -0,0 +1,49 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlInsert_cleanup.db2 +-- +-- SAMPLE: Cleanup script for the sample XmlInsert.sqlj +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlInsert_cleanup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- drop table oldcustomer + +DROP TABLE OLDCUSTOMER; + +connect reset; diff --git a/xml/java/sqlj/XmlInsert_setup.db2 b/xml/java/sqlj/XmlInsert_setup.db2 new file mode 100644 index 0000000..9650c80 --- /dev/null +++ b/xml/java/sqlj/XmlInsert_setup.db2 @@ -0,0 +1,54 @@ +--------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlInsert_setup.db2 +-- +-- SAMPLE: This sample serves as the setup script for the sample +-- XmlInsert.sqlj +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlInsert_setup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- create table 'oldcustomer' + +CREATE TABLE oldcustomer(ocid integer, + firstname varchar(15), + lastname varchar(15), + addr varchar(350), + information XML); + +connect reset; diff --git a/xml/java/sqlj/XmlIntegrate.sqlj b/xml/java/sqlj/XmlIntegrate.sqlj new file mode 100644 index 0000000..2e91c36 --- /dev/null +++ b/xml/java/sqlj/XmlIntegrate.sqlj @@ -0,0 +1,549 @@ +//************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: XmlIntegrate.sqlj +// +// PURPOSE: To show how to use XMLROW and XMLGROUP functions to publish +// relational information as XML. +// To show XMLQuery default passing mechanism. +// To show default column specification for XMLTABLE. +// +// USAGE SCENARIO: The super marker manager maintains a database to store +// all customer's addresses in a relational table called +// "addr" so that whenever a customer places an order for +// any item, he can use this "addr" table to deliver the +// item. As the number of customers grew year after +// year,there was a need to change the table structure +// to have one single XML column for address and maintain +// the data in a new table called "custinfo_new". +// +// PREQUISITES : 1. Create the pre-requisite tables by running the command: +// XmlIntegrateScrpt +// Alternatively,you can run the command: +// db2 -tvf XmlIntegrate_setup.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj XmlIntegrate +// 2. Run the sample as: +// java XmlIntegrate +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf XmlIntegrate_cleanup.db2 +// +// INPUTS: NONE +// +// OUTPUTS: Shows comparison of XML documents created using different +// SQLXML functions and using XMLROW, XMLGROUP functions +// +// OUTPUT FILE: XmlIntegrate.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// INSERT +// SELECT +// +// SQL/XML FUNCTIONS USED: +// XMLROW +// XMLGROUP +// XMLDOCUMENT +// XMLELEMENT +// XMLCONCAT +// XMLATTRIBUTES +// +//************************************************************************ +// For more information about the command line processor (CLP) scripts, +// see the README file. +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, building, and running DB2 +// applications, visit the DB2 application development website: +// http://www.software.ibm.com/data/db2/udb/ad +// +//************************************************************************ +// +// SAMPLE DESCRIPTION +// +//************************************************************************ +// +// 1. Shows comparison of publishing XML documents using different +// SQL/XML functions and XMLROW function. +// +// 1.1 Element centric mapping comparison. +// +// 1.2 Attribute centric mapping comparison. +// +// 2. Shows the comparison of publishing XML documents using +// different SQL/XML publishing functions and XMLGROUP function. +// +// 3. Shows XMLQuery default parameter passing mechanism. +// +// 4. Shows default column specification for XMLTABLE. +// +//************************************************************************* +// +// IMPORT ALL PACKAGES AND CLASSES +// +//************************************************************************* + +import java.util.*; +import java.io.*; +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +//************************************************************************* +// +// DECLARE CURSORS +// +//************************************************************************* + +#sql iterator XmlIntegrate_cursor (int , String); +#sql iterator XmlIntegrate_cursor1 (String); +#sql iterator XmlIntegrate_cursor2 (int, String); + +class XmlIntegrate +{ + public static void main(String argv[]) + { + String url = "jdbc:db2:sample"; + DefaultContext ctx = null; + Connection con = null; + try + { + + //***************************************************************** + // + // SETUP + // + //***************************************************************** + + // Register the jcc driver + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // Connect to sample database + con = DriverManager.getConnection(url); + + // Set connection to default connection context + ctx = new DefaultContext(con); + DefaultContext.setDefaultContext(ctx); + + System.out.println("--------------------------------------------------"); + System.out.println("This sample shows "+ + "1. How to use XMLROW and XMLGROUP functions to publish"+ + " relational information as XML."); + System.out.println("2. Shows XMLQuery default passing mechanism"); + System.out.println("3. Shows default column specification for XMLTABLE"); + System.out.println("--------------------------------------------------"); + System.out.println("\n"); + + + + XmlRowUsage(); + XmlGroupUsage(); + XQueryPassingMechanism(); + XMLTABLEColSpec(); + + // close connection + con.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //main + + //********************************************************************* + // 1. Shows comparison of publishing XML documents using different + // SQL/XML functions and XMLROW function. + // + //********************************************************************* + static void XmlRowUsage() + { + try + { + // create table 'addr' + System.out.println("\nThe table addr is created in the setup script \n" + + "XmlIntegrate_setup.db2 using the command \n" + + "'CREATE TABLE addr (custid int, \n" + + " name varchar(20), \n" + + " street varchar(20), \n" + + " city varchar(20), \n" + + " province varchar(20), \n" + + " postalcode BIGINT)' \n"); + + // create table 'custinfo_new' + System.out.println("\nThe table custinfo_new is created in the setup script \n" + + "XmlIntegrate_setup.db2 using the command \n" + + "'CREATE TABLE custinfo_new(custid int, address XML)' \n"); + + //**************************************************************** + // 1.1 Element centric mapping comparison + //**************************************************************** + + // Insert values into "addr" table + #sql {INSERT INTO addr + VALUES (1000, 'suma', 'james street', + 'madras', 'Tamil Nadu', 560004)}; + + // Insert values into "custinfo_new" table and Create an XML + // document address with name, street, city, postal code columns + // in the "addr" table and display it along with custid details + + #sql {INSERT INTO custinfo_new (Custid, Address) + SELECT Custid, XMLDOCUMENT( + XMLElement(NAME "row",XMLCONCAT( + XMLElement(NAME "name", name OPTION NULL ON NULL), + XMLElement(NAME "street", street OPTION NULL ON NULL), + XMLElement(NAME "city", city OPTION NULL ON NULL), + XMLElement(NAME "province", province OPTION NULL ON NULL), + XMLElement(NAME "postalcode", postalcode OPTION NULL ON NULL)) + OPTION NULL ON NULL )) + FROM addr}; + + // Create an XML document using XMLROW function with name, street + // city, postalcode columns of "addr" table and insert into Address + // column of "custinfo_new" table + + #sql {INSERT INTO custinfo_new (Custid, Address) + (SELECT Custid, XMLROW(C.name, C.street, C.city, + C.province,C.postalcode) + FROM addr C)}; + + + System.out.println(" Check whether XML document created using "+ + "SQL/XML publishing functions and the one " + + "created with XMLROW are same."); + + XmlIntegrate_cursor cur1; + #sql cur1 = {SELECT custid, address + FROM custinfo_new}; + + + int customerId = 0; + String Addr = ""; + + System.out.println("CUSTOMERID ADDRESS"); + System.out.println("---------- ---------"); + + #sql {FETCH :cur1 INTO :customerId, :Addr}; + while(true) + { + if (cur1.endFetch()) + { + break; + } + System.out.println(Data.format(customerId, 20) + " "+ + Data.format(Addr, 1024)); + #sql {FETCH :cur1 INTO :customerId, :Addr}; + } + + //************************************************************ + // 1.2 Attribute Centric mapping comparison + //************************************************************ + + // Attribute centric mapping using case expressions in DB2 9 + System.out.println("------------------------------------------"); + System.out.println(" Attribute Centric mapping "); + System.out.println("------------------------------------------"); + + #sql cur1 = { SELECT Custid, CASE WHEN C.name is NULL and + C.street is NULL and + C.City is NULL and + C.province is NULL and + C.postalcode is NULL + THEN cast(NULL as XML) + ELSE XMLDOCUMENT(XMLElement(name "row", + XMLAttributes(C.name, C.street, + C.city, C.province, + C.postalcode))) + END + FROM addr C}; + + #sql {FETCH :cur1 INTO :customerId, :Addr}; + while(true) + { + if (cur1.endFetch()) + { + break; + } + System.out.println(Data.format(customerId, 20) + " "+ + Data.format(Addr, 1024)); + #sql {FETCH :cur1 INTO :customerId, :Addr}; + } + + + System.out.println("-----------------------------------------------"); + System.out.println("Attribute centric mapping using XMLROW function"); + System.out.println("-----------------------------------------------"); + #sql cur1 = {SELECT Custid, XMLROW(C.name, C.street, C.city, + C.province,C.postalcode OPTION AS ATTRIBUTES) + FROM addr C}; + + #sql {FETCH :cur1 INTO :customerId, :Addr}; + while(true) + { + if (cur1.endFetch()) + { + break; + } + System.out.println(Data.format(customerId, 20) + " "+ + Data.format(Addr, 1024)); + #sql {FETCH :cur1 INTO :customerId, :Addr}; + } + cur1.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //XmlRowUsage + + //************************************************************************* + // 2. Shows the comparison of publishing XML documents + // using different SQL/XML publishing functions and XMLGROUP function + // + //************************************************************************* + static void XmlGroupUsage() + { + try + { + + // Get all purchaseorders made by a particular customer as one single + // XML document + + XmlIntegrate_cursor1 cur1; + + System.out.println("-----------------------------------------------"); + System.out.println(" Create XML document using SQL/XML publishing "+ + "functions"); + System.out.println("-----------------------------------------------"); + + #sql cur1 = {SELECT XMLDOCUMENT(XMLElement(NAME "rowset", + XMLAGG(XMLElement(NAME "row", + XMLElement(NAME "orderdate", p.orderdate OPTION NULL ON NULL), + XMLElement(NAME "porder", p.porder OPTION NULL ON NULL) + OPTION NULL ON NULL)) + OPTION NULL ON NULL)) + FROM purchaseorder p, customer c + WHERE p.custid=c.Cid}; + + String Addr = ""; + + System.out.println("ADDRESS"); + System.out.println("---------"); + + #sql {FETCH :cur1 INTO :Addr}; + while(true) + { + if (cur1.endFetch()) + { + break; + } + System.out.println( Data.format(Addr, 5000)); + #sql {FETCH :cur1 INTO :Addr}; + } + + // Doing the same as above using XMLGROUP function + + System.out.println("----------------------------------------------"); + System.out.println("Create an XML document using XMLGROUP function"); + System.out.println("----------------------------------------------"); + + #sql cur1 = {SELECT XMLGROUP(p.orderdate, p.porder) + FROM purchaseorder p, customer c + WHERE p.custid=c.Cid}; + #sql {FETCH :cur1 INTO :Addr}; + while(true) + { + if (cur1.endFetch()) + { + break; + } + System.out.println( Data.format(Addr, 5000)); + #sql {FETCH :cur1 INTO :Addr}; + } + + cur1.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //XmlGroupUsage + + //************************************************************************* + // + // 3. Shows XMLQuery default parameter passing mechanism + // + //************************************************************************* + static void XQueryPassingMechanism() + { + try + { + String info=""; + int empno=0; + + + System.out.println("-------------------------------------------"); + System.out.println("XMLQuery default parameter passing mechanism"); + System.out.println("-------------------------------------------"); + + // create table 'employee' + System.out.println("\nThe table employee is created in the setup script \n" + + "XmlIntegrate_setup.db2 using the command \n" + + "'CREATE TABLE EMPLOYEE (empno int,lastname varchar(20), \n" + + " firstname varchar(20), workdept varchar(20), \n" + + " phoneno varchar(20), hireDate DATE)' \n"); + + + #sql {INSERT INTO employee + VALUES (100, 'latha', 'suma', 'Informix', '5114', '03/01/2006')}; + + XmlIntegrate_cursor2 cur1; + + System.out.println("SELECT empno, XMLQuery('"+ + "{$WORKDEPT}"+ + "{$PHONENO}"+ + "{$HIREDATE}')"+ + "FROM employee"); + System.out.println("\n"); + + #sql cur1 = {SELECT empno, XMLQuery(' + {$WORKDEPT} + {$PHONENO} + {$HIREDATE}') + FROM employee}; + + #sql {FETCH :cur1 INTO :empno, :info}; + + System.out.println(Data.format(empno, 20)+" "+ + Data.format(info, 200)); + cur1.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //XQueryPassingMechanism + + + //************************************************************************* + // + // 4. Shows the default column specification of XMLTABLE + // + //************************************************************************* + + static void XMLTABLEColSpec() + { + try + { + String info = ""; + XmlIntegrate_cursor1 cur1; + + System.out.println("--------------------------------------------------"); + System.out.println("Shows the default column specification of XMLTABLE"); + System.out.println("--------------------------------------------------"); + + System.out.println("SELECT X.* FROM XMLTABLE ('db2-fn:xmlcolumn " + + "(\"CUSTOMER.INFO\")/customerinfo/phone') as X"); + System.out.println("\n"); + + #sql cur1 = {SELECT X.* FROM XMLTABLE ('db2-fn:xmlcolumn + ("CUSTOMER.INFO")/customerinfo/phone') as X}; + + #sql {FETCH :cur1 INTO :info}; + while(true) + { + if (cur1.endFetch()) + { + break; + } + + System.out.println("INFO"); + System.out.println("-----"); + + System.out.println(Data.format(info, 1024)); + #sql {FETCH :cur1 INTO :info}; + } + cur1.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //XMLTABLEColSpec +} //class XmlIntegrate diff --git a/xml/java/sqlj/XmlIntegrateScrpt b/xml/java/sqlj/XmlIntegrateScrpt new file mode 100644 index 0000000..2fb94fe --- /dev/null +++ b/xml/java/sqlj/XmlIntegrateScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: XmlIntegrateScrpt +# XmlIntegrate_cleanup.db2 drops tables created by XmlIntegrate_setup.db2 for the +# sample XmlIntegrate.sqlj +# XmlIntegrate_setup.db2 creates tables necessary for execution of the sample +# XmlIntegrate.sqlj +# Both CLP scripts can be run on their own +# Usage: XmlIntegrateScrpt + +db2 -tvf XmlIntegrate_cleanup.db2 +db2 -tvf XmlIntegrate_setup.db2 diff --git a/xml/java/sqlj/XmlIntegrate_cleanup.db2 b/xml/java/sqlj/XmlIntegrate_cleanup.db2 new file mode 100644 index 0000000..95dd0d5 --- /dev/null +++ b/xml/java/sqlj/XmlIntegrate_cleanup.db2 @@ -0,0 +1,51 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlIntegrate_cleanup.db2 +-- +-- SAMPLE: Cleanup script for the sample XmlIntegrate.sqlj +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlIntegrate_cleanup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- drop the tables addr, custinfo_new and employee + +DROP TABLE addr; +DROP TABLE custinfo_new; +DROP TABLE employee; + +connect reset; diff --git a/xml/java/sqlj/XmlIntegrate_setup.db2 b/xml/java/sqlj/XmlIntegrate_setup.db2 new file mode 100644 index 0000000..238d696 --- /dev/null +++ b/xml/java/sqlj/XmlIntegrate_setup.db2 @@ -0,0 +1,65 @@ +--------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlIntegrate_setup.db2 +-- +-- SAMPLE: This sample serves as the setup script for the samples +-- XmlIntegrate.sqlj +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlIntegrate_setup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- create table addr + +CREATE TABLE addr (custid int, + name varchar(20), + street varchar(20), + city varchar(20), + province varchar(20), + postalcode BIGINT); + +-- create table custinfo_new + +CREATE TABLE custinfo_new(custid int, address XML); + +-- create table employee + +CREATE TABLE EMPLOYEE (empno int,lastname varchar(20), + firstname varchar(20), workdept varchar(20), phoneno + varchar(20), hireDate DATE); + +connect reset; diff --git a/xml/java/sqlj/XmlRead.sqlj b/xml/java/sqlj/XmlRead.sqlj new file mode 100644 index 0000000..c28c22c --- /dev/null +++ b/xml/java/sqlj/XmlRead.sqlj @@ -0,0 +1,246 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlRead.sqlj +// +// SAMPLE: How to read XML columns from the table. +// +// SQL Statements USED: +// FETCH +// SELECT +// +// Classes used from Util.sqlj are: +// Db +// SqljException +// +// OUTPUT FILE: XmlRead.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.util.*; +import java.io.*; +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator TbXMLRead_cursor1(int, String); +#sql iterator TbXMLRead_cursor2(int, java.sql.Clob); +#sql iterator TbXMLRead_cursor3(int, java.sql.Blob); + +class XmlRead +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + System.out.println(); + System.out.println( + "THIS SAMPLE SHOWS HOW TO READ TABLE DATA."); + + // connect to the 'sample' database + db.getDefaultContext(); + + // read table data + execQuery(); + ReadClobData(); + ReadBlobData(); + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (Exception e) + { + SqljException sqljExc = new SqljException(e); + sqljExc.handle(); + } + } // main + + static void execQuery() + { + try + { + System.out.println(); + System.out.println( + "-------------------------------------------\n" + + "USE SQL SELECT \n" + + " Statement\n" + + "TO EXECUTE A QUERY."); + + + // execute the query + System.out.println(); + System.out.println( + " Execute Statement:\n" + + " SELECT cid,XMLSERIALIZE(info as varchar(600)"+ + " FROM customer WHERE cid < 1005 ORDER BY cid"); + + TbXMLRead_cursor1 cur1; + + #sql cur1 = { + SELECT cid,XMLSERIALIZE(info as varchar(600)) + FROM customer WHERE cid < 1005 ORDER BY cid}; + + System.out.println(); + System.out.println(" Results:\n" + + " CUSTOMERID CUSTOMERINFO \n" + + " ---------- --------------"); + + int customerid = 0; + String customerInfo = ""; + + // Read the data into customerid and customerInfo variables + #sql {FETCH :cur1 INTO :customerid, :customerInfo}; + + while (true) + { + if (cur1.endFetch()) + { + break; + } + + System.out.println(" " + + Data.format(customerid,10) + " " + + Data.format(customerInfo, 1024)); + #sql {FETCH :cur1 INTO :customerid, :customerInfo}; + } + } + catch (Exception e) + { + System.out.println(e); + } + } //execQuery + + static void ReadClobData() + { + try + { + int customerid = 0; + + String xmlData = ""; + // Create a CLOB object + java.sql.Clob clobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createClob(xmlData); + + System.out.println(); + System.out.println(" READ CLOB DATA FROM XML COLUMN\n"); + + TbXMLRead_cursor2 cur2; + + System.out.println("SELECT cid, XMLSERIALIZE(info as clob)" + + " from customer where cid < 1005 ORDER BY cid"); + + #sql cur2 = {SELECT cid, XMLSERIALIZE(info as clob) + from customer where cid < 1005 ORDER BY cid}; + + #sql {FETCH :cur2 INTO :customerid, :clobData}; + + String temp_clob = null; + + while(true) + { + if (cur2.endFetch()) + { + break; + } + + System.out.println(" " + + Data.format(customerid, 10) + " "); + + temp_clob = clobData.getSubString(1,(int) clobData.length()); + System.out.println(temp_clob); + + #sql {FETCH :cur2 INTO :customerid, :clobData}; + } + } + catch (Exception e) + { + System.out.println(e); + } + } //ReadClobData + + static void ReadBlobData() + { + try + { + int customerid = 0; + Blob blobData = null; + + System.out.println(); + System.out.println(" READ BLOB DATA FROM XML COLUMN\n"); + + TbXMLRead_cursor3 cur3; + + System.out.println("SELECT cid, " + + "XMLSERIALIZE(info as blob)" + + " from customer where cid < 1005 ORDER BY cid"); + + #sql cur3 = {SELECT cid, + XMLSERIALIZE(info as blob) + from customer where cid < 1005 ORDER BY cid}; + + #sql {FETCH :cur3 INTO :customerid, :blobData}; + + while(true) + { + if (cur3.endFetch()) + { + break; + } + + System.out.println(" " + + Data.format(customerid, 10) + " "); + + String temp_string = ""; + byte[] Array=blobData.getBytes(1, (int) blobData.length()); + + for (int i =0; i < Array.length; i++ ) + { + char temp_char; + temp_char = (char)Array[i]; + temp_string += temp_char; + } + + System.out.println(temp_string); + System.out.println(); + + #sql {FETCH :cur3 INTO :customerid, :blobData}; + } + } + catch (Exception e) + { + System.out.println(e); + } + } //ReadBlobData +} //XmlRead diff --git a/xml/java/sqlj/XmlSchema.sqlj b/xml/java/sqlj/XmlSchema.sqlj new file mode 100644 index 0000000..3aa41de --- /dev/null +++ b/xml/java/sqlj/XmlSchema.sqlj @@ -0,0 +1,263 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlSchema.sqlj +// +// SAMPLE: How to register an XML Schema +// SAMPLE USAGE SCENARIO: Consider a user who needs to insert an XML type value +// into the table. The user would like to ensure that the XML value conforms to a +// deterministic XML schema. +// +// PROBLEM: User has schema's for all the XML values and like to validate the values +// as per schema while inserting it to the tables. +// +// SOLUTION: +// To achieve the goal, the sample will follow the following steps: +// a) Register the primary XML schema +// b) Add the XML schema documents to the primary XML schema to ensure that the +// schema is deterministic +// c) Insert an XML value into an existing XML column and perform validation +// +// SQL Statements USED: +// INSERT +// +// Stored Procedure USED +// SYSPROC.XSR_REGISTER +// SYSPROC.XSR_ADDSCHEMADOC +// SYSPROC.XSR_COMPLETE +// +// SQL/XML Function USED +// XMLVALIDATE +// XMLPARSE +// +// PREREQUISITE: copy product.xsd, order.xsd, +// customer.xsd, header.xsd Schema files, order.xml XML +// document from xml/data directory to working +// directory. +// +// OUTPUT FILE: XmlSchema.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.io.*; +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +class XmlSchema +{ + private static DefaultContext ctx; //Default context for the sample + private static String relSchema=new String("POSAMPLE"); //Relational Schema + private static String schemaName=new String("order"); //XML Schema ID + private static String schemaLocation= new String("http://www.test.com/order"); + private static String primaryDocument= new String("order.xsd");// Primary schema name + private static String multipleSchema1= new String("header.xsd"); + private static String multipleSchema2= new String("customer.xsd"); + private static String multipleSchema3= new String("product.xsd"); + private static String xmlDocName = new String("order.xml"); + private static int shred = 0; + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + ctx= new DefaultContext(con); + // set the default context for the sample + DefaultContext.setDefaultContext(ctx); + System.out.println(); + // register the XML Schema + registerXmlSchema(); + // insert the XML value validating according to the registered schema + insertValidatexml(); + // drop the registered the schema + #sql { DROP XSROBJECT POSAMPLE.ORDER }; + System.out.println("SCHEMA DROPPED SUCCESSFULLY"); + // delete the row inserted + #sql { DELETE FROM PURCHASEORDER WHERE POID=10 }; + System.out.println("ROW DELETED"); + con.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// main + + // This function will register the Primary XML Schema + static void registerXmlSchema() + { + String xsdData = new String(); + xsdData=returnFileValues(primaryDocument); + byte[] byteArray=xsdData.getBytes(); + java.sql.Blob blobData = com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(byteArray); + try + { + // register primary XML Schema + System.out.println("Registering main schema "+ primaryDocument +"..."); + #sql { CALL SYSPROC.XSR_REGISTER (:relSchema,:schemaName,:schemaLocation,:blobData, NULL )}; + // add XML Schema document to the primary schema + System.out.println(" Adding XML Schema document "+ multipleSchema1 +"..."); + addXmlSchemaDoc(multipleSchema1); + System.out.println(" Adding XML Schema document "+ multipleSchema2 +"..."); + addXmlSchemaDoc(multipleSchema2); + System.out.println(" Adding XML Schema document " + multipleSchema3 +"..."); + addXmlSchemaDoc(multipleSchema3); + System.out.println(" Completing XML Schema registeration"); + // complete the registeration + #sql { CALL SYSPROC.XSR_COMPLETE(:relSchema,:schemaName,NULL,:shred)}; + System.out.println("Schema registered successfully"); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// registerXmlSchema + + // This function will ADD the Schema document to already registered schema. + // The Schema documents referred in the primary XML schema (using Import or include) + // should be added to the registered schema before completing the registeration. + public static void addXmlSchemaDoc(String schemaDocName) + { + try + { + String xsdData = new String(); + xsdData=returnFileValues(schemaDocName); + byte[] byteArray=xsdData.getBytes(); + // Create a BLOB object + java.sql.Blob blobData = com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(byteArray); + #sql { CALL XSR_ADDSCHEMADOC(:relSchema,:schemaName,:schemaLocation,:blobData, NULL )}; + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// addXmlSchemaDoc + + // this function will insert the XML value in the table validating it according + // to the registered schema + public static void insertValidatexml() + { + try + { + int poid=10; + String status=new String("shipped"); + String xmlData = new String(); + xmlData=returnFileValues(xmlDocName); + System.out.println(" Inserting the following XML value validating it according to the schema posample.order"); + System.out.println(xmlData); + byte[] byteArray=xmlData.getBytes(); + java.sql.Blob blobData = com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(byteArray); + #sql {INSERT INTO PURCHASEORDER(poid,status,porder) VALUES(:poid,:status,xmlvalidate(DOCUMENT cast(:blobData as XML) according to xmlschema id posample.order))}; + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// insertValidatexml + + // this function will Read a file in a buffer and return the String value to calling function + public static String returnFileValues(String fileName) + { + String record = null; + try + { + FileReader fr = new FileReader(fileName); + BufferedReader br = new BufferedReader(fr); + record = new String(); + record = br.readLine(); + String descReturn=record; + while ((record = br.readLine()) != null) + descReturn=descReturn+record; + return descReturn; + } + catch (IOException e) + { + // catch possible io errors from readLine() + System.out.println(" file " + fileName + "doesn't exist"); + System.out.println(" Can not continue with insert, please verify "+fileName+" and try again ."); + System.out.println(" Quitting program!"); + System.out.println(); + System.exit(-1); + } + return null; + }// returnFileValues +}// XmlSchema diff --git a/xml/java/sqlj/XmlToTable.sqlj b/xml/java/sqlj/XmlToTable.sqlj new file mode 100644 index 0000000..74f6cf6 --- /dev/null +++ b/xml/java/sqlj/XmlToTable.sqlj @@ -0,0 +1,347 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlToTable.sqlj +// +// SAMPLE USAGE SCENARIO:Purchase order XML document contains detailed +// information about all the orders. It will also have the detail of the +// customer with each order. +// +// PROBLEM: The document has some redundant information as customer info +// and product info is repeated in each order for example +// Customer info is repeated for each order from same customer. +// Product info will be repeated for each order of same product from different customers. +// +// SOLUTION: The sample database has tables with both relational and XML data to remove +// this redundant information. These relational tables will be used to store +// the customer info and product info in the relational table having XML data +// and id value. Purchase order will be stored in another table and it will +// reference the customerId and productId to refer the customer and product +// info respectively. +// +// To achieve the above goal this sample will shred the data for purchase order XML +// document and insert it into the tables. +// +// The sample will follow the following steps +// +// 1. Get the relevant data in XML format from the purchase order XML document (use XMLQuery) +// 2. Shred the XML doc into the relational table. (Use XMLTable) +// 3. Select the relevant data from the table and insert into the target relational table. +// +// PREQUISITES : 1. Copy the file purchaseorder.xml from the xml/data directory to +// the current working directory +// 2. Create the pre-requisite tables by running the command: +// XmlToTableScrpt +// Alternatively,you can run the command: +// db2 -tvf XmlToTable_setup.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj XmlToTable +// 2. Run the sample as: +// java XmlToTable +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf XmlToTable_cleanup.db2 +// +// SQL Statements USED: +// SELECT +// INSERT +// +// XML Functions USED: +// XMLCOLUMN +// XMLELEMENT +// XMLTABLE +// XMLDOCUMENT +// XMLATTRIBTES +// XMLCONCAT +// XQUERY +// +// OUTPUT FILE: XmlToTable.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +// +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +// Define the iterator to use in the functions +#sql iterator Positioned_Iterator1(int, String); + +class XmlToTable +{ + static int num_record_customer=0; + static int num_record_po=0; + + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + DefaultContext ctx=null; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + ctx= new DefaultContext(con); + + // set the default context for the sample + DefaultContext.setDefaultContext(ctx); + System.out.println(); + + // call PO_shre method + PO_shred(); + + // display the content of the purchaseorder table + displayContent(); + + // clean up + cleanUp(); + + con.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// main + + static void PO_shred() + { + String purchaseorder; + String data=null; + + try + { + Statement stmt1 = DefaultContext.getDefaultContext().getConnection().createStatement(); + + // create table po + System.out.println("The purchaseorder table PO is created in the setup script \n" + + "XmlToTable_setup.db2 using the command \n" + + "'CREATE TABLE PO (purchaseorder XML)' \n"); + + purchaseorder = returnFileValues("purchaseorder.xml"); + #sql { INSERT INTO PO(purchaseorder) values (:purchaseorder)}; + + // run the XQuery to find out the purchaseorder with status shipped + ResultSet rs=stmt1.executeQuery("XQUERY db2-fn:xmlcolumn('PO.PURCHASEORDER')/PurchaseOrders/PurchaseOrder[@Status='shipped']"); + + // iterate for all the rows, insert the data into the relational table + while(rs.next()) + { + data=rs.getString(1); + // insert into customer table + System.out.println("Inserting into customer table ...."); + #sql { INSERT INTO customer(CID,info,history) SELECT T.CustID,xmldocument + (XMLELEMENT(NAME "customerinfo",XMLATTRIBUTES (T.CustID as "Cid"), + XMLCONCAT( XMLELEMENT(NAME "name", T.Name ), T.Addr, + XMLELEMENT(NAME "phone", XMLATTRIBUTES(T.type as "type"), T.Phone) + ))), xmldocument(T.History) + FROM XMLTABLE( '$d/PurchaseOrder' PASSING cast(:data as XML) AS "d" + COLUMNS CustID BIGINT PATH '@CustId', + Addr XML PATH './Address', + Name VARCHAR(20) PATH './name', + Country VARCHAR(20) PATH './Address/@country', + Phone VARCHAR(20) PATH './phone', + Type VARCHAR(20) PATH './phone/@type', + History XML PATH './History') as T + WHERE T.CustID NOT IN (SELECT CID FROM customer) }; + + num_record_customer++; + System.out.println("Inserting into purchaseorder table .....\n"); + #sql { INSERT INTO purchaseOrder(poid, orderdate, custid,status, porder, comments) + SELECT poid, orderdate, custid, status,xmldocument(XMLELEMENT(NAME "PurchaseOrder", + XMLATTRIBUTES(T.Poid as "PoNum", T.OrderDate as "OrderDate", + T.Status as "Status"), + T.itemlist)), comment + FROM XMLTable ('$d/PurchaseOrder' PASSING cast(:data as XML) as "d" + COLUMNS poid BIGINT PATH '@PoNum', + orderdate date PATH '@OrderDate', + CustID BIGINT PATH '@CustId', + status varchar(10) PATH '@Status', + itemlist XML PATH './itemlist', + comment varchar(1024) PATH './comments') as T }; + + num_record_po++; + } + + // close the resultset + rs.close(); + + System.out.println("Number of rows inserted in customer table: " + num_record_customer); + System.out.println("Number of rows inserted in purchaseorder table: " + num_record_po); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } + public static String returnFileValues(String fileName) + { + String record = null; + try + { + FileReader fr = new FileReader(fileName); + BufferedReader br = new BufferedReader(fr); + + record = new String(); + + record = br.readLine(); + String descReturn=record; + while ((record = br.readLine()) != null) + descReturn=descReturn+record; + return descReturn; + } + catch (IOException e) + { + // catch possible io errors from readLine() + System.out.println(" file " + fileName + "doesn't exist"); + System.out.println(" Can not continue with insert, please verify "+fileName+" and try again."); + System.out.println(" Quitting program!"); + System.out.println(); + System.exit(-1); + } + return null; + }// returnFileValues + + static void displayContent() + { + String data=null; + int cid = 0; + try + { + + Positioned_Iterator1 custIter=null; + System.out.println("CONTENT OF CUSTOMER TABLE"); + #sql custIter = { SELECT CID, INFO FROM CUSTOMER }; + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :cid, :data}; + + if (custIter.endFetch()) + { + break; + } + // print the result + System.out.println(); + System.out.println("CUSTOMER "+cid); + System.out.println(); + System.out.println("INFO " +data); + } + + // close the cursor + custIter.close(); + System.out.println("CONTENT OF PURCHASEORDER TABLE"); + + #sql custIter = { SELECT poid, porder FROM PURCHASEORDER }; + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :cid, :data}; + + if (custIter.endFetch()) + { + break; + } + // print the result + System.out.println(); + System.out.println("POID "+cid); + System.out.println(); + System.out.println("PORDER "+ data); + } + + // close the cursor + custIter.close(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) {} + System.exit(1); + } + + } // displayContent + static void cleanUp() + { + try + { + #sql { DELETE FROM PURCHASEORDER WHERE POID IN (110,111) }; + #sql { DELETE FROM CUSTOMER WHERE CID IN (10,11) }; + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) {} + System.exit(1); + } + + + } +} // XmlToTable diff --git a/xml/java/sqlj/XmlToTableScrpt b/xml/java/sqlj/XmlToTableScrpt new file mode 100644 index 0000000..9791c2e --- /dev/null +++ b/xml/java/sqlj/XmlToTableScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: XmlToTableScrpt +# XmlToTable_cleanup.db2 drops tables created by XmlToTable_setup.db2 for the +# sample XmlToTable.sqlj +# XmlToTable_setup.db2 creates tables necessary for execution of the sample +# XmlToTable.sqlj +# Both CLP scripts can be run on their own +# Usage: XmlToTableScrpt + +db2 -tvf XmlToTable_cleanup.db2 +db2 -tvf XmlToTable_setup.db2 diff --git a/xml/java/sqlj/XmlToTable_cleanup.db2 b/xml/java/sqlj/XmlToTable_cleanup.db2 new file mode 100644 index 0000000..918bbe1 --- /dev/null +++ b/xml/java/sqlj/XmlToTable_cleanup.db2 @@ -0,0 +1,49 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlToTable_cleanup.db2 +-- +-- SAMPLE: Cleanup script for the sample XmlToTable.sqlj +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlToTable_cleanup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- drop the table po + +DROP TABLE PO; + +connect reset; diff --git a/xml/java/sqlj/XmlToTable_setup.db2 b/xml/java/sqlj/XmlToTable_setup.db2 new file mode 100644 index 0000000..47fff3a --- /dev/null +++ b/xml/java/sqlj/XmlToTable_setup.db2 @@ -0,0 +1,50 @@ +--------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlToTable_setup.db2 +-- +-- SAMPLE: This sample serves as the setup script for the samples +-- XmlToTable.sqlj +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlToTable_setup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- create table po + +CREATE TABLE PO (id INT GENERATED ALWAYS AS IDENTITY,purchaseorder XML); + +connect reset; diff --git a/xml/java/sqlj/XmlUpDel.sqlj b/xml/java/sqlj/XmlUpDel.sqlj new file mode 100644 index 0000000..bbda66e --- /dev/null +++ b/xml/java/sqlj/XmlUpDel.sqlj @@ -0,0 +1,860 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XmlUpDel.sqlj +// +// SAMPLE: How to insert XML document into a column of XML Datatype +// +// SQL Statements USED: +// INSERT +// ROLLBACK +// +// Classes used from Util.sqlj are: +// Db +// SqljException +// +// PREQUISITES : 1. copy the files cust1021.xml, cust1022 and +// cust1023.xml to working directory +// 2. Create the pre-requisite tables by running the command: +// XmlUpDelScrpt +// Alternatively,you can run the command: +// db2 -tvf XmlUpDel_setup.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj XmlUpDel +// 2. Run the sample as: +// java XmlUpDel +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf XmlUpDel_cleanup.db2 +// +// OUTPUT FILE: XmlUpDel.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ +import java.lang.*; +import java.util.*; +import java.io.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +#sql iterator TbXMLUpDel_cursor1(int, String); + +class XmlUpDel +{ + public static void main(String argv[]) + { + try + { + Db db = new Db(argv); + + // Connect to 'sample' database + db.getDefaultContext(); + + System.out.println(); + System.out.println("THIS SAMPLE SHOWS HOW TO UPDATE TABLE HAVING"+ + "XML COLUMNS. \n"); + + preRequisites(); + mostSimpleUpdatewithConstantString(); + UpdatewhereSourceisAnotherXmlColumn(); + UpdatewhereSourceisAnotherStringColumn(); + UpdateAnotherStringColumnWithImplicitParsing(); + UpdateUsingVarcharWithImplicitParsing(); + UpdatewithValidation(); + UpdatewhereSourceisBlob(); + UpdatewhereSourceisBlobWithImplicitParsing(); + UpdatewhereSourceisClob(); + SetRegisterWithPreserveWhitespace(); + DeleteofRowwithXmlData(); + + + // disconnect from the 'sample' database + db.disconnect(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + } //main + + static void mostSimpleUpdatewithConstantString() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM A SIMPLE UPDATE."); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=XMLPARSE(document'"+ + " rohitpark street\n" + + " delhi'preserve" + + " whitespace) WHERE cid=1008\n" + + " \n"); + + #sql { + UPDATE customer + SET info=XMLPARSE(document' + rohitpark street + delhi'preserve whitespace) + WHERE cid=1008}; + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // mostSimpleUpdatewithConstantString + + static void UpdatewhereSourceisAnotherXmlColumn() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println( + "----------------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM AN UPDATE WHERE SOURCE IS FROM ANOTHER XML COLUMN."); + + // display the content of the 'customer' table + // CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=(SELECT information FROM oldcust p\n" + + " WHERE p.ocid=1009)\n" + + " WHERE cid=1008\n" + + "\n"); + + #sql { + UPDATE customer + SET info=(SELECT information + FROM oldcust p + WHERE p.ocid=1009) + WHERE cid=1008}; + + System.out.println(); + System.out.println(); + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // UpdatewhereSourceisAnotherXmlColumn + + static void UpdatewhereSourceisAnotherStringColumn() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "--------------------------------------------\n\n" + + " USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + " TO PERFORM AN UPDATE WHERE SOURCE IS FROM "+ + " ANOTHER STRING COLUMN."); + + // display the content of the 'customer' table + // CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=(SELECT XMLPARSE(document addr preserve whitespace)\n" + + " FROM oldcust p\n" + + " WHERE p.ocid=1009)\n" + + " WHERE cid=1008\n" + + "\n"); + + #sql { + UPDATE customer + SET info=(SELECT XMLPARSE(document addr preserve whitespace) + FROM oldcust p + WHERE p.ocid=1009) + WHERE cid=1008}; + + System.out.println(); + System.out.println(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // UpdatewhereSourceisAnotherStringColumn + + static void UpdateAnotherStringColumnWithImplicitParsing() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "--------------------------------------------\n\n" + + " USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + " TO PERFORM AN UPDATE WHERE SOURCE IS FROM "+ + " ANOTHER STRING COLUMN" + + " WITH IMPLICIT PARSING."); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=SELECT addr " + + " FROM oldcust p\n" + + " WHERE p.ocid=1009)\n" + + " WHERE cid=1008\n" + + "\n"); + + #sql { + UPDATE customer + SET info=(SELECT addr + FROM oldcust p + WHERE p.ocid=1009) + WHERE cid=1008}; + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //UpdateAnotherStringColumnWithImplicitParsing + + static void UpdateUsingVarcharWithImplicitParsing() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "----------------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM A UPDATE USING VARCHAR WITH IMPLICIT PARSING."); + + // display the content of the 'customer' table + // CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info='"+ + " rohitpark street\n" + + " delhi'" + + " WHERE cid=1008\n" + + " \n"); + + #sql { + UPDATE customer + SET info = ' + rohitpark street + delhi' + WHERE cid=1008}; + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + } //UpdateUsingVarcharWithImplicitParsing + + static void UpdatewithValidation() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + " TO PERFORM AN UPDATE WITH VALIDATION WHERE "+ + " SOURCE IS TYPED OF VARCHAR."); + + // display the content of the 'customer' table + // CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET info=(SELECT XMLVALIDATE(XMLPARSE"+ + " (document addr preserve whitespace)\n" + + " according to XMLSCHEMA ID customer)\n" + + " FROM oldcust p\n" + + " WHERE p.ocid=1009)\n" + + " WHERE cid=1008\n" + + "\n"); + + #sql { + UPDATE customer + SET info=(SELECT XMLVALIDATE(XMLPARSE(document + addr preserve whitespace) + according to XMLSCHEMA ID customer) + FROM oldcust p + WHERE p.ocid=1009) + WHERE cid=1008}; + + System.out.println(); + System.out.println(); + + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + } // UpdatewithValidation + + static void UpdatewhereSourceisBlob() + { + try + { + int customerid = 0; + String customerInfo = ""; + + String xsdData = new String(); + xsdData=returnFileValues("cust1021.xml"); + byte[] Array=xsdData.getBytes(); + + // Create a BLOB object + java.sql.Blob blobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(Array); + + System.out.println(); + System.out.println( + "-------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM AN UPDATE WHERE SOURCE IS A BLOB VARIABLE."); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET INFO= XMLPARSE(document " + + " cast(? as Blob) strip whitespace)\n" + + " WHERE cid=1008\n" + + "\n"); + + #sql { + UPDATE customer SET INFO = XMLPARSE( + document cast(:blobData as Blob) strip whitespace) + WHERE cid=1008}; + + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // UpdatewhereSourceisBlob + + static void UpdatewhereSourceisBlobWithImplicitParsing() + { + try + { + int customerid = 0; + String customerInfo = ""; + + String xsdData = new String(); + xsdData=returnFileValues("cust1022.xml"); + byte[] Array=xsdData.getBytes(); + + // Create a BLOB object + java.sql.Blob blobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createBlob(Array); + + System.out.println(); + System.out.println( + "-------------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM AN UPDATE WHERE SOURCE IS A BLOB VARIABLE"+ + " WITH IMPLICIT PARSING \n"); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET INFO= :blobData " + + " WHERE cid=1008\n" + + "\n"); + + #sql { + UPDATE customer SET INFO = + :blobData + WHERE cid=1008}; + + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //UpdatewhereSourceisBlobWithImplicitParsing + + static void UpdatewhereSourceisClob() + { + try + { + int customerid = 0; + String customerInfo = ""; + + String Data = new String(); + Data=returnFileValues("cust1023.xml"); + + // Create a CLOB object + java.sql.Clob clobData = + com.ibm.db2.jcc.t2zos.DB2LobFactory.createClob(Data); + + System.out.println(); + System.out.println( + "----------------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " UPDATE\n" + + "TO PERFORM AN UPDATE WHERE SOURCE IS A CLOB VARIABLE."); + + // display the content of the 'customer' table + //CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " UPDATE customer\n" + + " SET INFO= XMLPARSE(document " + + " cast(? as Clob) strip whitespace)\n" + + " WHERE cid=1008\n" + + "\n"); + + #sql { + UPDATE customer + SET INFO=XMLPARSE(document cast(:clobData as Clob) strip whitespace) + WHERE cid=1008}; + + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // UpdatewhereSourceisClob + + static void SetRegisterWithPreserveWhitespace() + { + try + { + String parse_option = "preserve whitespace"; + + System.out.println(); + System.out.println( + "--------------------------------------------\n\n" + + " USE THE SQL STATEMENT:\n" + + " SET CURRENT\n" + + " TO SET CURRENT IMPLICIT XMLPARSE OPTION\n"); + + // display the content of the 'customer' table + // CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + "SET CURRENT IMPLICIT XMLPARSE OPTION\n"); + + #sql { + SET CURRENT IMPLICIT XMLPARSE OPTION = :parse_option}; + + System.out.println(); + System.out.println(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //SetRegisterWithPreserveWhitespace + + // helping function + static void preRequisites() + { + try + { + //create table 'oldcust' + + System.out.println("The table oldcust is created in the setup script \n" + + "XmlUpDel_setup.db2 using the command \n" + + "'CREATE TABLE oldcust(ocid integer, \n" + + " firstname varchar(15), \n" + + " lastname varchar(15), \n" + + " addr varchar(400), \n" + + " information XML)' \n"); + + // populate table oldcust with data + + System.out.println("Insert row into oldcust table \n"); + #sql { + INSERT INTO oldcust VALUES(1009,'Rahul','kumar', + ' + Rahul25 + MarkhamOntario + N9C-3T6 + 905-555-725 8',XMLPARSE(document + '
25 WestendMarkham + Ontario
' + preserve whitespace))}; + + System.out.println("Insert row into customer table \n"); + + #sql { + INSERT INTO customer(cid,info) VALUES(1008 ,XMLPARSE(document + 'divya' + preserve whitespace))}; + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //preRequisites + + static void CustomerTbContentDisplay(int Cid) + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + " SELECT cid,XMLSERIALIZE(info as varchar(600))\n" + + " FROM customer WHERE cid=" + Cid); + + TbXMLUpDel_cursor1 cur1; + + #sql cur1 = {SELECT cid,XMLSERIALIZE(info as varchar(600)) FROM customer WHERE customer.cid = :Cid}; + + System.out.println( + " CUSTOMERID CUSTOMERINFO \n" + + " ---------- -------------- "); + + #sql {FETCH :cur1 INTO :customerid, :customerInfo}; + + // retrieve and display the result from the SELECT statement + while (true) + { + if (cur1.endFetch()) + { + break; + } + System.out.println( + " " + + Data.format(customerid, 10) + " " + + Data.format(customerInfo, 1024)); + + #sql {FETCH :cur1 INTO :customerid, :customerInfo}; + } + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // CustomerTableContentDisplay + + + // this function will Read a file in a buffer + // and return the String value to cal + public static String returnFileValues(String fileName) + { + String record = null; + try + { + FileReader fr = new FileReader(fileName); + BufferedReader br = new BufferedReader(fr); + record = new String(); + record = br.readLine(); + String descReturn=record; + while ((record = br.readLine()) != null) + descReturn=descReturn+record; + return descReturn; + } + catch (Exception e) + { + // catch possible io errors from readLine() + System.out.println(" file " + fileName + "doesn't exist"); + + System.out.println(" Quitting program!"); + System.out.println(); + System.exit(-1); + } + return null; + }// returnFileValues + + static void DeleteofRowwithXmlData() + { + try + { + int customerid = 0; + String customerInfo = ""; + + System.out.println(); + System.out.println( + "---------------------------------------\n\n" + + "USE THE SQL STATEMENT:\n" + + " DELETE\n" + + "TO PERFORM A DELETE OF ROWS WITH XML DATA."); + + // display the content of the 'customer' table + // CustomerTbContentDisplay(1008); + + System.out.println(); + System.out.println(" Perform:\n" + + " DELETE FROM customer\n" + + " WHERE cid=1008\n" + + "\n"); + #sql { + DELETE FROM customer + WHERE cid=1008}; + + // display the content of the 'customer' table + CustomerTbContentDisplay(1008); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // DeleteofRowwithXmlData + +} //XmlUpdel diff --git a/xml/java/sqlj/XmlUpDelScrpt b/xml/java/sqlj/XmlUpDelScrpt new file mode 100644 index 0000000..abcdcb5 --- /dev/null +++ b/xml/java/sqlj/XmlUpDelScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: XmlUpDelScrpt +# XmlUpDel_cleanup.db2 drops tables created by XmlUpDel_setup.db2 for the +# sample XmlUpDel.sqlj +# XmlUpDel_setup.db2 creates tables necessary for execution of the sample +# XmlUpDel.sqlj +# Both CLP scripts can be run on their own +# Usage: XmlUpDelScrpt + +db2 -tvf XmlUpDel_cleanup.db2 +db2 -tvf XmlUpDel_setup.db2 diff --git a/xml/java/sqlj/XmlUpDel_cleanup.db2 b/xml/java/sqlj/XmlUpDel_cleanup.db2 new file mode 100644 index 0000000..a9085e1 --- /dev/null +++ b/xml/java/sqlj/XmlUpDel_cleanup.db2 @@ -0,0 +1,49 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlUpDel_cleanup.db2 +-- +-- SAMPLE: Cleanup script for the sample XmlUpDel.sqlj +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlUpDel_cleanup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- drop table oldcustomer + +DROP TABLE "OLDCUST"; + +connect reset; diff --git a/xml/java/sqlj/XmlUpDel_setup.db2 b/xml/java/sqlj/XmlUpDel_setup.db2 new file mode 100644 index 0000000..6a34e2a --- /dev/null +++ b/xml/java/sqlj/XmlUpDel_setup.db2 @@ -0,0 +1,54 @@ +--------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlUpDel_setup.db2 +-- +-- SAMPLE: This sample serves as the setup script for the samples +-- XmlUpDel.sqlj +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlUpDel_setup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- create table 'oldcust' + +CREATE TABLE oldcust(ocid integer, + firstname varchar(15), + lastname varchar(15), + addr varchar(400), + information XML); + +connect reset; diff --git a/xml/java/sqlj/XmlXslt.sqlj b/xml/java/sqlj/XmlXslt.sqlj new file mode 100644 index 0000000..953dfea --- /dev/null +++ b/xml/java/sqlj/XmlXslt.sqlj @@ -0,0 +1,350 @@ +//************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: XmlXslt.sqlj +// +// PURPOSE: The purpose of this sample is to show: +// 1. Using the XSLTRANSFORM function to convert one XML document to +// another using an XSLT stylesheet. +// 2. Passing an XSL parameter document to the XSLTRANSFORM function +// at runtime. +// +// USAGE SCENARIO: A supermarket manager maintains a webpage to show +// the details of the products available in his shop. +// He maintains two tables, namely "product_details" +// and "display_productdetails". +// The "product_details" table contains information about +// all of the products available in his shop, where the +// details for each product are in an XML document format. +// The "display_productdetails" table contains the XSLT +// stylesheet, which specifies how to display the product +// details on the webpage. +// +// PREQUISITES : 1. Create the pre-requisite tables by running the command: +// XmlXsltScrpt +// Alternatively,you can run the command: +// db2 -tvf XmlXslt_setup.db2 +// +// EXECUTION : 1. Compile the sample using: +// bldsqlj XmlXslt +// 2. Run the sample as: +// java XmlXslt +// 3. Perform a clean up once the sample has been executed using: +// db2 -tvf XmlXslt_cleanup.db2 +// +// INPUT: NONE +// +// OUTPUT: Displays the new XML documents that result from the XSLT conversion. +// +// OUTPUT FILE: XmlXslt.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// INSERT +// +// SQL/XML FUNCTIONS USED: +// XSLTRANSFORM +// +//*************************************************************************** +// +// For more information about the command line processor (CLP) scripts, +// see the README file. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, building, and running DB2 +// applications, visit the DB2 application development website: +// http://www.software.ibm.com/data/db2/udb/ad +//*************************************************************************** +// +// SAMPLE DESCRIPTION +// +//*************************************************************************** +// 1. Using the XSLTRANSFORM function to convert one XML document to another +// using an XSLT stylesheet. +// 1.1 Insert an XML document into the "product_details" table. +// 1.2 Insert an XSL stylesheet into the "display_productdetails" table. +// 1.3 Display the new XML document after transforming the XML document +// in the "product_details" table using the XSL stylesheet. +// +// 2. Passing an XSL parameter document to the XSLTRANSFORM function +// at runtime. +// 2.1 Insert a parameter document into the "param_tab" table. +// 2.2 Display the new XML document after transforming the XML document +// in the "product_details" table using XSL the stylesheet with +// the parameter document. +// +//************************************************************************** +// +// INCLUDE ALL PACKAGES AND CLASS FILES +// +//*************************************************************************** + +import java.lang.*; +import java.sql.*; +import java.io.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; +import com.ibm.db2.jcc.DB2Xml; + +#sql iterator cursor1(String); + +class XmlXslt +{ + public static void main(String argv[]) + { + int rc=0; + Connection con = null; + String url = "jdbc:db2:sample"; + DefaultContext ctx = null; + + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + con = DriverManager.getConnection( url ); + + ctx = new DefaultContext(con); + DefaultContext.setDefaultContext(ctx); + System.out.println(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + System.out.println("This sample shows how to use XSLTRANSFORM"); + System.out.println(" function to convert one XML document "); + System.out.println(" into another XML document"); + + System.out.println("\n\n-------------------------------------"); + + convertXmlToHtml(); + convertXmlToHtmlWithParam(); + } // main + + static void convertXmlToHtml() + { + try + { + String str = null; + + //*********************************************************************** + // 1. Using the XSLTRANSFORM function to convert one XML document to another + // using an XSLT stylesheet. + //*********************************************************************** + + // create table product_details + System.out.println("The product_details table is created in the setup script \n" + + "XmlXslt_setup.db2 using the command \n" + + "'CREATE TABLE product_details (productid INTEGER, description XML)' \n"); + + // create table display_productdetails + System.out.println("The display_productdetails table is created in the setup script \n" + + "XmlXslt_setup.db2 using the command \n" + + "'CREATE TABLE display_productdetails (productid INTEGER,stylesheet CLOB (1M))' \n"); + + //*********************************************************************** + // 1.1 Insert an XML document into the "product_details" table. + //*********************************************************************** + + System.out.println("INSERT values into the product_details table"); + System.out.println(""); + #sql {INSERT INTO product_details + VALUES (1, ' + + + + Ice Scraper, Windshield 4 inch +
Basic Ice Scraper 4 inches wide, foam handle
+ 3.99 +
+ BIG BAZAR +
+
') }; + + //************************************************************************ + // 1.2 Insert an XSL stylesheet into the "display_productdetails" table. + //************************************************************************ + + System.out.println("INSERT values into the display_productdetails table"); + System.out.println(""); + #sql {INSERT INTO display_productdetails + VALUES (1, ' + + + + + +

+ + + + + + + +
product IDproduct namepricedetailssupermarket name
+ + + + + +
')}; + + //*********************************************************************** + // 1.3 Display the new XML document after transforming the XML document + // in the "product_details" table using the XSL stylesheet. + //*********************************************************************** + + cursor1 cur1; + System.out.print("SELECT XSLTRANSFORM (description USING stylesheet"); + System.out.print(" AS CLOB (1M)) FROM product_details X,"); + System.out.print("display_productdetails D "); + System.out.println("WHERE X.productid = D.productid"); + System.out.println(""); + + #sql cur1 = {SELECT XSLTRANSFORM (description USING stylesheet + AS CLOB (1M)) + FROM product_details X, display_productdetails D + WHERE X.productid = D.productid }; + + #sql {FETCH :cur1 INTO :str}; + + System.out.println("----------------------------------------------"); + System.out.println( Data.format(str, 1024)); + System.out.println("----------------------------------------------"); + + cur1.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // convertXmlToHtml + + static void convertXmlToHtmlWithParam() + { + try + { + String str = null; + + //*********************************************************************** + // 2. Passing an XSL parameter document to the XSLTRANSFORM function + // at runtime. + // + //*********************************************************************** + + + System.out.print("This part of the sample shows how to pass "); + System.out.println(" parameters to XSLTRANSFORM function"); + System.out.println(""); + + // create table param_tab + System.out.println("The param_tab table is created in the setup script \n" + + "XmlXslt_setup.db2 using the command \n" + + "'CREATE TABLE param_tab(productid INTEGER, param VARCHAR (1000))' \n"); + + //*********************************************************************** + // 2.1 Insert a parameter document into the table "param_tab". + //*********************************************************************** + + System.out.println("INSERT parameter values into the param_tab table"); + System.out.println(""); + #sql {INSERT INTO param_tab + VALUES (1, ' + + + BIG BAZAR super market + ')}; + + //************************************************************************* + // 2.2 Display the new XML document after transforming the XML document + // in the "product_details" table using the XSL stylesheet with + // the parameter document. + //************************************************************************* + + cursor1 cur1; + + System.out.println("DISPLAY final document"); + System.out.println(""); + System.out.print("SELECT XSLTRANSFORM (description USING stylesheet"); + System.out.print(" WITH param AS CLOB (1M)) FROM product_details"); + System.out.print(" X, param_tab P,display_productdetails D"); + System.out.print("WHERE X.productid=P.productid and "); + System.out.println("X.productid = D.productid"); + System.out.println(""); + + #sql cur1 = {SELECT XSLTRANSFORM (description USING stylesheet + WITH param AS CLOB (1M)) + FROM product_details X,param_tab P,display_productdetails D + WHERE X.productid=P.productid AND X.productid = D.productid}; + + #sql {FETCH FROM :cur1 INTO :str}; + + System.out.println("----------------------------------------------"); + System.out.println(Data.format(str, 1024)); + System.out.println("----------------------------------------------"); + + cur1.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // convertXmlToHtmlWithParam +} diff --git a/xml/java/sqlj/XmlXsltScrpt b/xml/java/sqlj/XmlXsltScrpt new file mode 100644 index 0000000..a9b657c --- /dev/null +++ b/xml/java/sqlj/XmlXsltScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: XmlXsltScrpt +# XmlXslt_cleanup.db2 drops tables created by XmlXslt_setup.db2 for the +# sample XmlXslt.sqlj +# XmlXslt_setup.db2 creates tables necessary for execution of the sample +# XmlXslt.sqlj +# Both CLP scripts can be run on their own +# Usage: XmlXsltScrpt + +db2 -tvf XmlXslt_cleanup.db2 +db2 -tvf XmlXslt_setup.db2 diff --git a/xml/java/sqlj/XmlXslt_cleanup.db2 b/xml/java/sqlj/XmlXslt_cleanup.db2 new file mode 100644 index 0000000..51a9b9c --- /dev/null +++ b/xml/java/sqlj/XmlXslt_cleanup.db2 @@ -0,0 +1,51 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlXslt_cleanup.db2 +-- +-- SAMPLE: Cleanup script for the sample XmlXslt.sqlj +-- +-- SQL STATEMENTS USED: +-- DROP TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlXslt_cleanup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- drop the tables product_details, display_productdetails and param_tab + +DROP TABLE product_details; +DROP TABLE display_productdetails; +DROP TABLE param_tab; + +connect reset; diff --git a/xml/java/sqlj/XmlXslt_setup.db2 b/xml/java/sqlj/XmlXslt_setup.db2 new file mode 100644 index 0000000..9415ee9 --- /dev/null +++ b/xml/java/sqlj/XmlXslt_setup.db2 @@ -0,0 +1,59 @@ +--------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: XmlXslt_setup.db2 +-- +-- SAMPLE: This sample serves as the setup script for the sample +-- XmlXslt.sqlj +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf XmlXslt_setup.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- create table product_details + +CREATE TABLE product_details (productid INTEGER, description XML); + +-- create table display_productdetails + +CREATE TABLE display_productdetails (productid INTEGER, + stylesheet CLOB (1M)); + +-- create table param_tab + +CREATE TABLE param_tab(productid INTEGER, param VARCHAR (1000)); + +connect reset; diff --git a/xml/java/sqlj/bldsqlj b/xml/java/sqlj/bldsqlj new file mode 100644 index 0000000..8006187 --- /dev/null +++ b/xml/java/sqlj/bldsqlj @@ -0,0 +1,90 @@ +#!/bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldsqlj +# Builds Java embedded SQL (SQLJ) applications and applets on UNIX +# Usage: bldsqlj prog_name (requires hardcoding user ID and password) +# bldsqlj prog_name userid password +# bldsqlj prog_name userid password server_name +# bldsqlj prog_name userid password server_name port_number +# bldsqlj prog_name userid password server_name port_number db_name +# +# Defaults: +# userid = $USER variable requires updating if used +# password = $PSWD variable requires updating if used +# server_name = $SERVER variable set to local hostname +# port_number = $PORTNUM variable set to 50000 +# db_name = $DB variable set to "sample" + +# To hardcode user ID (USER) and password (PSWD) +# Replace "NULL" with the correct values in quotes +USER="NULL" +PSWD="NULL" +# You can replace the defaults for each of the following +# with a new value. Note that the PORTNUM number cannot +# be one already used by another process. +SERVER=`hostname` +PORTNUM=50000 +DB="sample" + + +# Translate and compile the SQLJ source file +# and bind the package to the database. + if ( [ $# -eq 1 ] && [ $USER != "NULL" ] && [ $PSWD != "NULL" ] ) || ( [ $# -ge 3 ] && [ $# -le 6 ] ) + then + # Remove .sqlj extension + progname=${1%.sqlj} + + sqlj "${progname}.sqlj" + + if [ $# -eq 1 ] + then + db2sqljcustomize -url jdbc:db2://$SERVER:$PORTNUM/$DB \ + -user $USER -password $PSWD -longpkgname "${progname}_SJProfile0" + elif [ $# -eq 3 ] + then + db2sqljcustomize -url jdbc:db2://$SERVER:$PORTNUM/$DB -user $2 -password $3 \ + -longpkgname "${progname}_SJProfile0" + elif [ $# -eq 4 ] + then + db2sqljcustomize -url jdbc:db2://$4:$PORTNUM/$DB -user $2 -password $3 \ + -longpkgname "${progname}_SJProfile0" + elif [ $# -eq 5 ] + then + db2sqljcustomize -url jdbc:db2://$4:$5/$DB -user $2 -password $3 \ + -longpkgname "${progname}_SJProfile0" + else + db2sqljcustomize -url jdbc:db2://$4:$5/$6 -user $2 -password $3 \ + -longpkgname "${progname}_SJProfile0" + fi + else + echo 'Usage: bldsqlj prog_name (requires hardcoding user ID and password)' + echo ' bldsqlj prog_name userid password' + echo ' bldsqlj prog_name userid password server_name' + echo ' bldsqlj prog_name userid password server_name port_number' + echo ' bldsqlj prog_name userid password server_name port_number db_name' + echo '' + echo ' Defaults:' + echo ' userid = '$USER + echo ' password = '$PSWD + echo ' server_name = '$SERVER + echo ' port_number = '$PORTNUM + echo ' db_name = '$DB + fi diff --git a/xml/java/sqlj/makefile b/xml/java/sqlj/makefile new file mode 100644 index 0000000..58a5b6f --- /dev/null +++ b/xml/java/sqlj/makefile @@ -0,0 +1,157 @@ +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# +# MAKEFILE for XML SQLj samples on Unix +# +# Enter one of the following commands +# +# make - Builds the program designated by . +# +# make all - Builds all supplied sample programs. +# +# make clean - Erases all intermediate files produced in the +# build process. +# +# make cleanall - Erases all files produced in the build process +# (all files except the original source files). +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +############################################################################ +# 1 -- VARIABLES +############################################################################ + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +# To connect to a remote SAMPLE database cataloged on the client machine +# with another name, update the DB variable. +DB=sample + +# Set UID, PWD, SERVER_NAME and PORT_NUMBER +UID=$(USER) +PWD= +SERVER_NAME=$(HOSTNAME) +PORT_NUMBER=50000 + +COPY=cp +ERASE=rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all +# 2b - make clean +# 2c - make cleanall +############################################################################# + +#**************************************************************************** +# 2a - make all +#**************************************************************************** + +all : \ + XmlSchema XmlIndex XmlConst \ + XmlInsert XmlUpDel \ + XmlRead XmlToTable \ + RelToXmlType RelToXmlDoc \ + XmlXslt XmlIntegrate + +#**************************************************************************** +# 2b - make clean +#**************************************************************************** + +clean : + $(ERASE) XmlSchema.java + $(ERASE) XmlIndex.java + $(ERASE) XmlConst.java + $(ERASE) XmlInsert.java + $(ERASE) XmlUpDel.java + $(ERASE) XmlRead.java + $(ERASE) XmlToTable.java + $(ERASE) RelToXmlDoc.java + $(ERASE) RelToXmlType.java + $(ERASE) XmlXslt.java + $(ERASE) XmlIntegrate.java + +#**************************************************************************** +# 2c - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) *.class *.ser + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - standalone applications +############################################################################# + +#*************************************************************************** +# 3a - standalone applications +#*************************************************************************** + +XmlSchema : Util.class XmlSchema.sqlj + sqlj XmlSchema.sqlj + +XmlIndex : Util.class XmlIndex.sqlj + sqlj XmlIndex.sqlj + +XmlConst : Util.class XmlConst.sqlj + sqlj XmlConst.sqlj + +XmlInsert : Util.class XmlInsert.sqlj + XmlInsertScrpt + bldsqlj XmlInsert $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +XmlToTable : Util.class XmlToTable.sqlj + XmlToTableScrpt + bldsqlj XmlToTable $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +RelToXmlType : Util.class RelToXmlType.sqlj + cp $(DB2PATH)/samples/xml/data/setupscript.db2 . + cp $(DB2PATH)/samples/xml/data/cleanupscript.db2 . + RelToXmlScrpt + bldsqlj RelToXmlType $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +RelToXmlDoc : Util.class RelToXmlDoc.sqlj + reltoxmlprocScrpt + bldsqlj RelToXmlDoc $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +XmlUpDel : Util.class XmlUpDel.sqlj + XmlUpDelScrpt + bldsqlj XmlUpDel $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +XmlXslt : Util.class XmlXslt.sqlj + XmlXsltScrpt + bldsqlj XmlXslt $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +XmlIntegrate : Util.class XmlIntegrate.sqlj + XmlIntegrateScrpt + bldsqlj XmlIntegrate $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +XmlRead : Util.class XmlRead.sqlj + bldsqlj XmlRead $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +Util.class : Util.sqlj + bldsqlj Util $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) diff --git a/xml/java/sqlj/reltoxmlproc.db2 b/xml/java/sqlj/reltoxmlproc.db2 new file mode 100644 index 0000000..1b6f28c --- /dev/null +++ b/xml/java/sqlj/reltoxmlproc.db2 @@ -0,0 +1,81 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: reltoxmlproc.db2 +-- +-- SAMPLE: This stored procedure uses the constructor functions to create an XML +-- document with all the purchase order details. The input to the constructor +-- function will be the relational data stored in the tables. The final +-- output of the constructor functions will be a well formed XML document having +-- all the purchase orders. The stored procedure will return the purchase order +-- XML document back to the application. +-- +-- This stored procedure will be called by samples +-- a)reltoxmldoc.db2 +-- b)reltoxmldoc.sqc +-- c)RelToXmlDoc.java +-- d)RelToXmlDoc.sqlj +-- +-- SQL STATEMENTS USED: +-- CONNECT +-- CREATE PROCEDURE +-- OPEN +-- +-- OUTPUT FILE: NA +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +CONNECT TO SAMPLE@ +CREATE PROCEDURE reltoxmlproc() +RESULT SETS 1 +LANGUAGE SQL +BEGIN +DECLARE C1 CURSOR WITH RETURN FOR +SELECT po.PoNum, po.CustID, po.OrderDate, XMLCONCAT( XMLPI(NAME "pi", 'MESSAGE("valid, well-formed document")'), +XMLELEMENT (NAME "PurchaseOrder", XMLNAMESPACES( 'http://www.example.org' AS "e"), +XMLATTRIBUTES (po.CustID as "CustID", po.PoNum as "PoNum", po.OrderDate as "OrderDate", po.Status as "Status" ), + XMLELEMENT (NAME "CustomerAddress", XMLCONCAT( + XMLELEMENT (NAME "e.Name", c.Name ), + XMLELEMENT (NAME "e.Street", c.Street ), + XMLELEMENT (NAME "e.City", c.City ), + XMLELEMENT (NAME "e.Province", c.Province ), + XMLELEMENT (NAME "e.PostalCode", c.PostalCode ) ) ), + XMLELEMENT (NAME "ItemList" , +XMLELEMENT (NAME "Item", +XMLELEMENT (NAME "PartId", l.ProdID ), +XMLELEMENT (NAME "Description", p.Description ), +XMLELEMENT (NAME "Quantity", l.Quantity ), +XMLELEMENT (NAME "Price", p.Price ) , +XMLCOMMENT(po.comment) ) ) ) ) +FROM PurchaseOrder_Relational as Po, CustomerInfo_Relational AS c, Lineitem_Relational AS l, Products_Relational AS p +WHERE po.CustID = c.CustID and po.PoNum = l.PoNum and l.ProdID = p.ProdID +ORDER BY po.PoNum; +OPEN C1; +END@ + diff --git a/xml/java/sqlj/reltoxmlprocScrpt b/xml/java/sqlj/reltoxmlprocScrpt new file mode 100644 index 0000000..ad6f0f2 --- /dev/null +++ b/xml/java/sqlj/reltoxmlprocScrpt @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: reltoxmlprocScrpt +# reltoxmlprocdrop.db2 drops the procedure created by reltoxmlproc.db2 for the +# sample RelToXmlDoc.sqlj +# reltoxmlproc.db2 creates the procedure reltoxmlproc necessary for execution of +# the sample RelToXmlDoc.sqlj +# Both CLP scripts can be run on their own +# Usage: reltoxmlprocScrpt + +db2 -tvf reltoxmlprocdrop.db2 +db2 -td@ -f reltoxmlproc.db2 diff --git a/xml/java/sqlj/reltoxmlprocdrop.db2 b/xml/java/sqlj/reltoxmlprocdrop.db2 new file mode 100644 index 0000000..a6946b9 --- /dev/null +++ b/xml/java/sqlj/reltoxmlprocdrop.db2 @@ -0,0 +1,49 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: reltoxmlprocdrop.db2 +-- +-- SAMPLE: Drops the stored procedure 'reltoxmlproc' created by reltoxmlproc.db2 +-- +-- SQL STATEMENTS USED: +-- DROP PROCEDURE +-- +-- To run this script from the CLP issue the below command: +-- "db2 -tvf reltoxmlprocdrop.db2" +-- +---------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +connect to sample; + +-- drop procedure + +DROP PROCEDURE reltoxmlproc; + +connect reset; diff --git a/xml/porder.xsd b/xml/porder.xsd new file mode 100644 index 0000000..cb407ac --- /dev/null +++ b/xml/porder.xsd @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/product.xsd b/xml/product.xsd new file mode 100644 index 0000000..649f7fc --- /dev/null +++ b/xml/product.xsd @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/supplier.xsd b/xml/supplier.xsd new file mode 100644 index 0000000..12acb67 --- /dev/null +++ b/xml/supplier.xsd @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/xquery/README b/xml/xquery/README new file mode 100644 index 0000000..f19978b --- /dev/null +++ b/xml/xquery/README @@ -0,0 +1,206 @@ +****************************************************************************** +* (c) Copyright IBM Corp. 2007 All rights reserved. +* +* The following sample of source code ("Sample") is owned by International +* Business Machines Corporation or one of its subsidiaries ("IBM") and is +* copyrighted and licensed, not sold. You may use, copy, modify, and +* distribute the Sample in any form without payment to IBM, for the purpose of +* assisting you in the development of your applications. +* +* The Sample code is provided to you on an "AS IS" basis, without warranty of +* any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +* not allow for the exclusion or limitation of implied warranties, so the above +* limitations or exclusions may not apply to you. IBM shall not be liable for +* any damages you suffer as a result of using, copying, modifying or +* distributing the Sample, even if IBM has been advised of the possibility of +* such damages. +* +****************************************************************************** +* +* README for XML XQUERY Samples +* +* The /sqllib/samples/xml/xquery directory on UNIX and +* \sqllib\samples\xml\xquery directory on Windows contain this +* README file. +* is the location of DB2 9.7 on your hard drive. +* The default location for is $HOME for UNIX +* and C:\Program Files\IBM for windows. +* +* The DB2 9.7 sample code for XQUERY is located in the following directory : +* /sqllib/samples/xml/xquery directory on Unix and +* \sqllib\samples\xml\xquery directory on Windows. +* +* This README is organized into DIRECTORY ROADMAP, GETTING XML SAMPLES UP +* AND RUNNING, XML SAMPLES DESIGN OVERVIEW and DETAILS OF SAMPLES sections. +* +****************************************************************************** +* +* DIRECTORY ROADMAP +* +* xquery/ : This directory contains samples for demonstrating the XQuery +* features. +* 1. xquery/clp : This directory contains the files for CLP samples +* 2. xquery/c : This directory contains the files for ebbedded SQL +* samples +* 3. xquery/cli : This directory contains the files for CLI samples +* 4. xquery/clp : This directory contains the files for CLP scripts +* 5. xquery/java : This directory contains the files for JAVA samples +* java/jdbc directory contains files for jdbc samples +* java/sqlj directory contains files for sqlj samples +* +* For more details on the content of these directories, please refer to the +* the README file in the respective directories. +* +****************************************************************************** +* +* GETTING XQUERY SAMPLES UP AND RUNNING +* +* WARNINGS +* 1. These steps gives an overview of building and running the samples. +* Please refer to the README in corresponding directory for any specific +* considerations. +* +* SETUP: +* +* 1) Copy the files from corresponding directory to a working +* directory and ensure that directory has write permission. +* +* 2) On Windows platform, all samples should be run and built in DB2 +* Command Window. +* The DB2 command window is needed to execute the db2 specific commands. +* You can follow the step below to open DB2 command window. +* From the Start Menu click Start --> Programs --> IBM DB2 --> +* --> Command Line Tools --> Command Window. +* +* 3) Start the database manager with the following command: +* db2start +* +* 4) Create the sample database with the following command: +* db2sampl -xml +* +* 5) Connect to the sample database with the following command: +* db2 connect to sample +* +* 6) To build stored procedures and User defined functions, +* ensure that you have write permission on the +* /sqllib/function directory on UNIX and +* \sqlib\function directory on WINDOWS. +* +* 7) Change directory (CD) to the directory containing the files +* copied in step 1. +* +* BUILD AND RUN: +* 1. Some of the samples might need one or more of the data files at +* runtime. The data files can be found in the xquery/data directory. +* Please copy the data files to your working directory before running +* the particular sample. For more details on the data files required +* for a particular sample, please refer the header section of the +* sample. +* +* To compile these samples, build scripts are provided. +* The README file in each directory containing the actual samples provides +* the details about how to compile the samples using the build script. +* +* Here is the brief overview : +* +* BUILD AND RUN : +* +* To compile these samples, build scripts are provided. +* +* C and CLI: +* +* To create the executable for the sample: +* +* bldapp +* +* where is the name of the sample without any extension. +* +* e.g. bldapp xpath +* +* To run the sample: +* +* xpath +* +* SQLJ: +* +* To create the class file: +* +* bldsqlj userid password [server name] [port name] +* +* where is the name of the sample without any extension. +* +* To run the sample: +* +* java .class +* +* where is the name of the sample without any extension. +* +* JDBC: +* +* To create the class file: +* +* javac .java +* +* where is the name of the sample without any extension. +* +* To run the sample file: +* +* java .class +* +* where is the name of the sample without any extension. +* +****************************************************************************** +* +* XQUERY SAMPLES: DEMONSTRATED FEATURES AND USAGE SCENARIOS +* +* To help provide valid, usable and comprehensive XML XQuery samples, the +* samples have been created to be based on specific usage scenarios or to +* demonstrate a particular feature or API. +* +* 1. Usage Scenarios +* +* 1. Some of the suppliers have extended the promotional price. +* Find all the purchaseorder for these products and find out the +* excess amount given by the customer. The financial department +* needs the details of the customers so that amount can be returned +* to customer. The result can be returned as an XML document. +* +* Sample Name: xquery_xmlproc.* +* +* 2. Features +* +* 1. Path expressions - These samples demonstrate the path expression +* with different kind of axis. +* +* Sample Name: xpath.* +* +* 2. Flwor exoression - These samples demonstrate XQuery FLWOR +* expression. +* +* Sample Name: flwor.* +* +* 3. SQL/XML function - These samples demonstrate how XQuery interacts +* with SQL using SQL/XML functions. +* +* Sample Name: sqlxquery.* +* Sample Name: xqueryparam.* -- Shows how to pass parameters to +* db2-fn:sqlquery function. +* Sample Name: xupdate.* -- Demonstrates how to insert, delete, +* update, replace, and rename +* one or more XML documents or document +* fragments using transform expressions. +* +* 4. Nested XQueries - These samples demonstrate the nesting of FLWOR +* expression to restructure the XML data stored in the relation +* table with XML columns. +* +* Sample Name: xquery.* +* +* 5. XQuery Explain Support - This sample demonstrates the explain +* supoort for SQL/XML and XQuery statements. +* +* Sample Name: xquery_explain.db2 +* +****************************************************************************** diff --git a/xml/xquery/c/bldapp b/xml/xquery/c/bldapp new file mode 100644 index 0000000..b82a5f0 --- /dev/null +++ b/xml/xquery/c/bldapp @@ -0,0 +1,111 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldapp +# Builds C applications for Linux +# Usage: bldapp [ [ ]] + +# Select a compiler to use +CC=gcc +#CC=xlc_r + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then +BITWIDTH=64 +else +# x86 is the only native 32-bit platform +BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] + then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +# Note: some .sqc files contain no SQL but link in +# utilemb.sqc, so if you get this warning, ignore it: +# SQL0053W No SQL statements were found in the program. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 $3 $4 + # Compile the utilemb.c error-checking utility. + $CC $EXTRA_C_FLAGS -I$DB2PATH/include -c utilemb.c +else + # Compile the utilapi.c error-checking utility. + $CC $EXTRA_C_FLAGS -I$DB2PATH/include -c utilapi.c +fi + +# Compile the program. +$CC $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c + +if [ -f $1".sqc" ] +then + # Link the program with utilemb.o. + $CC $EXTRA_C_FLAGS -o $1 $1.o utilemb.o $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 +else + # Link the program with utilapi.o. + $CC $EXTRA_C_FLAGS -o $1 $1.o utilapi.o $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 +fi diff --git a/xml/xquery/c/bldrtn b/xml/xquery/c/bldrtn new file mode 100644 index 0000000..663f958 --- /dev/null +++ b/xml/xquery/c/bldrtn @@ -0,0 +1,111 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldrtn +# Builds C routines (stored procedures or UDFs) for Linux +# Usage: bldrtn [ ] + +# Select the compiler to use +CC=gcc +#CC=xlc_r + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default compiler/linker settings +EXTRA_C_FLAGS="" +SHARED_LIB_FLAG="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then +BITWIDTH=64 +else +# x86 is the only native 32-bit platform +BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] + then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +if [ "$CC" = "xlc_r" ] +then + SHARED_LIB_FLAG="-qmkshrobj" +else + SHARED_LIB_FLAG="-shared" + EXTRA_C_FLAGS="$EXTRA_C_FLAGS -fpic" +fi + +LINK_FLAGS="$EXTRA_C_FLAGS $SHARED_LIB_FLAG" + +# Set the runtime path. +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 +fi + +# Compile the program. +$CC $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c -D_REENTRANT + +# Link the program and create a shared library +$CC $LINK_FLAGS -o $1 $1.o $EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2 -lpthread + +# Copy the shared library to the function subdirectory. +# The user must have write permission to this directory. +rm -f $DB2PATH/function/$1 +cp $1 $DB2PATH/function diff --git a/xml/xquery/c/client_xquery_xmlproc.sqc b/xml/xquery/c/client_xquery_xmlproc.sqc new file mode 100644 index 0000000..5839329 --- /dev/null +++ b/xml/xquery/c/client_xquery_xmlproc.sqc @@ -0,0 +1,179 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: client_xquery_xmlproc.sqc +** +** SAMPLE: Call a stored procedure with XML type parameters +** +** This file contains one function that call stored procedure: +** callxquery_proc gives the solution for following scenario: +** Some of the suppliers have extended the promotional price date for +** their products. Getting all the customer's Information who purchased +** these products in the extended period will help the financial department +** to return the excess amount paid by those customers. The supplier +** information along with extended date's for the products is provided +** in an XML document and the customer wants to have the information +** of all the customers who has paid the excess amount by purchasing those +** products in the extended period. +** +** This procedure will return an XML document containing customer info +** along with the the excess amount paid by them. +** +** The file "utilemb.sqC" contains functions for error-checking and +** rolling back a transaction in case of error. This file must be +** compiled and its object file linked in to the "client_xquery_xmlproc" +** program. +** +** SQL STATEMENTS USED: +** CALL +** CONNECT +** ROLLBACK +** SELECT INTO +** +** STRUCTURES USED: +** sqlca +** sqlda +** +** EXTERNAL DEPENDENCIES: +** Ensure existence of database for precompile purposes. +** Ensure that the stored procedures called from this program have +** been built and cataloged with the database (see the instructions in +** xquery_xmlproc.sqc). +** Precompile with the SQL precompiler (PREP in DB2) +** Bind to a database (BIND in DB2) +** Compile and link loop with the compiler supported on your platform. +** +** OUTPUT FILE: client_xquery_xmlproc.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL INCLUDE SQLCA; + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[9]; + char user[128 + 1]; + char pswd[19]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* call the procedure */ + callxquery_proc(); + + /* Roll back stored procedure actions to preserve + the state of the database */ + EXEC SQL ROLLBACK; + EMB_SQL_CHECK("ROLLBACK"); + printf("\nStored procedure rolled back\n"); + + /* Disconnect from Remote Database */ + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + return 0; +} + +int callxquery_proc() +{ + /********************************************************\ + * Call Supp_XML_Proc_C stored procedure * + \********************************************************/ + + EXEC SQL BEGIN DECLARE SECTION; + SQL TYPE IS XML AS CLOB(5000) outXML; + SQL TYPE IS XML AS CLOB(5000) inXML; + sqlint32 outRet; + sqlint16 outXML_ind; + sqlint16 inXML_ind; + sqlint16 outRet_ind; + sqlint32 i; + EXEC SQL END DECLARE SECTION; + + /* initialize variables */ + outXML_ind = -1; + outRet = -6666; + outRet_ind = -1; + + /* assign the input data to the inXML variable */ + inXML_ind = 0; + strcpy(inXML.data, "" + " 2006-01-02" + " 2006-08-02 " + " " + "2006-09-22 " + " "); + inXML.length = strlen(inXML.data); + + printf("\n \n"); + printf("==============================================\n"); + printf("calling the stored procedure Supp_XML_Proc_C \n"); + printf("==============================================\n"); + printf("\n"); + /* calling the procedure */ + EXEC SQL CALL Supp_XML_Proc_C( :inXML:inXML_ind, + :outXML:outXML_ind, + :outRet:outRet_ind); + + if (outXML_ind == 0 && outRet_ind == 0 && outRet == 0) + { + printf("\n called Successfully.\n"); + printf("\n Customers Information : \n"); + for (i = 0; i < outXML.length; i++) + { + printf("%c", outXML.data[i]); + } + } + + return 0; +} /* end of program: client_xquery_xmlproc.sqc */ diff --git a/xml/xquery/c/embprep b/xml/xquery/c/embprep new file mode 100644 index 0000000..56dce72 --- /dev/null +++ b/xml/xquery/c/embprep @@ -0,0 +1,63 @@ + +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: embprep +# To prep and bind C/C++ and Micro Focus COBOL embedded SQL programs +# +# Usage: embprep [ [ ]] + +# Connect to a database. +if (test $# -lt 2) +then + db2 connect to sample +elif (test $# -lt 3) +then + db2 connect to $2 +else + db2 connect to $2 user $3 using $4 +fi + +# Precompile the program. +if [ -f $1".sqc" ] +then + db2 prep $1.sqc bindfile + if [ -f utilemb.sqc ] + then + db2 prep utilemb.sqc + fi +elif [ -f $1".sqC" ] +then + db2 prep $1.sqC bindfile + if [ -f utilemb.sqC ] + then + db2 prep utilemb.sqC + fi +elif [ -f $1".sqb" ] +then + db2 prep $1.sqb bindfile target mfcob CALL_RESOLUTION DEFERRED +fi + +# Bind the program to the database. +db2 bind $1.bnd + +# Disconnect from the database. +db2 connect reset +db2 terminate diff --git a/xml/xquery/c/flwor.sqc b/xml/xquery/c/flwor.sqc new file mode 100644 index 0000000..5a21592 --- /dev/null +++ b/xml/xquery/c/flwor.sqc @@ -0,0 +1,330 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: flwor.sqc +** +** SAMPLE: How to use XQuery FLWOR expression +** +** SQL/XML FUNCTIONS USED +** xmlcolumn +** xmlquery +** +** XQuery functions used +** data +** string +** +** +** OUTPUT FILE: flwor.out (available in the online documentation) +***************************************************************************** +** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using XQUERY statements, see the XQUERY Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char stmt[16384]; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob; + sqlint32 cid; + char country[10]; + float price; +EXEC SQL END DECLARE SECTION; + +/* The orderCustDetails method returns customer information in alphabetical order by customer name */ +int OrderCustDetails(void); + +/* The conditionalCustDetails1 returns information for customers whose customer ID is greater than + the cid value passed as an argument */ +int conditionalCustDetails1(sqlint32 cid); + +/* The conditionalCustDetails2 method returns information for customers whose customer ID is greater than + the cid value passed to the function and who dont live in the country passed as an argument */ +int conditionalCustDetails2(int cid, char *country); + +/* The maxpriceproduct function returns the product details with maximun price */ +int maxpriceproduct(void); + +/* The basicproduct function returns the product with basic attribute value true + if the price is less then price parameter otherwiese false */ +int basicproduct(float price); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + printf("THIS SAMPLE WILL DEMONSTRATE"); + printf("1. FLWOR expression for XQuery"); + printf("2. How to use parameter markers in XQuery"); + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* The follwing functions will use the dynamic sql statements to declare cursor + for the xquery */ + rc=OrderCustDetails(); + rc=maxpriceproduct(); + + /* These functions will make use of parameter marker to pass the value to XQuery + passing by clause of xmlquery function will be used to pass the value */ + cid=1002; + rc=conditionalCustDetails1(cid); + strcpy(country,"US"); + cid=1002; + rc=conditionalCustDetails2(cid,country); + price=10; + basicproduct(price); + return 0; +} /* main */ + +int OrderCustDetails() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT CUSTOMER DETAILS IN ALPHABETICAL ORDER USING ORDER BY CLAUSE\n"); + printf("OF FLWOR EXPRESSION"); + sprintf( stmt, "XQUERY for $custinfo in db2-fn:xmlcolumn('CUSTOMER.INFO')" + "/customerinfo[addr/@country=\"Canada\"]" + " order by $custinfo/name,fn:number($custinfo/@Cid)" + " return $custinfo"); + + printf("\n%s",stmt); + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c1 CURSOR FOR s1; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c1; + EMB_SQL_CHECK("cursor -- open"); + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c1; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; +} /* OrderCustDetails */ + +int conditionalCustDetails1(sqlint32 cid) +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT CUSTOMER DETAILS BASED ON A CONDITION\n"); + printf(" CUSTOMER ID GREATER THEN A %d \n", cid); + printf("USING WHERE CLAUSE OF FLWOR EXPRESSION"); + printf("\n VALUE=%d",cid); + sprintf( stmt, "SELECT XMLQUERY('for $customer in $cust/customerinfo" + " where ($customer/@Cid > $id)" + " order by $customer/@Cid " + " return " + " {$customer/name} {$customer/addr} '" + " passing by ref customer.info as \"cust\", cast(? as integer) as \"id\")" + " FROM customer ORDER BY cid"); + + printf("\n%s",stmt); + EXEC SQL PREPARE s2 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c2 CURSOR FOR s2; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c2 USING :cid; + EMB_SQL_CHECK("cursor -- open"); + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c2; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; +} /* conditionalCustDetails1 */ + +int conditionalCustDetails2(int cid, char* country) +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT CUSTOMER DETAILS BASED ON CONDITIONS\n"); + printf(" CUSTOMER ID GREATER THEN %d", cid); + printf("\nAND COUNTRY NOT EQUAL TO %s\n", country); + printf("USING WHERE CLAUSE OF FLWOR EXPRESSION"); + printf("\n ID VALUE=%d COUNTRY VALUE=%s",cid,country); + sprintf( stmt, "SELECT XMLQUERY('" + "for $customer in db2-fn:xmlcolumn(\"CUSTOMER.INFO\")/customerinfo" + " where ($customer/@Cid > $id) and ($customer/addr/@country !=$c)" + " order by $customer/@Cid" + " return " + " {$customer/name}" + "
{$customer/addr/street}" + " {$customer/addr/city}
'" + " passing by ref cast(? as integer) as \"id\"," + " cast(? as varchar(10)) as \"c\")" + " FROM SYSIBM.SYSDUMMY1"); + + printf("\n%s",stmt); + EXEC SQL PREPARE s3 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c3 CURSOR FOR s3; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c3 USING :cid, :country; + EMB_SQL_CHECK("cursor -- open"); + EXEC SQL FETCH c3 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + EXEC SQL FETCH c3 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c3; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; +} /* conditionalCustDetails2 */ + +int maxpriceproduct() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO RETURN THE PRODUCT WITH MAXIMUM PRICE USING ORDER BY CLAUSE\n"); + printf("OF FLWOR EXPRESSION"); + sprintf( stmt, "XQUERY " + " let $prod := for $product in db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product/description" + " order by fn:number($product/price) descending return $product" + " return {$prod[1]/name} "); + + printf("\n %s", stmt); + EXEC SQL PREPARE s4 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c4 CURSOR FOR s4; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c4; + EMB_SQL_CHECK("cursor -- open"); + EXEC SQL FETCH c4 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + + EXEC SQL CLOSE c4; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; +} /* maxpriceproduct */ + +int basicproduct(float price) +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO RETURN THE PRODUCT WITH BASIC ATTRIBUTE VALUE TRUE IF THE PRICE IS LESS THEN %f\n", price); + sprintf( stmt, "SELECT XMLQUERY('" + "for $prod in db2-fn:xmlcolumn(\"PRODUCT.DESCRIPTION\")/product/description" + " order by $prod/name " + " return ( if ($prod/price < $price)" + " then {fn:data($prod/name)}" + " else {fn:data($prod/name)})'" + " passing by ref cast(? as float) as \"price\")" + " FROM SYSIBM.SYSDUMMY1"); + + printf("\n%s",stmt); + EXEC SQL PREPARE s5 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c5 CURSOR FOR s5; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c5 USING :price; + EMB_SQL_CHECK("cursor -- open"); + EXEC SQL FETCH c5 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + EXEC SQL FETCH c5 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c5; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; +} /* basicproduct */ diff --git a/xml/xquery/c/makefile b/xml/xquery/c/makefile new file mode 100644 index 0000000..47166de --- /dev/null +++ b/xml/xquery/c/makefile @@ -0,0 +1,168 @@ +############################################################################## +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################## +# +# MAKEFILE for XML XQUERY C samples on UNIX +# +# Enter one of the following commands +# +# make - Builds the program designated by +# make all - Builds all supplied sample programs +# make srv - Builds sample that run on the server +# (stored procedure) +# make all_client - Builds all client samples (all programs in the +# call_rtn and client_run categories) +# make call_rtn - Builds client programs that call stored procedure +# make client_run - Builds all programs that run completely on the +# client (not ones that call stored procedure) +# make clean - Erases intermediate files +# make cleanall - Erases all files produced in the build process +# except the original source files +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +############################################################################## +# 1 -- VARIABLES +############################################################################## + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +BLDAPP=bldapp +BLDRTN=bldrtn + +# To connect to a remote SAMPLE database cataloged on the client machine +# with another name, update the ALIAS variable. +ALIAS=sample +# Set UID and PWD if neccesary +UID= +PWD= + + +COPY=cp +ERASE=rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all (srv + all_client) +# 2b - make srv +# 2c - make all_client (call_rtn + client_run) +# 2d - make call_rtn +# 2e - make client_run +# 2f - make clean +# 2g - make cleanall +############################################################################# + +#**************************************************************************** +# 2a - make all +#**************************************************************************** + +all : \ + srv \ + all_client + +#**************************************************************************** +# 2b - make srv +#**************************************************************************** + +srv : \ + xquery_xmlproc + +#**************************************************************************** +# 2c - make all_client (call_rtn + client_run) +#**************************************************************************** + +all_client : \ + call_rtn \ + client_run + +#**************************************************************************** +# 2d - make call_rtn +#**************************************************************************** + +call_rtn : \ + client_xquery_xmlproc + +#**************************************************************************** +# 2e - make client_run +#**************************************************************************** + +client_run : \ + xpath flwor sqlxquery xquery xqueryparam xupdate + +#**************************************************************************** +# 2f - make clean +#**************************************************************************** + +clean : + $(ERASE) *.o + $(ERASE) *.DEL *.TXT *.MSG + $(ERASE) xpath.c flwor.c sqlxquery.c xquery.c xquery_xmlproc_client.c \ + xquery_xmlproc.c utilemb.c xqueryparam.c xupdate.c + +#**************************************************************************** +# 2g - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) *.bnd + $(ERASE) xpath flwor sqlxquery xquery client_xquery_xmlproc xquery_xmlproc + $(ERASE) xqueryparam xupdate + $(ERASE) $(DB2PATH)/function/xquery_xmlproc + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - regular samples, embedded SQL +# 3b - client/server samples +############################################################################# + +#**************************************************************************** +# 3a - regular samples, embedded SQL +#**************************************************************************** + +xpath : + $(BLDAPP) xpath $(ALIAS) $(UID) $(PWD) +flwor : + $(BLDAPP) flwor $(ALIAS) $(UID) $(PWD) +sqlxquery : + $(BLDAPP) sqlxquery $(ALIAS) $(UID) $(PWD) +xquery : + $(BLDAPP) xquery $(ALIAS) $(UID) $(PWD) +xqueryparam : + $(BLDAPP) xqueryparam $(ALIAS) $(UID) $(PWD) +xupdate : + $(BLDAPP) xupdate $(ALIAS) $(UID) $(PWD) + + +#**************************************************************************** +# 3b - client/server samples +#**************************************************************************** + +client_xquery_xmlproc : + $(BLDAPP) client_xquery_xmlproc +xquery_xmlproc : + $(BLDRTN) xquery_xmlproc + spcat_xquery diff --git a/xml/xquery/c/spcat_xquery b/xml/xquery/c/spcat_xquery new file mode 100644 index 0000000..8ef1bab --- /dev/null +++ b/xml/xquery/c/spcat_xquery @@ -0,0 +1,30 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: spcat_xquery +# To catalog XML SQC stored procedures on UNIX +# Catalogs the stored procedures in the xquery_xmlproc library +# xquery_xmlproc_drop.db2 uncatalogs the stored procedures if previously cataloged +# xquery_xmlproc_create.db2 catologs the stored procedures +# Both CLP scripts can be run on their own +# Usage: spcat + +db2 -td@ -vf xquery_xmlproc_drop.db2 +db2 -td@ -vf xquery_xmlproc_create.db2 diff --git a/xml/xquery/c/sqlxquery.sqc b/xml/xquery/c/sqlxquery.sqc new file mode 100644 index 0000000..058c6f8 --- /dev/null +++ b/xml/xquery/c/sqlxquery.sqc @@ -0,0 +1,306 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: sqlxquery.sqc +** +** SAMPLE: SQL/XML Queries +** +** SQL/XML FUNCTIONS USED +** XMLQUERY +** XMLEXISTS +** +** OUTPUT FILE: sqlxquery.out (available in the online documentation) +***************************************************************************** +** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using XQUERY statements, see the XQUERY Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char stmt[16384]; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob2; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob3; + sqlint64 cid; + char custname[20]; + sqlint32 count; + char name[20]; + char partid[20]; +EXEC SQL END DECLARE SECTION; + +/* The firstPO1 function returns the first item in the purchase order for customer custname passed as an argument*/ +int firstPO1(char *custname); + +/* The firstPO2 function returns the first item in the purchaseorder when + Name is from the sequence (X,Y,Z) + or the customer id is from the sequence (1000,1002,1003) */ +int firstPO2(); + +/* The sortCust_PO function sort the customers according to the number of purchaseorders */ +int sortCust_PO(); + +/* The numPO function returns the number of purchaseorder having specific partid + for the specific customer passed as an argument to the function*/ +int numPO(char *name, char *partid); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + strcpy(custname,"Robert Shoemaker"); + rc=firstPO1(custname); + + rc=firstPO2(); + rc=sortCust_PO(); + + strcpy(name,"Robert Shoemaker"); + strcpy(partid,"100-101-01"); + + rc=numPO(name,partid); + return 0; +} /* main */ + +int firstPO1(char *custname) +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT FIRST PURCHASEORDER OF THE CUSTOMERS USING SQL/XML QUERY\n"); + printf("CUSTOMER NAME: %s",custname); + sprintf( stmt,"SELECT XMLQUERY('$p/PurchaseOrder/item[1]' PASSING p.porder AS \"p\")" + " FROM purchaseorder AS p, customer AS c" + " WHERE XMLEXISTS('$custinfo/customerinfo[name=$c and @Cid = $cid]'" + " PASSING c.info AS \"custinfo\", p.custid AS \"cid\", cast(? as varchar(20)) as \"c\")"); + + printf("\n%s",stmt); + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + + EXEC SQL DECLARE c1 CURSOR FOR s1; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c1 USING :custname; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Print the result */ + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c1; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* firstPO1 */ + + +int firstPO2() +{ + + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT FIRST PURCHASEORDER OF THE CUSTOMERS BASED ON THE FOLLOWING CONDITIONS"); + printf("\n1. Customer name in the sequence (X,Y,Z) or"); + printf("\n2. Customer id in the sequence (1000,1002,1003)"); + printf(" \n\nUSING SQL/XML QUERY\n"); + sprintf( stmt,"SELECT cid,XMLQUERY('$custinfo/customerinfo/name' passing c.info as \"custinfo\")," + " XMLQUERY('$p/PurchaseOrder/item[1]' passing p.porder as \"p\")," + "XMLQUERY('$x/history' passing c.history as \"x\")" + " FROM purchaseorder as p,customer as c" + " WHERE XMLEXISTS('$custinfo/customerinfo[name=(X,Y,Z)" + " or @Cid=(1000,1002,1003) and @Cid=$cid ]'" + " passing c.info as \"custinfo\", p.custid as \"cid\") ORDER BY cid"); + + printf("\n%s",stmt); + EXEC SQL PREPARE s2 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + + EXEC SQL DECLARE c2 CURSOR FOR s2; + EMB_SQL_CHECK("declare -- cursor"); + + EXEC SQL OPEN c2; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c2 INTO :cid, :xmlblob, :xmlblob2, :xmlblob3; + EMB_SQL_CHECK("cursor -- fetch"); + + /* print the result */ + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + xmlblob2.data[xmlblob2.length]='\0'; + xmlblob3.data[xmlblob3.length]='\0'; + printf("\n\n CID : %d\n",cid); + printf("NAME :%s\n", xmlblob.data); + printf("FIRST PURCHASEORDER : %s\n", xmlblob2.data); + printf("HISTORY : %s\n", xmlblob3.data); + + EXEC SQL FETCH c2 INTO :cid,:xmlblob, :xmlblob2, :xmlblob3; + EMB_SQL_CHECK("cursor -- fetch"); + } + + EXEC SQL CLOSE c2; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* firstPO2 */ + +int sortCust_PO() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT ALL THE CUSTOMER NAMES AND SORT THEN ACCORDING TO THE NUMBER OF PURCHASE ORDERS"); + sprintf( stmt,"WITH count_table AS ( SELECT count(poid) as c,custid" + " FROM purchaseorder,customer" + " WHERE cid=custid group by custid )" + " SELECT c, xmlquery('$s/customerinfo[@Cid=$id]/name'" + " passing customer.info as \"s\", count_table.custid as \"id\")" + " FROM customer,count_table" + " WHERE custid=cid ORDER BY custid"); + + + printf("\n%s",stmt); + EXEC SQL PREPARE s3 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + + EXEC SQL DECLARE c3 CURSOR FOR s3; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c3; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c3 INTO :count, :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* print the result */ + printf("\nCOUNT CUSTOMER NAME"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%d %s",count, xmlblob.data); + EXEC SQL FETCH c3 INTO :count, :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c3; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* sortCust_PO */ + + +int numPO(char *name, char *partid) +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO FIND OUT THE NUMBER OF PURCHASEORDER FOR CUSTOMER WITH A SPECIFIC PARTID"); + printf(" USING SQL/XML QUERY\n"); + printf("\nCUSTOMER NAME: %s, PART ID: %s",name,partid); + sprintf( stmt,"WITH cid_table AS (SELECT Cid FROM customer" + " WHERE XMLEXISTS('$custinfo/customerinfo[name=$name]'" + " PASSING customer.info AS \"custinfo\", cast(? as varchar(20)) as \"name\"))" + " SELECT count(poid) FROM purchaseorder,cid_table" + " WHERE XMLEXISTS('$po/itemlist/item[partid=$id]'" + " PASSING purchaseorder.porder AS \"po\", cast(? as varchar(20)) as \"id\")" + " AND purchaseorder.custid=cid_table.cid"); + + + printf("\n%s",stmt); + EXEC SQL PREPARE s4 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + + EXEC SQL DECLARE c4 CURSOR FOR s4; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c4 using :name,:partid; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c4 INTO :count; + EMB_SQL_CHECK("cursor -- fetch"); + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n COUNT : %d \n",count); + + EXEC SQL CLOSE c4; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* numPO */ + + diff --git a/xml/xquery/c/utilapi.c b/xml/xquery/c/utilapi.c new file mode 100644 index 0000000..eed6364 --- /dev/null +++ b/xml/xquery/c/utilapi.c @@ -0,0 +1,359 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilapi.c +** +** SAMPLE: Error-checking utility for non-embedded SQL samples in C +** +** This utility file is compiled and linked in as an object module +** with non-embedded SQL sample programs by the supplied makefile +** and build files. It checks for and prints to the screen SQL +** warnings and errors. +** +** DB2 APIs USED: +** sqlaintp -- Get Error Message +** sqlogstt -- Get SQLSTATE Message +** sqleatin -- Attach to an Instance +** sqledtin -- Detach from an Instance +** +** Included functions: +** SqlInfoPrint - prints to the screen SQL warnings and errors +** CmdLineArgsCheck1 - checks the command line arguments, version 1 +** CmdLineArgsCheck2 - checks the command line arguments, version 2 +** CmdLineArgsCheck3 - checks the command line arguments, version 3 +** CmdLineArgsCheck4 - checks the command line arguments, version 4 +** InstanceAttach - attach to instance +** InstanceDetach - detach from instance +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "utilapi.h" + +void SqlInfoPrint(char *appMsg, struct sqlca *pSqlca, int line, char *file) +{ + int rc = 0; + char sqlInfo[1024]; + char sqlInfoToken[1024]; + char sqlstateMsg[1024]; + char errorMsg[1024]; + + if (pSqlca->sqlcode != 0 && pSqlca->sqlcode != 100) + { + strcpy(sqlInfo, ""); + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "\n---- error report -----------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } + else + { + sprintf(sqlInfoToken, + "\n---- warning report ---------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } /* endif */ + + sprintf(sqlInfoToken, "\napplication message = %s\n", appMsg); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "line = %d\n", line); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "file = %s\n", file); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "SQLCODE = %d\n\n", pSqlca->sqlcode); + strcat(sqlInfo, sqlInfoToken); + + /* get error message */ + rc = sqlaintp(errorMsg, 1024, 80, pSqlca); + if (rc > 0) /* return code is the length of the errorMsg string */ + { + sprintf(sqlInfoToken, "%s\n", errorMsg); + strcat(sqlInfo, sqlInfoToken); + } + + /* get SQLSTATE message */ + rc = sqlogstt(sqlstateMsg, 1024, 80, pSqlca->sqlstate); + if (rc > 0) + { + sprintf(sqlInfoToken, "%s\n", sqlstateMsg); + strcat(sqlInfo, sqlInfoToken); + } + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "---- end error report ------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } + else + { + sprintf(sqlInfoToken, + "---- end warning report ----------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } /* endif */ + } /* endif */ +} /* SqlInfoPrint */ + + +int CmdLineArgsCheck1(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck1 */ + +int CmdLineArgsCheck2(int argc, + char *argv[], + char nodeName[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(nodeName, ""); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(nodeName, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(nodeName, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [nodeName [userid passwd]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck2 */ + +int CmdLineArgsCheck3(int argc, + char *argv[], + char dbAlias[], + char nodeName[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(nodeName, ""); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(nodeName, ""); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 3: + strcpy(dbAlias, argv[1]); + strcpy(nodeName, argv[2]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 5: + strcpy(dbAlias, argv[1]); + strcpy(nodeName, argv[2]); + strcpy(user, argv[3]); + strcpy(pswd, argv[4]); + break; + default: + printf("\nUSAGE: %s [dbAlias [nodeName [userid passwd]]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck3 */ + +int CmdLineArgsCheck4(int argc, + char * argv[], + char dbAlias1[], + char dbAlias2[], + char user1[], + char pswd1[], + char user2[], + char pswd2[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias1, "sample"); + strcpy(dbAlias2, "sample2"); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 2: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, "sample2"); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 3: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 4: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, "sample2"); + strcpy(user1, argv[2]); + strcpy(pswd1, argv[3]); + strcpy(user2, argv[2]); + strcpy(pswd2, argv[3]); + break; + case 5: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[3]); + strcpy(pswd2, argv[4]); + break; + case 7: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[5]); + strcpy(pswd2, argv[6]); + break; + default: + printf("\nUSAGE: %s " + "[dbAlias1 [dbAlias2] [user1 pswd1 [user2 pswd2]]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck4 */ + + +int InstanceAttach(char nodeName[], + char user[], + char pswd[]) +{ + struct sqlca sqlca; + + if (strlen(nodeName) > 0) + { + printf("\n\n############## ATTACH TO THE INSTANCE: %s #######\n\n", + nodeName); + + /* attach to an instance */ + sqleatin(nodeName, user, pswd, &sqlca); + DB2_API_CHECK("instance -- attach"); + } + + return 0; +} /* CmdLineArgsCheck4 */ + + +int InstanceDetach(char * nodeName) +{ + struct sqlca sqlca; + + if (strlen(nodeName) > 0) + { + printf("\n\n############## DETACH FROM THE INSTANCE: %s #####\n\n", + nodeName); + + /* detach from an instance */ + sqledtin(&sqlca); + DB2_API_CHECK("instance -- detach"); + } + + return 0; +} /* InstanceDetach */ + + diff --git a/xml/xquery/c/utilapi.h b/xml/xquery/c/utilapi.h new file mode 100644 index 0000000..7ca1167 --- /dev/null +++ b/xml/xquery/c/utilapi.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilapi.h +** +** SAMPLE: Error-checking utility header file for utilapi.c +** +** This is the header file for the utilapi.c error-checking utility +** file. The utilapi.c file is compiled and linked in as an object +** module with non-embedded SQL sample programs by the supplied +** makefile and build files. +** +** Macros defined: +** DB2_API_CHECK(MSG_STR) +** EXPECTED_ERR_CHECK(MSG_STR) +** EXPECTED_WARN_CHECK(MSG_STR) +** +** Functions declared: +** SqlInfoPrint - prints to the screen SQL warnings and errors +** CmdLineArgsCheck1 - checks the command line arguments, version 1 +** CmdLineArgsCheck2 - checks the command line arguments, version 2 +** CmdLineArgsCheck3 - checks the command line arguments, version 3 +** CmdLineArgsCheck4 - checks the command line arguments, version 4 +** InstanceAttach - attach to instance +** InstanceDetach - detach from instance +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILAPI_H +#define UTILAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef max +#define max(A, B) ((A) > (B) ? (A) : (B)) +#endif +#ifndef min +#define min(A, B) ((A) > (B) ? (B) : (A)) +#endif + +#define USERID_SZ 128 +#define PSWD_SZ 14 + +#if (defined(DB2NT)) +#define PATH_SEP "\\" +#else /* UNIX */ +#define PATH_SEP "/" +#endif + +/* macro for DB2_API checking */ +#define DB2_API_CHECK(MSG_STR) \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ +if (sqlca.sqlcode < 0) \ +{ \ + return 1; \ +} + +/* macro for expected error checking and message */ +#define EXPECTED_ERR_CHECK(MSG_STR) \ +printf("\n-- The following error report is expected! --"); \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ + +/* macro for expected warning */ +#define EXPECTED_WARN_CHECK(MSG_STR) \ +printf("\n-- The following warning report is expected! --"); \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ + +/* functions used in ..._CHECK macros */ +void SqlInfoPrint(char *, struct sqlca *, int, char *); + +/* other functions */ +int CmdLineArgsCheck1(int, char * argv[], char *, char *, char *); +int CmdLineArgsCheck2(int, char * argv[], char *, char *, char *); +int CmdLineArgsCheck3(int, char * argv[], char *, char *, char *, char *); +int CmdLineArgsCheck4(int, char * argv[], char *, char *, + char *, char *, char *, char *); +int InstanceAttach(char * , char *, char *); +int InstanceDetach(char *); + +#ifdef __cplusplus +} +#endif + +#endif /* UTILAPI_H */ + diff --git a/xml/xquery/c/utilemb.h b/xml/xquery/c/utilemb.h new file mode 100644 index 0000000..602595f --- /dev/null +++ b/xml/xquery/c/utilemb.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilemb.h +** +** SAMPLE: Error-checking utility header file for utilemb.sqc +** +** This is the header file for the utilemb.sqc error-checking utility +** file. The utilemb.sqc file is compiled and linked in as an object +** module with embedded SQL sample programs by the supplied makefile +** and build files. +** +** Macro defined: +** EMB_SQL_CHECK(MSG_STR) +** +** Functions declared: +** TransRollback - rolls back the transaction +** DbConn - connects to the database +** DbDisconn - disconnects from the database +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILEMB_H +#define UTILEMB_H + +#include "utilapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_UID_LENGTH 18 +#define MAX_PWD_LENGTH 30 + +#ifndef max +#define max(A, B) ((A) > (B) ? (A) : (B)) +#endif +#ifndef min +#define min(A, B) ((A) > (B) ? (B) : (A)) +#endif + +#define LOBLENGTH 29 + +/* macro for embedded SQL checking */ +#define EMB_SQL_CHECK(MSG_STR) \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ +if (sqlca.sqlcode < 0) \ +{ \ + TransRollback(); \ + return 1; \ +} + +/* function used in EMB_SQL_CHECK macro */ +void TransRollback(void); + +/* other useful functions with self-explanatory names */ +int DbConn(char * , char *, char *); +int DbDisconn(char *); + +#ifdef __cplusplus +} +#endif + +#endif /* UTILEMB_H */ + diff --git a/xml/xquery/c/utilemb.sqc b/xml/xquery/c/utilemb.sqc new file mode 100644 index 0000000..7ab2196 --- /dev/null +++ b/xml/xquery/c/utilemb.sqc @@ -0,0 +1,130 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilemb.sqc +** +** SAMPLE: Error-checking utility for embedded SQL samples in C +** +** This utility file is compiled and linked in as an object module +** with embedded SQL sample programs by the supplied makefile and +** build files. It checks for and prints to the screen SQL warnings +** and errors. +** +** SQL STATEMENTS USED: +** BEGIN DECLARE SECTION +** END DECLARE SECTION +** ROLLBACK +** CONNECT +** +** Included functions: +** TransRollback - rolls back the transaction +** DbConn - connects to the database +** DbDisconn - disconnects from the database +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "utilapi.c" +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char dbAlias[15]; + char user[129]; + char pswd[15]; +EXEC SQL END DECLARE SECTION; + +void TransRollback() +{ + struct sqlca sqlca; + + /* rollback the transaction */ + printf("\n Rolling back the transaction...\n"); + + EXEC SQL ROLLBACK; + SqlInfoPrint("ROLLBACK", &sqlca, __LINE__, __FILE__); + if (sqlca.sqlcode == 0) + { + printf(" The transaction was rolled back.\n"); + } +} /* TransRollback */ + +int DbConn(char paramDbAlias[], char paramUser[], char paramPswd[]) +{ + struct sqlca sqlca; + int rc = 0; + + strcpy(dbAlias, paramDbAlias); + strcpy(user, paramUser); + strcpy(pswd, paramPswd); + + printf("\n Connecting to '%s' database...\n", dbAlias); + if (strlen(user) == 0) + { + EXEC SQL CONNECT TO :dbAlias; + EMB_SQL_CHECK("CONNECT"); + } + else + { + EXEC SQL CONNECT TO :dbAlias USER :user USING :pswd; + EMB_SQL_CHECK("CONNECT"); + } + printf(" Connected to '%s' database.\n", dbAlias); + + return 0; +} /* DbConn */ + +int DbDisconn(char *dbAlias) +{ + struct sqlca sqlca; + int rc = 0; + + printf("\n Disconnecting from '%s' database...\n", dbAlias); + + /* Commit all non-committed transactions to release database locks */ + EXEC SQL COMMIT; + EMB_SQL_CHECK("COMMIT"); + + EXEC SQL CONNECT RESET; + EMB_SQL_CHECK("CONNECT RESET"); + + printf(" Disconnected from '%s' database.\n", dbAlias); + + return 0; +} /* DbDisconn */ + diff --git a/xml/xquery/c/xpath.sqc b/xml/xquery/c/xpath.sqc new file mode 100644 index 0000000..980e117 --- /dev/null +++ b/xml/xquery/c/xpath.sqc @@ -0,0 +1,342 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xpath.sqc +** +** SAMPLE: How to run queries with a simple path expression +** +** SQL/XML FUNCTIONS USED +** xmlcolumn +** sqlquery +** +** XQuery functions used +** count +** avg +** start-with +** distinct-values +** +** OUTPUT FILE: xpath.out (available in the online documentation) +***************************************************************************** +** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using XQUERY statements, see the XQUERY Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char stmt[16384]; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob2; + sqlint32 num; +EXEC SQL END DECLARE SECTION; + +/* The CustomerDetails method returns all of the XML data in the INFO column of the CUSTOMER table */ +int CustomerDetails(void); + +/* The CustomerFromToronto method returns information about customers from Toronto */ +int CustomerFromToronto(void); + +/* The CitiesInCanada method returns a list of cities that are in Canada */ +int CitiesInCanada(void); + +/* The NumOfCustInToronto method returns the number of customer from Toronto city */ +int NumOfCustInToronto(void); + +/* The CustMobileNum method returns the names of customers whose mobile number starts with 905 */ +int CustMobileNum(void); + +/* The AvgPRice method determines the average prive of the products in the 100 series */ +int AvgPrice(void); + + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + printf("\nXQUERY STATEMENT CANNOT BE EXECUTED STATICALLY."); + printf("\nTO EMBED AN XQUERY STATEMENT, APPLICATION SHOULD MAKE USE OF DYNAMIC SQL LIKE"); + printf("\n PREPARE, DECLARE CURSOR, OPEN AND FETCH STATEMENT"); + printf("OR XMLQUERY FUNCTION WHICH"); + printf("\nCAN BE EMBEDDED STATICALLY\n"); + + printf("\nTHIS SAMPLE DEMONSTRATES HOW THE QUERIES WTH PATH EXPRESSION CAN BE EMBEDDED"); + printf("\n INTO THE APPLICATION"); + + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* the following function will make use of DYNAMIC statements to run the path expression*/ + rc=CustomerDetails(); + rc=CitiesInCanada(); + rc=AvgPrice(); + + /* the following function will make use of XMLQUERY function to run the path expression */ + rc=CustomerFromToronto(); + rc= NumOfCustInToronto(); + rc=CustMobileNum(); + return 0; +} /* main */ +int CustomerDetails() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT CUSTOMER DETAILS USING PATH EXPRESSION.\n"); + + printf("\nXQUERY for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo"); + printf("\n order by xs:double($cust/@Cid)"); + printf("\n return $cust"); + sprintf( stmt, "XQUERY for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo" + " order by xs:double($cust/@Cid)" + " return $cust"); + + + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c1 CURSOR FOR s1; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c1; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + while( sqlca.sqlcode == SQL_RC_OK ) + { + /* Display results */ + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("cursor -- close"); + return 0; +} /* CustomerDetails */ + +int CustomerFromToronto() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\n\nUSE THE XMLQUERY FUNCTION IN SELECT STATEMENT TO FIND OUT THE CUSTOMER"); + printf("\nDETAILS FROM TORONTO CITY"); + printf("\n\nDECLARE C2 CURSOR FOR SELECT XMLQUERY("); + printf("\n'db2-fn:xmlcolumn(\"CUSTOMER.INFO\")/customerinfo[addr/city=\"Toronto\"]'"); + printf("RETURNING SEQUENCE BY REF) from SYSIBM.SYSDUMMY1"); + + sprintf( stmt, "XQUERY for $cust in db2-fn:xmlcolumn(\"CUSTOMER.INFO\")/customerinfo[addr/city=\"Toronto\"]" + " order by $cust/@Cid" + " return $cust"); + + EXEC SQL PREPARE s5 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE C2 CURSOR FOR s5; + EXEC SQL OPEN c2; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + while( sqlca.sqlcode == SQL_RC_OK ) + { + /* Display results */ + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + + EXEC SQL CLOSE c2; +} /* CustomerFromToronto */ + + +int CitiesInCanada() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT CUSTOMERS CITIES IN CANDA USING SIMPLE PATH EXPRESSION\n"); + + printf("\nXQUERY for $cty in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO')"); + printf("\n/customerinfo/addr[@country=\"Canada\"]/city)"); + printf("\norder by $cty"); + printf("\nreturn $cty"); + sprintf( stmt, "XQUERY for $cty in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO')" + "/customerinfo/addr[@country=\"Canada\"]/city) " + "order by $cty " + "return $cty"); + + + EXEC SQL PREPARE s3 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c3 CURSOR FOR s3; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c3; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c3 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + while( sqlca.sqlcode == SQL_RC_OK ) + { + /* Display results */ + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + EXEC SQL FETCH c3 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + + EXEC SQL CLOSE c3; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* CitiesInCanada */ + +int NumOfCustInToronto() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\n\nUSE THE XMLQUERY FUNCTION IN SELECT STATEMENT TO FIND OUT THE CUSTOMER"); + printf("\nNUMBER OF CUSTOMER IN TORONTO CITY"); + printf("\n XQUERY FUNCTION COUNT WILL BE USED TO COUNT THE NUMBER OF CUSTOMER"); + printf("\n\nDECLARE C4 CURSOR FOR XMLCAST(SELECT XMLQUERY("); + printf("\n'fn:count(db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[addr/city=\"Toronto\"])'"); + printf("RETURNING SEQUENCE BY REF) as INTEGER) from SYSIBM.SYSDUMMY1"); + EXEC SQL DECLARE c4 CURSOR FOR SELECT XMLCAST(XMLQUERY( + 'fn:count(db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo[addr/city="Toronto"])' + RETURNING SEQUENCE BY REF) as INTEGER) from SYSIBM.SYSDUMMY1; + EXEC SQL OPEN c4; + EMB_SQL_CHECK("cursor -- open"); + EXEC SQL FETCH c4 INTO :num; + EMB_SQL_CHECK("cursor -- fetch"); + printf("\n NUMBER OF CUSTOMER = %d",num); + /* Display results */ + + EXEC SQL CLOSE c4; + +} /* NumOfCustInToronto */ + +int CustMobileNum() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\n\nUSE THE XMLQUERY FUNCTION IN SELECT STATEMENT TO FIND OUT THE CUSTOMER"); + printf("\nDETAILS WHOSE NUMBER STARTS WITH 905"); + printf("\n\nDECLARE C5 CURSOR FOR SELECT XMLQUERY("); + printf("\n'db2-fn:xmlcolumn(\"CUSTOMER.INFO\")/customerinfo[phone[@type=\"cell\" "); + printf(" and fn:starts-with(text(),\"905\")]]"); + printf("RETURNING SEQUENCE BY REF) from SYSIBM.SYSDUMMY1"); + EXEC SQL DECLARE C5 CURSOR FOR SELECT XMLQUERY( + 'db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo[phone[@type="cell" and fn:starts-with(text(),"905")]]' + RETURNING SEQUENCE BY REF) from SYSIBM.SYSDUMMY1; + EXEC SQL OPEN c5; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c5 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + while( sqlca.sqlcode == SQL_RC_OK ) + { + /* Display results */ + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + EXEC SQL FETCH c5 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + + EXEC SQL CLOSE c5; +} /* CustMobileNum */ + +int AvgPrice() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT AVERAGE PRICE FOR ALL THE PRODUCTS IN 100 SERIES USING PATH EXPRESSION\n"); + printf("\nXQUERY let $prod_price := db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')"); + printf("/product[fn:starts-with(@pid,\"100\")]/description/price"); + printf(" return avg($prod_price)"); + sprintf( stmt, "XQUERY let $prod_price := db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')" + "/product[fn:starts-with(@pid,\"100\")]/description/price" + " return avg($prod_price)"); + + + EXEC SQL PREPARE s6 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c6 CURSOR FOR s6; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c6; + EMB_SQL_CHECK("cursor -- open"); + EXEC SQL FETCH c6 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + /* Display results */ + + EXEC SQL CLOSE c6; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* AvgPrice */ diff --git a/xml/xquery/c/xquery.sqc b/xml/xquery/c/xquery.sqc new file mode 100644 index 0000000..6f03482 --- /dev/null +++ b/xml/xquery/c/xquery.sqc @@ -0,0 +1,425 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xquery.sqc +** +** SAMPLE: How to run a nested XQuery and shows how to pass parameters to +** sqlquery function. +** +** SQL/XML FUNCTIONS USED +** sqlquery +** xmlcolumn +** +** XQUERY EXPRESSION USED +** FLWOR Expression +** +** +** OUTPUT FILE: xquery.out (available in the online documentation) +***************************************************************************** +** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using XQUERY statements, see the XQUERY Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char stmt[16384]; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob; + char id[20]; +EXEC SQL END DECLARE SECTION; + +/* Functions used in the sample */ + +/* The PO_orderbycity function restructures the purchaseorders according to the city. */ +int PO_orderbycity(); + +/* The Customer_orderbyproduct restructures the purchaseorder according to the product */ +int Customer_orderbyproduct(); + +/* The PO_orderbyProvCityStreet function restructures the purchaseorder data according to provience, city and street */ +int PO_orderbyProvCityStreet(); + +/* This CustomerPO function combines the data from customer and product table to create a purchaseorder*/ +int CustomerPO(); + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* Order by city */ + rc=PO_orderbycity(); + + /* Order by product */ + rc=Customer_orderbyproduct(); + + /* Order by provience city and street */ + rc=PO_orderbyProvCityStreet(); + + /* Join data from customer and product tables */ + rc=CustomerPO(); +} + + +int PO_orderbycity() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT CUSTOMER DETAILS CITY WISE USING NESTED XQUERY.\n"); + sprintf( stmt,"XQUERY for $city in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/addr/city)" + " order by $city" + " return" + " " + "{" + " for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[addr/city=$city]" + " let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"pos\"\"," + " (XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", c.custid)," + "XMLELEMENT(NAME \"\"order\"\", c.porder)" + " ) ))" + " FROM purchaseorder AS c\")" + " let $id:=$cust/@Cid," + " $order:=$po/pos[custid=$id]/order" + " order by $cust/@Cid" + " return" + " " + " {$cust/name}" + " {$cust/addr}" + " {$order}" + " }" + " "); + + printf("\n\n %s",stmt); + + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c1 CURSOR FOR s1; + EMB_SQL_CHECK("declare -- cusrsor"); + + /* Open cursor */ + EXEC SQL OPEN c1; + EMB_SQL_CHECK("cursor -- open"); + + /* Fetch the result */ + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + while( sqlca.sqlcode == SQL_RC_OK ) + { + + /* Display results */ + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + + printf ("\n\nThe following query shows how to pass parameters to sqlquery function"); + printf(" which is an enhancement in Viper2 "); + printf("\n-----------------------------------------------------------------------"); + + sprintf(stmt, "XQUERY " + "for $city in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO') /customerinfo/addr/city)" + " order by $city " + "return" + "" + "{" + "for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo [addr/city=$city]" + "let $po:=db2-fn:sqlquery(\"SELECT porder FROM PURCHASEORDER WHERE custid=parameter(1)\",$cust/@Cid)," + " $order:=$po/order" + " order by $cust/@Cid" + " return" + " " + " {$cust/name}" + " {$cust/Addr}" + " {$order}" + " }" + " "); + printf("\n\n%s\n", stmt); + + EXEC SQL PREPARE st FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE cr CURSOR FOR st; + EMB_SQL_CHECK("declare -- cusrsor"); + + /* Open cursor */ + EXEC SQL OPEN cr; + EMB_SQL_CHECK("cursor -- open"); + + /* Fetch the result */ + EXEC SQL FETCH cr INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + while( sqlca.sqlcode == SQL_RC_OK ) + { + + /* Display results */ + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + + EXEC SQL FETCH cr INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + + /* Close the cursor */ + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("cursor -- close"); + EXEC SQL CLOSE cr; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* PO_orderbycity */ + + +int Customer_orderbyproduct() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT CUSTOMER DETAILS PRODUCT WISE USING NESTED XQUERY.\n"); + sprintf( stmt,"XQUERY let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"pos\"\"," + "( XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", c.custid)," + "XMLELEMENT(NAME \"\"order\"\", c.porder)" + " ) ))" + " FROM purchaseorder AS c\" )" + " for $partid in fn:distinct-values(db2-fn:xmlcolumn('PURCHASEORDER.PORDER')/PurchaseOrder/item/partid)" + " order by $partid" + " return" + " " + " " + " {" + " for $id in fn:distinct-values($po[order/PurchaseOrder/item/partid=$partid]/custid)" + " let $order:=" + " {fn:sum($po[custid=$id]/order/PurchaseOrder/item[partid=$partid]/quantity)}" + " ," + " $cust:=db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[@Cid=$id]" + " order by $id" + " return" + " " + " {$order}" + " {$cust}" + " " + " }" + " " + ""); + + printf("\n\n %s",stmt); + EXEC SQL PREPARE s2 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c2 CURSOR FOR s2; + EMB_SQL_CHECK("declare -- cusrsor"); + + /* Open Cursor */ + EXEC SQL OPEN c2; + EMB_SQL_CHECK("cursor -- open"); + + /* Fetch the result */ + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + while( sqlca.sqlcode == SQL_RC_OK ) + { + + /* Display results */ + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + + EXEC SQL CLOSE c2; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* Customer_orderbyproduct */ + +int PO_orderbyProvCityStreet() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO SELECT CUSTOMER DETAILS PROVINCE CITY AND STREET WISE USING NESTED XQUERY.\n"); + sprintf( stmt,"XQUERY let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"pos\"\"," + "( XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", c.custid)," + "XMLELEMENT(NAME \"\"order\"\", c.porder)" + ") ))" + " FROM PURCHASEORDER as c ORDER BY poid\")," + " $addr:=db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/addr" + " for $prov in distinct-values($addr/prov-state)" + " return" + " " + " {" + " for $city in fn:distinct-values($addr[prov-state=$prov]/city)" + " order by $city" + " return" + " " + " {" + " for $s in fn:distinct-values($addr/street) where $addr/city=$city" + " order by $s" + " return" + " " + " {" + " for $info in $addr[prov-state=$prov and city=$city and street=$s]/.." + " order by $info/@Cid" + " return" + " " + " {$info/name}" + " {" + " let $id:=$info/@Cid, $order:=$po[custid=$id]/order" + " return $order" + " }" + " " + " }" + " " + " }" + " " + " }" + " "); + + printf("\n\n %s",stmt); + EXEC SQL PREPARE s3 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c3 CURSOR FOR s3; + EMB_SQL_CHECK("declare -- cusrsor"); + + /* Open cursor */ + EXEC SQL OPEN c3; + EMB_SQL_CHECK("cursor -- open"); + + /* Fetch the result in a BLOB variale */ + EXEC SQL FETCH c3 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Display results */ + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + + EXEC SQL CLOSE c3; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* PO_orderbyProvCityStreet */ + +int CustomerPO() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE SQL STATEMENTS:\n"); + printf(" DECLARE CURSOR\n"); + printf(" OPEN\n"); + printf(" FETCH\n"); + printf(" CLOSE\n"); + printf("TO COMBINE THE DATA FROM PRODUCT AND CUSTOMER TABLE TO CREATE A PURCHASEORDER.\n"); + sprintf( stmt,"XQUERY " + "{" + " for $ns1_customerinfo0 in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo" + " where ($ns1_customerinfo0/@Cid=1001)" + " return" + " " + " {$ns1_customerinfo0/name}" + "
" + " {$ns1_customerinfo0/addr/street}" + " {$ns1_customerinfo0/addr/city}" + " {" + " if($ns1_customerinfo0/addr/@country=\"US\")" + " then" + " $ns1_customerinfo0/addr/prov-state" + " else()" + " }" + " {" + " fn:concat ($ns1_customerinfo0/addr/pcode-zip/text(),\",\",fn:upper-case($ns1_customerinfo0/addr/@country))}" + "
" + "
" + " }" + " {" + " for $ns2_product0 in db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product" + " where ($ns2_product0/@pid=\"100-100-01\")" + " return" + " $ns2_product0" + " }" + "
"); + + + printf("\n\n %s",stmt); + EXEC SQL PREPARE s4 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + EXEC SQL DECLARE c4 CURSOR FOR s4; + EMB_SQL_CHECK("declare -- cusrsor"); + EXEC SQL OPEN c4; + EMB_SQL_CHECK("cursor -- open"); + EXEC SQL FETCH c4 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Display results */ + xmlblob.data[xmlblob.length]='\0'; + printf("\n\n\n%s",xmlblob.data); + + EXEC SQL CLOSE c4; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} /* CustomerPO */ + diff --git a/xml/xquery/c/xquery_xmlproc.exp b/xml/xquery/c/xquery_xmlproc.exp new file mode 100644 index 0000000..c56a855 --- /dev/null +++ b/xml/xquery/c/xquery_xmlproc.exp @@ -0,0 +1 @@ +xquery_proc diff --git a/xml/xquery/c/xquery_xmlproc.sqc b/xml/xquery/c/xquery_xmlproc.sqc new file mode 100644 index 0000000..2693a44 --- /dev/null +++ b/xml/xquery/c/xquery_xmlproc.sqc @@ -0,0 +1,280 @@ +/************************************************************************* +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +*************************************************************************** +** +** SOURCE FILE NAME: xquery_xmlproc.sqc +** +** SAMPLE: Code implementation of a stored procedure Supp_XML_Proc_C +** +** The stored procedures defined in this program is called by the client +** application client_xquery_xmlproc.sqc. Before building and running +** client_xquery_xmlproc.sqc, build the shared library by completing the +** following steps: +** +** BUILDING THE SHARED LIBRARY: +** 1. Ensure the Database Manager Configuration file has the keyword +** KEEPFENCED set to "no". This allows shared libraries to be unloaded +** while you are developing stored procedures. You can view the file's +** settings by issuing the command: "db2 get dbm cfg". You can set +** KEEPFENCED to "no" with this command: "db2 update dbm cfg using +** KEEPFENCED no". NOTE: Setting KEEPFENCED to "no" reduces performance +** the performance of accessing stored procedures, because they have +** to be reloaded into memory each time they are called. If this is a +** concern, set KEEPFENCED to "yes", stop and then restart DB2 before +** building the shared library, by entering "db2stop" followed by +** "db2start". This forces DB2 to unload shared libraries and enables +** the build file or the makefile to delete a previous version of the +** shared library from the "sqllib/function" directory. +** 2. To build the shared library, enter "bldrtn xquery_xmlproc", or use the +** makefile: "make xquery_xmlproc" (UNIX) or "nmake xquery_xmlproc" (Windows). +** +** CATALOGING THE STORED PROCEDURES +** 1. The stored procedures are cataloged automatically when you build +** the client application "client_xquery_xmlproc" using the appropriate "make" +** utility for your Operating System and the "makefile" provided with these +** samples. If you wish to catalog or recatalog them manually, enter +** "spcat_xquery". The spcat_xquery script (UNIX) or spcat_xquery.bat batch file (Windows) +** connects to the database, runs xquery_xmlproc_drop.db2 to uncatalog the stored +** procedures if they were previously cataloged, then runs xquery_xmlproc_create.db2 +** which catalogs the stored procedures, then disconnects from the +** database. +** +** CALLING THE STORED PROCEDURES IN THE SHARED LIBRARY: +** 1. Compile the client_xquery_xmlproc program with "bldapp client_xquery_xmlproc" +** or use the makefile: "make client_xquery_xmlproc" (UNIX) or +** "nmake client_xquery_xmlproc" (Windows). +** 2. Run client_xquery_xmlproc: "client_xquery_xmlproc" (if calling remotely add +** the parameters for database, user ID and password.) +** +** Function xquery_Proc solves the following scenario: +** Some of the suppliers have extended the promotional price date for +** their products. Getting all the customer's Information who purchased +** these products in the extended period will help the financial department +** to return the excess amount paid by those customers. The supplier +** information along with extended date's for the products is provided +** in an XML document and the client wants to have the information +** of all the customers who has paid the excess amount by purchasing those +** products in the extended period. +** +** This procedure will return an XML document containing customer information +** along with the the excess amount paid by them. +** +** SQL STATEMENTS USED: +** CLOSE +** DECLARE +** FETCH +** OPEN +** SELECT +** SELECT INTO +** CREATE +** +** STRUCTURES USED: +** sqlca +** sqlda +** +** EXTERNAL DEPENDENCIES: +** This program must be built on a DB2 server. +** Ensure existence of the sample database. +** Precompile with the SQL precompiler (PREP in DB2) +** Bind to a database (BIND in DB2) +** Compile and link loop with the compiler supported on your +** platform. +** +** OUTPUT FILE: client_xquery_xmlproc.out (available in the online documentation) +*************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +SQL_API_RC SQL_API_FN xquery_proc( SQLUDF_CLOB* inXML, + SQLUDF_CLOB* outXML, + sqlint32 *outReturnCode, + SQLUDF_NULLIND *inXML_ind, + SQLUDF_NULLIND *outXML_ind, + SQLUDF_NULLIND *outReturnCode_ind, + SQLUDF_TRAIL_ARGS) +{ + + EXEC SQL INCLUDE SQLCA; + + EXEC SQL BEGIN DECLARE SECTION; + sqlint64 custid,quantity; + SQL TYPE IS XML AS CLOB(5000) ipdata,orders,tempXML; + char prodid[12],partid[12]; + char oldPromoDate[11], newPromoDate[11]; + double originalPrice,promoPrice,excessamount; + char insstmt1[1024],insstmt2[1024]; + char stmt_xq1[2024],stmt_xq2[2024],stmt_xq3[2024],stmt_xq4[2024]; + EXEC SQL END DECLARE SECTION; + + /* Initialize the input data */ + ipdata.length = 0; + strcpy(ipdata.data," "); + + /* Initialize output parameters .. */ + *outReturnCode = -1; + *outReturnCode_ind = 0; + + /* Copy input parameters to host variables */ + ipdata.length = inXML->length; + strncpy(ipdata.data, inXML->data, inXML->length); + ipdata.data[ipdata.length]='\n'; + + /* an XQUERY statement to restructure all the PurchaseOrders + into the following form + + + XXXX + XXX-XXX-XX + XX + ............................... + ................. + store the above XML document in an application variable "orders" */ + sprintf(stmt_xq1,"XQUERY let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"porders\"\"," + "( XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", p.custid), p.porder))) " + "FROM PURCHASEORDER as p\") return {for $i in $po for $j in " + "$po[custid=$i/custid]/PurchaseOrder[@PoNum=$i/PurchaseOrder/@PoNum]/item " + "return {$i/PurchaseOrder/@OrderDate}{$i/custid}{$j/partid}" + "{$j/quantity}}"); + + EXEC SQL PREPARE stmt1 FROM :stmt_xq1 ; + EXEC SQL DECLARE cur_xq1 CURSOR FOR stmt1; + EXEC SQL OPEN cur_xq1; + EXEC SQL FETCH cur_xq1 INTO :orders; + EXEC SQL CLOSE cur_xq1; + + /* select the oldpromodate, newpromodate, price and promoprice + for the products for which the promodate is extended + using input XML document */ + sprintf(stmt_xq2,"SELECT Pid,PromoEnd,Price,PromoPrice,XMLCAST(XMLQUERY(" + "'$info/Suppliers/Supplier/Products/Product[@id=$pid]/ExtendedDate'" + "passing cast(? as XML) as \"info\", pid as \"pid\") as DATE) FROM " + "product WHERE XMLEXISTS('for $prod in $info//Product[@id=$pid] return" + " $prod' passing by ref cast(? as XML) as \"info\", pid as \"pid\")"); + + EXEC SQL PREPARE stmt2 FROM :stmt_xq2; + EXEC SQL DECLARE cur_xq2 CURSOR FOR stmt2; + EXEC SQL OPEN cur_xq2 USING :ipdata, :ipdata; + EXEC SQL FETCH cur_xq2 INTO :prodid, :oldPromoDate, :originalPrice, :promoPrice, :newPromoDate; + + /* create two temporary tables */ + EXEC SQL CREATE TABLE temp_table1(custid INT,partid VARCHAR(12),excessamount DECIMAL(30,2)); + EXEC SQL CREATE TABLE temp_table2(cid INT,total DECIMAL(30,2)); + + /* repeat the above for all products */ + while (sqlca.sqlcode != 100) + { + /* finding out the toatal quantity of the product purchased by a customer + if that order is made in between oldpromodate and extended promodate. + this query will return the custid, product id and total quantity of + that product purchased in all his orders. */ + sprintf(stmt_xq3,"WITH temp1 AS (SELECT cid,partid,quantity,orderdate FROM " + "XMLTABLE('$od//item' passing cast(? as XML) as \"od\" " + "COLUMNS cid BIGINT path './custid', " + "partid VARCHAR(20) path './partid', orderdate DATE path " + "'./@OrderDate', quantity BIGINT path './quantity') as temp2) " + "SELECT temp1.cid, temp1.partid, sum(temp1.quantity) as quantity " + "FROM temp1 WHERE partid=? and orderdate>cast(? as DATE) and " + "orderdate + + XXXX + XXXX.XXXX + + xxxx xxx + ......... + + + ............ + */ + sprintf(stmt_xq4, "XQUERY let $res:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME " + "\"\"Customer\"\",( XMLCONCAT(XMLELEMENT(NAME \"\"Custid\"\", t.cid)," + "XMLELEMENT( NAME \"\"Total\"\", t.total),c.info))) " + "FROM temp_table2 AS t,customer AS c WHERE t.cid = c.cid\") " + "return {$res}"); + + EXEC SQL PREPARE stmt4 FROM :stmt_xq4; + EXEC SQL DECLARE cur_xq4 CURSOR FOR stmt4; + EXEC SQL OPEN cur_xq4; + EXEC SQL FETCH cur_xq4 INTO :tempXML; + EXEC SQL CLOSE cur_xq4; + + /* drop the temporary tables */ + EXEC SQL DROP TABLE temp_table1; + EXEC SQL DROP TABLE temp_table2; + + /* assign the data to output parameters */ + outXML->length = tempXML.length; + strncpy(outXML->data, tempXML.data, tempXML.length); + *outXML_ind = 0; + + *outReturnCode = sqlca.sqlcode; + *outReturnCode_ind = 0; + + return 0; +} diff --git a/xml/xquery/c/xquery_xmlproc_create.db2 b/xml/xquery/c/xquery_xmlproc_create.db2 new file mode 100644 index 0000000..f22a993 --- /dev/null +++ b/xml/xquery/c/xquery_xmlproc_create.db2 @@ -0,0 +1,53 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xquery_xmlproc_create.db2 +-- +-- SAMPLE: How to catalog the stored procedure contained in xquery_xmlproc.sqc +-- +-- To run this script from the CLP, issue the command +-- "db2 -td@ -vf xquery_xmlproc_create.db2" +----------------------------------------------------------------------------- +-- For more information on the sample programs, see the README file. +-- +-- For information on developing C applications, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- create procedure Supp_XML_Proc_C +CREATE PROCEDURE Supp_XML_Proc_C ( IN inXML XML AS CLOB(5000), + OUT Customers XML AS CLOB(5000), + OUT outReturnCode INTEGER) +LANGUAGE C +PARAMETER STYLE SQL +FENCED +PARAMETER CCSID UNICODE +EXTERNAL NAME 'xquery_xmlproc!xquery_proc'@ + +CONNECT RESET@ diff --git a/xml/xquery/c/xquery_xmlproc_drop.db2 b/xml/xquery/c/xquery_xmlproc_drop.db2 new file mode 100644 index 0000000..ffe65f2 --- /dev/null +++ b/xml/xquery/c/xquery_xmlproc_drop.db2 @@ -0,0 +1,49 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xquery_xmlproc_drop.db2 +-- +-- SAMPLE: How to uncatalog the stored procedures contained in xquery_xmlproc.sqc +-- +-- To run this script from the CLP, perform the following steps: +-- 1. issue the command "db2 -td@ -vf xquery_xmlproc_drop.db2" +----------------------------------------------------------------------------- +-- For more information on the sample programs, see the README file. +-- +-- For information on developing C applications, see the Application +-- Development Guide. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- drop the procedure Supp_XML_Proc_C +DROP PROCEDURE Supp_XML_Proc_C( XML AS CLOB(5000), XML AS CLOB(5000), INTEGER)@ + +-- reset the connection +CONNECT RESET@ + + diff --git a/xml/xquery/c/xqueryparam.sqc b/xml/xquery/c/xqueryparam.sqc new file mode 100644 index 0000000..33eb0ff --- /dev/null +++ b/xml/xquery/c/xqueryparam.sqc @@ -0,0 +1,338 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SAMPLE FILE NAME: xqueryparam.sqc +** +** PURPOSE: This sample shows how to pass parameters to the +** db2-fn:sqlquery function. +** +** USAGE SCENARIO: The super market manager maintains database with +** "employees" and "dept_location" tables. "Employee" table +** contains employee ID and employee address. +** "dept_location" table contains the department and +** and it's location details.He will query +** these tables to get information about employees, their +** department details. +** The last XQuery exprepression in this sample shows +** purchaseorder details from the sample database +** purchaseorder table. +** +** PREREQUISITE: NONE +** +** EXECUTION: bldapp xqueryparam +** xqueryparam +** +** INPUTS: NONE +** +** OUTPUTS: Queries will display the results. +** +** OUTPUT FILE: xqueryparam.out (available in the online documentation) +** +** +** SQL STATEMENTS USED: +** CREATE TABLE +** INSERT +** DROP +** +** SQL/XML FUNCTIONS USED: +** SQLQUERY +** XMLCOLUMN +** +** +***************************************************************************** +** For more information about the command line processor (CLP) scripts, +** see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +** +******************************************************************************* +** SAMPLE DESCRIPTION +** +******************************************************************************* +** 1. Passing single parameter to SQL fullselect in db2-fn:sqlquery function. +** +** 2. Passing multiple parameters to SQL fullselect in db2-fn:sqlquery function. +** +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char stmt[16384]; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob; + char id[20]; +EXEC SQL END DECLARE SECTION; + +main(int argc, char *argv[]) +{ + int rc = 0; + struct sqlca sqlca; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + sprintf(stmt, "CREATE TABLE employees(empid int, addr XML)"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE employees"); + + sprintf(stmt, "CREATE TABLE dept_location(dept_name varchar(20)," + " branch_name varchar(50)," + " block_no varchar(20), street " + " varchar(20), city varchar(20), " + " zip_code varchar(20), " + " dept_details XML)"); + + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("CREATE TABLE dept_location"); + + sprintf(stmt, "INSERT INTO employees " + "VALUES (1005, XMLPARSE(document " + "' " + "Ravi varma " + "" + "Koramangala" + "Bangalore" + "Karnataka" + "500042" + "" + "'))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO employees"); + + sprintf(stmt, "INSERT INTO employees " + "VALUES (1006, XMLPARSE(document " + "'" + "Oswal Menard" + "" + "Hebbal" + "Bangalore" + "Karnataka" + "500067" + "" + "'))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO employees"); + + sprintf(stmt, "INSERT INTO dept_location " + "VALUES ('DB2', 'EGL', 'B', 'Koramangala', 'Bangalore', '500042'," + "XMLPARSE(document " + "'" + "Peter suzanski" + "" + "Samples" + "testing" + "Development" + "" + "140" + "' ))"); + printf("\n%s\n", stmt); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO dept_location"); + + sprintf(stmt, "INSERT INTO dept_location " + "VALUES ('Informix','MANYATA', 'D2', 'Hebbal', 'Bangalore', '500067'," + "XMLPARSE(document" + "'" + "Jeff " + "" + "bird" + "QA" + "" + "60" + "' ))"); + printf("\n%s\n", stmt); + + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("INSERT INTO dept_location"); + + /**************************************************************************** + ** 1. Passing single parameter to SQL fullselect in db2-fn:sqlquery function. + *****************************************************************************/ + + printf("\nThe following XQuery expression returns an employee's postal"); + printf("\n code and department details when the employee and the department"); + printf("\n are in same location (defined by zip code)\n "); + + sprintf(stmt, "XQUERY " + "declare default element namespace \"http://posample.org\";" + "for $pcode in db2-fn:xmlcolumn(\"EMPLOYEES.ADDR\")" + "/employeeinfo/addr/pcode-zip " + "for $deptinfo in db2-fn:sqlquery( \"SELECT dept_details FROM " + "dept_location WHERE zip_code = parameter(1)\", $pcode) " + " order by $pcode " + "return {$pcode, $deptinfo }"); + printf("\n%s\n", stmt); + + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("PREPARE s1"); + + EXEC SQL DECLARE c1 CURSOR for s1; + EMB_SQL_CHECK("DECLARE CURSOR"); + + EXEC SQL OPEN c1; + EMB_SQL_CHECK("OPEN c1"); + + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("FETCH c1"); + + printf("\n----------------------------------------------------"); + while (sqlca.sqlcode == SQL_RC_OK) + { + printf("\n%s\n", xmlblob.data); + + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("FETCH c1"); + } + printf("\n----------------------------------------------------"); + + EXEC SQL CLOSE c1; + EMB_SQL_CHECK("CLOSE c1"); + + /************************************************************************ + ** 2. Passing multiple parameters to SQL fullselect in + ** db2-fn:sqlquery function. + ************************************************************************/ + + printf("\n The following XQuery expression returns an employee's postal"); + printf("\n code, department name and department details,when an employee "); + printf("\n and a department are in same location and the employee belongs"); + printf("\n to one of the following departments: DB2, Informix or CM.\n "); + + sprintf(stmt,"XQUERY " + "declare default element namespace \"http://posample.org\"; " + "for $pcode in db2-fn:xmlcolumn(\"EMPLOYEES.ADDR\")" + "/employeeinfo/addr/pcode-zip," + "$dept in ('DB2', 'Informix', 'CM')" + "for $deptinfo in db2-fn:sqlquery(" + "\"SELECT dept_details FROM dept_location " + "WHERE zip_code = parameter(1) and dept_name = parameter(2)\", $pcode, $dept)" + " order by $pcode " + "return " + "{$pcode}" + "{$dept}" + "{$deptinfo}" + ""); + printf("\n%s\n", stmt); + + EXEC SQL PREPARE s2 FROM :stmt; + EMB_SQL_CHECK("PREPARE s2"); + + EXEC SQL DECLARE c2 CURSOR FOR s2; + EMB_SQL_CHECK("DECLARE CURSOR"); + + EXEC SQL OPEN c2; + EMB_SQL_CHECK("OPEN c2"); + + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("FETCH c2"); + + printf("\n----------------------------------------------------"); + while(sqlca.sqlcode == SQL_RC_OK) + { + printf("\n%s\n", xmlblob.data); + + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("FETCH c2"); + } + printf("\n----------------------------------------------------"); + + EXEC SQL CLOSE c2; + EMB_SQL_CHECK("CLOSE c2"); + + printf("\n The following XQuery expression uses the purchaseorder "); + printf("\n table from the sample database"); + printf("\n The XQuery expression returns all purchaseorders "); + printf("\n made by customers after the date \"2005-11-18\" \n"); + + sprintf(stmt, "XQUERY " + "for $ponum in db2-fn:xmlcolumn(\"PURCHASEORDER.PORDER\")" + "/PurchaseOrder/@PoNum " + "for $x in db2-fn:sqlquery(\"SELECT porder FROM purchaseorder" + " WHERE OrderDate > parameter(1) and poid = parameter(2)\"," + "'2005-11-18', $ponum) order by $ponum return {$x} "); + printf("\n%s\n", stmt); + + EXEC SQL PREPARE s3 FROM :stmt; + EMB_SQL_CHECK("PREPARE s3"); + + EXEC SQL DECLARE c3 CURSOR FOR s3; + EMB_SQL_CHECK("DECLARE c3"); + + EXEC SQL OPEN c3; + EMB_SQL_CHECK("OPEN c3"); + + EXEC SQL FETCH c3 INTO :xmlblob; + EMB_SQL_CHECK("FETCH c3"); + + printf("\n----------------------------------------------------"); + while (sqlca.sqlcode == SQL_RC_OK) + { + printf("\n%s\n", xmlblob.data); + + EXEC SQL FETCH c3 INTO :xmlblob; + EMB_SQL_CHECK("FETCH c3"); + } + printf("\n----------------------------------------------------\n"); + + EXEC SQL CLOSE c3; + EMB_SQL_CHECK("CLOSE c3"); + + /********************************************************************* + ** CLEANUP + *********************************************************************/ + + EXEC SQL DROP TABLE employees; + EMB_SQL_CHECK("DROP TABLE employees"); + + EXEC SQL DROP TABLE dept_location; + EMB_SQL_CHECK("DROP TABLE dept_location"); +} + diff --git a/xml/xquery/c/xupdate.sqc b/xml/xquery/c/xupdate.sqc new file mode 100755 index 0000000..a305255 --- /dev/null +++ b/xml/xquery/c/xupdate.sqc @@ -0,0 +1,427 @@ +/* ************************************************************************* +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +** ************************************************************************* +** +** SAMPLE FILE NAME: xupdate.sqc +** +** PURPOSE: To demonstrate how to insert, delete, update, replace, and rename +** one or more XML documents or document fragments using transform +** expressions. +** +** USAGE SCENARIO: The orders made by customers are stored in the existing +** PurchaseOrder system. A customer has ordered some items initially, +** and now the customer wants to add some more items and remove some +** items from the list. This sample will show how the order is modified +** using the XQuery transform expression and updating expressions. +** +** PREREQUISITE: NONE +** +** EXECUTION: bldapp xupdate (Build the sample) +** xupdate (Run the sample) +** +** INPUTS: NONE +** +** OUTPUTS: Successful updation of the purchase orders. +** +** OUTPUT FILE: xupdate.out (available in the online documentation) +** +** SQL STATEMENTS USED: +** INSERT +** UPDATE +** DROP +** +** SQL/XML FUNCTIONS USED: +** XMLQUERY +** +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing C applications, see the Application +** Development Guide. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on DB2 APIs, see the Administrative API Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http:**www.software.ibm.com/data/db2/udb/ad +**************************************************************************** +** +** SAMPLE DESCRIPTION +** +** ************************************************************************* +** 1. Insert Expression -- Insert a new element to the existing XML document/fragment. +** 2. Delete Expression -- Delete some elements from the exisitng XML document/fragment. +** 3. Replace value of Expression -- i) Replace the value of an element +** ii) Replace the value of attribute +** 4. Replace Expression -- Replace an element and attribute +** 5. Rename Expression -- i) Rename an element in the existing XML document/fragment. +** ii) Rename an attribute in the existing XML document/fragment. +** 6. Insert and Replace Expressions -- Combination of transform expressions. +** *************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilemb.h" + +EXEC SQL BEGIN DECLARE SECTION; + char stmt[1684]; + SQL TYPE IS XML AS BLOB( 10K ) xmlblob; +EXEC SQL END DECLARE SECTION; + +int main(int argc, char *argv[]) +{ + int rc = 0; + char dbAlias[SQL_ALIAS_SZ + 1]; + char user[USERID_SZ + 1]; + char pswd[PSWD_SZ + 1]; + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + /* connect to database */ + rc = DbConn(dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + rc=insertExpr(); + rc=deleteExpr(); + rc=renameExpr(); + rc=replaceExpr(); + rc=combinationExprr(); + + return 0; +} /* main */ + +int insertExpr() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n*******************************************************************************"); + printf("\n Insert Expression -- Insert a new element to the existing XML document/fragment."); + printf("\n*******************************************************************************"); + sprintf(stmt,"SELECT xmlquery('transform copy $po := $order modify do insert document { 100-103-01 Snow Shovel, Super Deluxe 26 inch 2 49.99 } as last into $po return $po' passing purchaseorder.porder as \"order\") from purchaseorder where poid=5004"); + + printf("\n\n Query: \n %s", stmt); + EXEC SQL PREPARE s1 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + + EXEC SQL DECLARE c1 CURSOR FOR s1; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c1; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + printf("\n\n Data after insert:"); + /* Print the result */ + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n%s",xmlblob.data); + EXEC SQL FETCH c1 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c1; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} + +int deleteExpr() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n\n*******************************************************************************"); + printf("\n Delete Expression -- Delete some elements from the exisitng XML document/fragment."); + printf("\n*******************************************************************************"); + sprintf( stmt,"UPDATE purchaseorder SET porder = xmlquery('transform copy $po := $order modify do delete $po/PurchaseOrder/item[partid = ''100-201-01''] return $po' passing porder as \"order\") WHERE poid=5004"); + + printf("\n\n Query: \n%s",stmt); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Update -- statement"); + + sprintf( stmt, "SELECT porder FROM purchaseorder WHERE poid=5004"); + EXEC SQL PREPARE s2 FROM :stmt; + EXEC SQL DECLARE c11 CURSOR FOR s2; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c11; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c11 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + printf("\n\n Data after delete: "); + /* Print the result */ + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n%s",xmlblob.data); + EXEC SQL FETCH c11 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c11; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + return 0; + +} //deleteExpr + +int replaceExpr() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n\n*******************************************************************************"); + printf("\n Replace value of Expression -- Replace the value of an element"); + printf("\n*******************************************************************************"); + + sprintf( stmt,"UPDATE purchaseorder SET porder = xmlquery('transform copy $po := $order modify for $i in $po/PurchaseOrder[@OrderDate = \"2006-02-18\"]//price return do replace value of $i with $i*0.8 return $po' passing porder as \"order\")"); + + printf("\n\n Query: \n%s",stmt); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Update -- statement"); + + sprintf( stmt, "SELECT porder FROM purchaseorder ORDER BY poid"); + + EXEC SQL PREPARE s3 FROM :stmt; + EXEC SQL DECLARE c111 CURSOR FOR s3; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c111; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c111 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Print the result */ + printf("\n\n Data after replace value of an element:"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n%s",xmlblob.data); + EXEC SQL FETCH c111 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c111; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + + + + printf("\n\n*******************************************************************************"); + printf("\n Replace value of Expression -- Replace the value of attribute"); + printf("\n*******************************************************************************"); + sprintf( stmt,"UPDATE purchaseorder SET porder = xmlquery('transform copy $po := $order modify do replace value of $po/PurchaseOrder/@Status with \"Shipped\" return $po' passing porder as \"order\") WHERE poid = 5002"); + + printf("\n\n Query: \n%s",stmt); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Update -- statement"); + + sprintf( stmt, "SELECT porder FROM purchaseorder WHERE poid = 5002"); + EXEC SQL PREPARE s4 FROM :stmt; + EXEC SQL DECLARE c2 CURSOR FOR s4; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c2; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Print the result */ + printf("\n\n Data after replace value of an attribute:"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n%s",xmlblob.data); + EXEC SQL FETCH c2 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c2; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + + + printf("\n\n*******************************************************************************"); + printf("\n Replace Expression -- Replace an element and attribute."); + printf("\n*******************************************************************************"); + + sprintf( stmt,"XQUERY for $k in db2-fn:sqlquery(\"select porder from purchaseorder where poid = 5004\") return transform copy $i := $k modify (do replace $i//PurchaseOrder/@OrderDate with ( attribute BilledDate {\"12-12-2007\"}), do replace $i//item[1]/price with $k//item[1]/price) return $i//PurchaseOrder"); + + printf("\n\n Query: \n%s",stmt); + EXEC SQL PREPARE s5 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + + EXEC SQL DECLARE c3 CURSOR FOR s5; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c3; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c3 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Print the result */ + printf("\n\n Data after replacing an element and attribute:"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n%s",xmlblob.data); + EXEC SQL FETCH c3 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c3; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + + return 0; + +} //replaceExpr + + +int renameExpr() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n\n*******************************************************************************"); + printf("\n Rename Expression -- Rename an element in the existing XML document/fragment."); + printf("\n*******************************************************************************"); + + sprintf( stmt,"UPDATE purchaseorder SET porder = xmlquery('transform copy $po := $order modify for $i in $po//item[quantity > 1] return do rename $i as \"items\" return $po' passing porder as \"order\") WHERE poid=5002"); + + printf("\n\n Query: \n%s",stmt); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Update -- statement"); + + sprintf( stmt, "SELECT porder FROM purchaseorder WHERE poid=5002"); + EXEC SQL PREPARE s6 FROM :stmt; + EXEC SQL DECLARE c5 CURSOR FOR s6; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c5; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c5 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Print the result */ + printf("\n\n Data after renaming an element:"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n%s",xmlblob.data); + EXEC SQL FETCH c5 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c5; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + + printf("\n\n*******************************************************************************"); + printf("\n Rename Expression -- Rename an attribute in the existing XML document/fragment."); + printf("\n*******************************************************************************"); + + sprintf(stmt, "XQUERY for $k in db2-fn:sqlquery(\"select porder from purchaseorder where poid=5003\") return transform copy $i := $k modify (do rename $i//*:PurchaseOrder/@OrderDate as \"BilledDate\", do insert attribute Totalcost {\"405.99\"} into $i//*:PurchaseOrder, do rename $i//*:PurchaseOrder//*:partid as \"productid\") return $i//*:PurchaseOrder"); + + printf("\n\n Query: \n%s",stmt); + EXEC SQL PREPARE s7 FROM :stmt; + EMB_SQL_CHECK("prepare -- statement"); + + EXEC SQL DECLARE c21 CURSOR FOR s7; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c21; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c21 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Print the result */ + printf("\n\n Data after renaming an attribute and an element:"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n%s",xmlblob.data); + EXEC SQL FETCH c21 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c21; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + + return 0; + +} //renameExpr + + +int combinationExprr() +{ + int rc = 0; + struct sqlca sqlca; + printf("\n\n*******************************************************************************"); + printf("\n Insert and Replace Expressions -- Combination of transform expressions."); + printf("\n*******************************************************************************"); + + sprintf( stmt,"UPDATE purchaseorder SET porder = xmlquery ('transform copy $po := $order modify ( for $i in $po/PurchaseOrder[@OrderDate = ''2006-02-18'']//price return do replace value of $i with $i*0.8, do insert document { 100-103-01 Snow Shovel, Super Deluxe 26 inch 2 49.99 } as last into $po/PurchaseOrder) return $po' passing porder as \"order\") WHERE poid = 5004 "); + + printf("\n\n Query: \n%s",stmt); + EXEC SQL EXECUTE IMMEDIATE :stmt; + EMB_SQL_CHECK("Update -- statement"); + + sprintf( stmt, "SELECT porder FROM purchaseorder WHERE poid=5004"); + EXEC SQL PREPARE s8 FROM :stmt; + EXEC SQL DECLARE c4 CURSOR FOR s8; + EMB_SQL_CHECK("declare -- cusrsor"); + + EXEC SQL OPEN c4; + EMB_SQL_CHECK("cursor -- open"); + + EXEC SQL FETCH c4 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + + /* Print the result */ + printf("\n\n Data after insert and replace:"); + while( sqlca.sqlcode == SQL_RC_OK ) + { + xmlblob.data[xmlblob.length]='\0'; + printf("\n%s",xmlblob.data); + EXEC SQL FETCH c4 INTO :xmlblob; + EMB_SQL_CHECK("cursor -- fetch"); + } + EXEC SQL CLOSE c4; + EXEC SQL COMMIT; + EMB_SQL_CHECK("cursor -- close"); + + return 0; +} //combinationExprr + diff --git a/xml/xquery/cli/bldapp b/xml/xquery/cli/bldapp new file mode 100644 index 0000000..4ac3d5d --- /dev/null +++ b/xml/xquery/cli/bldapp @@ -0,0 +1,94 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldapp +# Builds CLI applications for Linux +# Usage: bldapp [ [ ]] + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then + BITWIDTH=64 +else + # x86 is the only native 32-bit platform + BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] +then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# If an embedded SQL program, precompile and bind it. +if [ -f $1".sqc" ] +then + ./embprep $1 $2 $3 $4 +fi + +# Compile the error-checking utility. +gcc $EXTRA_C_FLAGS -I$DB2PATH/include -c utilcli.c + +# Compile the program. +gcc $EXTRA_C_FLAGS -I$DB2PATH/include -c $1.c + +# Link the program. +gcc $EXTRA_C_FLAGS -o $1 $1.o utilcli.o $EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2 diff --git a/xml/xquery/cli/bldrtn b/xml/xquery/cli/bldrtn new file mode 100644 index 0000000..880545c --- /dev/null +++ b/xml/xquery/cli/bldrtn @@ -0,0 +1,94 @@ +#! /bin/sh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldrtn +# Builds CLI routines (stored procedures or UDFs) for Linux +# Usage: bldrtn + +# Set DB2PATH to where DB2 will be accessed. +# The default is the standard instance path. +DB2PATH=$HOME/sqllib + +# Default flags +EXTRA_C_FLAGS="" + +# Figure out which Linux architecture we are on +HARDWAREPLAT=`uname -m` + +# Default to native bitwidth for the platform +if [ "$HARDWAREPLAT" = "x86_64" ] || [ "$HARDWAREPLAT" = "ppc64" ] || + [ "$HARDWAREPLAT" = "s390x" ] || [ "$HARDWAREPLAT" = "ia64" ] || + [ "$HARDWAREPLAT" = "ppc64le" ] +then + BITWIDTH=64 +else + # x86 is the only native 32-bit platform + BITWIDTH=32 +fi + +# Uncomment the next line to force a 32-bit application compile/link +#BITWIDTH=32 + +# Set flags for 32-bit compilation on non-native 32-bit platforms +if [ $BITWIDTH = "32" ] +then + LIB="lib32" + if [ "$HARDWAREPLAT" = "s390x" ] + then + EXTRA_C_FLAGS="-m31" + else + if [ "$HARDWAREPLAT" = "ia64" ] + then + # DB2 does not support 32-bit applications on Linux on IA64 + BITWIDTH=64 + else + EXTRA_C_FLAGS="-m32" + fi + fi +fi + +# Set flags for 64-bit compilation +if [ $BITWIDTH = "64" ] +then + LIB="lib64" + if [ "$HARDWAREPLAT" != "ia64" ] + then + # gcc on ia64 does not support the -m64 flag + EXTRA_C_FLAGS="-m64" + fi +fi + +# Setup the embedded library path +EXTRA_LFLAG="-Wl,-rpath,$DB2PATH/$LIB" + +# Compile the error-checking utility. +gcc $EXTRA_C_FLAGS -fpic -I$DB2PATH/include -c utilcli.c -D_REENTRANT + +# Compile the program. +gcc $EXTRA_C_FLAGS -fpic -I$DB2PATH/include -c $1.c -D_REENTRANT + +# Link the program. +gcc $EXTRA_C_FLAGS -o $1 $1.o utilcli.o -shared $EXTRA_LFLAG \ + -L$DB2PATH/$LIB -ldb2 -lpthread + +# Copy the shared library to the function subdirectory. +# The user must have write permission to this directory. +rm -f $DB2PATH/function/$1 +cp $1 $DB2PATH/function diff --git a/xml/xquery/cli/flwor.c b/xml/xquery/cli/flwor.c new file mode 100644 index 0000000..ded0516 --- /dev/null +++ b/xml/xquery/cli/flwor.c @@ -0,0 +1,458 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: flwor.c +** +** SAMPLE: How to use XQuery FLWOR expressions +** +** CLI FUNCTIONS USED: +** SQLAllocHandle +** SQLExecDirect +** SQLBindCol +** SQLFetch +** SQLFreeHandle +** SQLPrepare +** SQLBindParameter +** +** SQL/XML FUNCTIONS USED: +** xmlcolumn +** xmlquery +** +** XQuery function used: +** data +** string +** +** OUTPUT FILE: flwor.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on using XQuery statements, see the XQuery Reference + +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ + +/* The orderCustDetails method returns customer information in alphabetical order by customer name */ +int OrderCustDetails(SQLHANDLE hdbc); + +/* The conditionalCustDetails1 returns information for customers whose customer ID is greater than + the cid value passed as an argument */ +int conditionalCustDetails1(SQLHANDLE hdbc,sqlint32 cid); + +/* The conditionalCustDetails2 method returns information for customers whose customer ID is greater than + the cid value passed to the function and who dont live in the country passed as an argument */ +int conditionalCustDetails2(SQLHANDLE hdbc,int cid, char *country); + +/* The maxpriceproduct function returns the product details with maximun price */ +int maxpriceproduct(SQLHANDLE hdbc); + +/* The basicproduct function returns the product with basic attribute value true + if the price is less then price parameter otherwiese false */ +int basicproduct(SQLHANDLE hdbc,float price); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + SQLINTEGER cid; + float price; + char country[10]; + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE DEMONSTRATES HOW THE SIMPLE FLWOR EXPRESSION QUERIES CAN BE USED IN CLI"); + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + + /* Set the attribute SQL_ATTR_XML_DECLARATION to skip the XML declaration from XML Data */ + rc=SQLSetConnectAttr(hdbc, SQL_ATTR_XML_DECLARATION, (SQLPOINTER)SQL_XML_DECLARATION_NONE, SQL_NTS); + printf("%d", rc); + if (rc != 0) + { + return rc; + } + + + printf("*******************************************************************\n"); + printf("Return customer information in alphabetical order by customer name.....\n\n"); + rc=OrderCustDetails(hdbc); + + printf("*******************************************************************\n\n"); + printf("Return the product information with maximum price......\n\n"); + rc=maxpriceproduct(hdbc); + + cid=1002; + printf("*******************************************************************\n"); + printf("Return the information for customer whose customer ID is greater then %d.....\n\n", cid); + rc=conditionalCustDetails1(hdbc,cid); + + cid=1000; + strcpy(country,"US"); + printf("*******************************************************************\n"); + printf("Return the customer information with customer ID greater then %d and",cid); + printf(" who dont live in country %s.....\n\n", country); + rc=conditionalCustDetails2(hdbc,cid,country); + + price=10; + printf("*******************************************************************\n\n"); + printf("Return the product with basic price %f........\n\n", price); + rc=basicproduct(hdbc,price); + return rc; +} /* main */ + +int OrderCustDetails(SQLHANDLE hdbc) +{ + + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* query to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"for $custinfo in db2-fn:xmlcolumn('CUSTOMER.INFO')" + "/customerinfo[addr/@country=\"Canada\"]" + " order by $custinfo/name,fn:number($custinfo/@Cid)" + " return $custinfo"; + + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* Set the attribute SQL_ATTR_XQUERY_STATEMENT to indicate that the query is an XQuery */ + rc = SQLSetStmtAttr(hstmt, SQL_ATTR_XQUERY_STATEMENT, (SQLPOINTER)SQL_TRUE, SQL_NTS); + + if (rc != 0) + { + return rc; + } + + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("%s \n\n",xmldata); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* OrderCustDetails */ + +int conditionalCustDetails1(SQLHANDLE hdbc,sqlint32 cid) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* SQL/XML statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *) "select xmlquery('" + " for $customer in $cust/customerinfo" + " where ($customer/@Cid > $id)" + " order by $customer/@Cid " + " return " + " {$customer/name} {$customer/addr} '" + " passing by ref customer.info as \"cust\", cast(? as integer) as \"id\")" + " from customer order by cid"; + + + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" %s\n", stmt); + cliRC = SQLPrepare(hstmt,(SQLCHAR *)stmt,SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind the parameter value */ + printf("\nBind the parameter markers with the value %d", cid); + SQLBindParameter(hstmt,1,SQL_PARAM_INPUT,SQL_C_LONG,SQL_INTEGER,4,0,&cid,4,NULL); + + printf("\nExecute the Statement.....\n"); + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 3000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + if(strcmp((char *)xmldata,"")!=0) + printf("%s \n\n",xmldata); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* conditionalCustDetails1 */ + +int conditionalCustDetails2(SQLHANDLE hdbc,int cid, char *country) +{ + + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* SQL/XML statement to be executed */ + + SQLCHAR *stmt = (SQLCHAR *) "SELECT XMLQUERY('" + " for $customer in db2-fn:xmlcolumn(\"CUSTOMER.INFO\")/customerinfo" + " where ($customer/@Cid > $id) and ($customer/addr/@country !=$c)" + " order by $customer/@Cid" + " return " + " {$customer/name}" + "
{$customer/addr/street}" + " {$customer/addr/city}
'" + " passing by ref cast(? as integer) as \"id\"," + " cast(? as varchar(10)) as \"c\")" + " FROM SYSIBM.SYSDUMMY1"; + + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" %s\n", stmt); + cliRC = SQLPrepare(hstmt,(SQLCHAR *)stmt,SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind the first parameter marker */ + printf("\nBind the first parameter marker with the value %d\n", cid); + SQLBindParameter(hstmt,1,SQL_PARAM_INPUT,SQL_C_LONG,SQL_INTEGER,4,0,&cid,4,NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind the second parameter marker */ + printf("\nBind the second parameter parameter with the value %s", country); + SQLBindParameter(hstmt,2,SQL_PARAM_INPUT,SQL_C_CHAR, SQL_CHAR, 10,0,country,10,NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\nExecute the Statement.....\n\n"); + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 3000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("%s \n\n",xmldata); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* conditionalCustDetails2 */ + +int maxpriceproduct(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* query to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY " + " let $prod := for $product in db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product/description" + " order by fn:number($product/price) descending return $product" + " return {$prod[1]/name} "; + + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* Set the attribute SQL_ATTR_XQUERY_STATEMENT to indicate that the query is an XQuery */ + rc = SQLSetStmtAttr(hstmt, SQL_ATTR_XQUERY_STATEMENT, (SQLPOINTER)SQL_TRUE, SQL_NTS); + printf("%d", rc); + + if (rc != 0) + { + return rc; + } + + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + else + printf("%s \n\n",xmldata); + + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* maxpriceproduct */ + +int basicproduct(SQLHANDLE hdbc,float price) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* SQL/XML statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *) "select xmlquery('" + "for $prod in db2-fn:xmlcolumn(\"PRODUCT.DESCRIPTION\")/product/description" + " order by $prod/name " + " return ( if ($prod/price < $price)" + " then {fn:data($prod/name)}" + " else {fn:data($prod/name)})'" + " passing by ref cast(? as float) as \"price\")" + " from SYSIBM.SYSDUMMY1"; + + + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf(" %s\n", stmt); + cliRC = SQLPrepare(hstmt,(SQLCHAR *)stmt,SQL_NTS); + + /* Bind the parameter marker */ + printf("\nBind the parameter marker with the value %f", price); + SQLBindParameter(hstmt,1,SQL_PARAM_INPUT,SQL_C_FLOAT,SQL_REAL,8,0,&price,8,NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\nExecute the Statement....."); + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("%s \n\n",xmldata); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* Free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* basicproduct */ + diff --git a/xml/xquery/cli/makefile b/xml/xquery/cli/makefile new file mode 100644 index 0000000..26cf834 --- /dev/null +++ b/xml/xquery/cli/makefile @@ -0,0 +1,161 @@ +############################################################################## +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################## +# +# MAKEFILE for CLI XQUERY samples on UNIX +# +# Enter one of the following commands +# +# make - Builds the program designated by +# make all - Builds all supplied sample programs +# make srv - Builds sample that that run on the server +# (stored procedure) +# make all_client - Builds all client samples (all programs in the +# call_rtn and client_run categories) +# make call_rtn - Builds client program that call store procedure +# make client_run - Builds all programs that run completely on the +# client (not one that call stored procedure) +# make clean - Erases intermediate files +# make cleanall - Erases all files produced in the build process +# except the original source files +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +############################################################################## +# 1 -- VARIABLES +############################################################################## + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +BLDAPP=bldapp +BLDRTN=bldrtn + +# To connect to a remote SAMPLE database cataloged on the client machine +# with another name, update the ALIAS variable. +ALIAS=sample +# Set UID and PWD if neccesary +UID= +PWD= + + +COPY=cp +ERASE=rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all (srv + all_client) +# 2b - make srv +# 2c - make all_client (call_rtn + client_run) +# 2d - make call_rtn +# 2e - make client_run +# 2f - make clean +# 2g - make cleanall +############################################################################# + +#**************************************************************************** +# 2a - make all +#**************************************************************************** + +all : \ + srv \ + all_client + +#**************************************************************************** +# 2b - make srv +#**************************************************************************** + +srv : \ + xquery_xmlproc + +#**************************************************************************** +# 2c - make all_client (call_rtn + client_run) +#**************************************************************************** + +all_client : \ + call_rtn \ + client_run + +#**************************************************************************** +# 2d - make call_rtn +#**************************************************************************** + +call_rtn : \ + xquery_xmlproc_client + +#**************************************************************************** +# 2e - make client_run +#**************************************************************************** + +client_run : \ + xpath flwor sqlxquery xquery +#**************************************************************************** +# 2f - make clean +#**************************************************************************** + +clean : + $(ERASE) *.o + $(ERASE) *.DEL *.TXT *.MSG + +#**************************************************************************** +# 2g - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) *.bnd + $(ERASE) xpath flwor sqlxquery xquery xquery_xmlproc_client xquery_xmlproc + $(ERASE) $(DB2PATH)/function/xquery_xmlproc + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - regular samples, embedded SQL +# 3b - client/server samples +############################################################################# + +#**************************************************************************** +# 3a - regular samples, embedded SQL +#**************************************************************************** + +xpath : + $(BLDAPP) xpath $(ALIAS) $(UID) $(PWD) +flwor : + $(BLDAPP) flwor $(ALIAS) $(UID) $(PWD) +sqlxquery : + $(BLDAPP) sqlxquery $(ALIAS) $(UID) $(PWD) +xquery : + $(BLDAPP) xquery $(ALIAS) $(UID) $(PWD) + + +#**************************************************************************** +# 3b - client/server samples +#**************************************************************************** + +xquery_xmlproc_client : + $(BLDAPP) xquery_xmlproc_client $(ALIAS) $(UID) $(PWD) +xquery_xmlproc : + $(BLDRTN) xquery_xmlproc $(ALIAS) + spcat_xquery + diff --git a/xml/xquery/cli/spcat_xquery b/xml/xquery/cli/spcat_xquery new file mode 100644 index 0000000..4c6e0fd --- /dev/null +++ b/xml/xquery/cli/spcat_xquery @@ -0,0 +1,31 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: spcat_xquery +# To catalog CLI stored procedures on UNIX +# Catalogs the stored procedures in the xquery_xmlproc library +# xquery_xmlproc_drop.db2 uncatalogs the stored procedures if previously cataloged +# xquery_xmlproc_create.db2 catologs the stored procedures +# Both CLP scripts can be run on their own +# Usage: spcat_xquery + +db2 -td@ -vf xquery_xmlproc_drop.db2 +db2 -td@ -vf xquery_xmlproc_create.db2 + diff --git a/xml/xquery/cli/sqlxquery.c b/xml/xquery/cli/sqlxquery.c new file mode 100644 index 0000000..15f1773 --- /dev/null +++ b/xml/xquery/cli/sqlxquery.c @@ -0,0 +1,369 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: sqlxquery.c +** +** SAMPLE: How to run SQL/XML Queries +** +** CLI FUNCTIONS USED: +** SQLAllocHandle +** SQLExecDirect +** SQLBindCol +** SQLFetch +** SQLFreeHandle +** SQLPrepare +** SQLBindParameter +** +** SQL/XML FUNCTIONS USED: +** XMLQUERY +** XMLEXISTS +** +** SQL STATEMENT USED: +** SELECT +** +** +** OUTPUT FILE: sqlxquery.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ + +/* The firstPO1 function returns the first item in the purchase order for customer custname passed as an argument*/ +int firstPO1(SQLHANDLE hdbc,char *custname); + +/* The firstPO2 function returns the first item in the purchaseorder when + Name is from the sequence (X,Y,Z) + or the customer id is from the sequence (1000,1002,1003) */ +int firstPO2(SQLHANDLE hdbc); + +/* The sortCust_PO function sort the customers according to the number of purchaseorders */ +int sortCust_PO(SQLHANDLE hdbc); + +/* The numPO function returns the number of purchaseorder having specific partid + for the specific customer passed as an argument to the function*/ +int numPO(SQLHANDLE hdbc,char *name, char *partid); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + SQLINTEGER cid; + SQLINTEGER price; + char custname[20]; + sqlint32 count; + char name[20]; + char partid[20]; + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE DEMONSTRATES HOW THE SQL/XML QUERIES CAN BE RUN USING CLI"); + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + strcpy(custname,"Robert Shoemaker"); + rc=firstPO1(hdbc,custname); + + rc=firstPO2(hdbc); + + rc=sortCust_PO(hdbc); + + strcpy(name,"Robert Shoemaker"); + strcpy(partid,"100-101-01"); + rc=numPO(hdbc,name,partid); +} /* main */ + +int firstPO1(SQLHANDLE hdbc,char *custname) +{ + + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + SQLCHAR *stmt = (SQLCHAR *)"SELECT XMLQUERY('$p/PurchaseOrder/item[1]' PASSING p.porder AS \"p\")" + " FROM purchaseorder AS p, customer AS c" + " WHERE XMLEXISTS('$custinfo/customerinfo[name=$c and @Cid = $cid]'" + " PASSING c.info AS \"custinfo\", p.custid AS \"cid\", cast(? as varchar(20)) as \"c\")"; + + printf("\n SELECT FIRST PURCHASEORDER OF THE A CUSTOMER USING SQL/XML QUERY\n"); + printf("CUSTOMER NAME: %s",custname); + + printf("\n%s\n",stmt); + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + cliRC = SQLPrepare(hstmt,(SQLCHAR *)stmt,SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind the parameter marker */ + printf("\nBind the parameter markers with the value %s", custname); + SQLBindParameter(hstmt,1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,20,0,custname,20,NULL); + + printf("\nExecute the Statement.....\n\n"); + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("%s \n",xmldata); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return 0; +} /* firstPO1 */ + +int firstPO2(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata1[3000]; + SQLVARCHAR xmldata2[3000]; + SQLVARCHAR name[3000]; + sqlint32 cid; + SQLCHAR *stmt=(SQLCHAR *)"SELECT cid, XMLQUERY('$custinfo/customerinfo/name' passing c.info as \"custinfo\")," + "XMLQUERY('$p/PurchaseOrder/item[1]' passing p.porder as \"p\")," + "XMLQUERY('$x/history' passing c.history as \"x\")" + " FROM purchaseorder as p,customer as c" + " WHERE xmlexists('$custinfo/customerinfo[name=(X,Y,Z)" + " or @Cid=(1000,1002,1003) and @Cid=$cid ]'" + " passing c.info as \"custinfo\", p.custid as \"cid\")"; + + printf("\n*******************************************************************************"); + printf("\nUSE THE SQL/XML STATEMENT:\n"); + printf("TO RETURN THE FIRST PURCHASEORDER OF THE CUSTOMERS BASED ON THE FOLLOWING CONDITIONS"); + printf("\n1. Customer name in the sequence (X, Y, Z) or"); + printf("\n2. Customer id in the sequence (1000,1002,1003)"); + printf("\n%s\n",stmt); + + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* Directly execute the statement */ + printf("\n Directly execute the statement\n"); + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_LONG, &cid, 4, NULL); + + /* bind column 2 to variable */ + cliRC = SQLBindCol(hstmt, 2, SQL_C_CHAR, &name, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 3 to variable */ + cliRC = SQLBindCol(hstmt, 3, SQL_C_CHAR, &xmldata1, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 4 to variable */ + cliRC = SQLBindCol(hstmt, 4, SQL_C_CHAR, &xmldata2, 1000, NULL); + + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("cid: %d \n name: %s\n",cid,name); + printf("First PurchaseOrder: %s \n History: %s \n\n",xmldata1,xmldata2); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* firstPO2 */ + +int sortCust_PO(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLINTEGER count; + SQLVARCHAR xmldata[3000]; + SQLCHAR *stmt = (SQLCHAR *)"WITH count_table AS ( SELECT count(poid) as c,custid" + " FROM purchaseorder,customer" + " WHERE cid=custid group by custid )" + " SELECT c, xmlquery('$s/customerinfo[@Cid=$id]/name'" + " passing customer.info as \"s\", count_table.custid as \"id\")" + " FROM customer,count_table" + " WHERE custid=cid ORDER BY c"; + + printf("\n**************************************************"); + printf("\nRETURN ALL THE CUSTOMER NAMES AND SORT THEN ACCORDING TO THE NUMBER OF PURCHASE ORDERS"); + printf("\n%s",stmt); + + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* directly execute the statement */ + printf("\n Directly execute the statement\n"); + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_LONG, &count, 4, NULL); + + /* bind column 2 to variable */ + cliRC = SQLBindCol(hstmt, 2, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\nCount name\n"); + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("%d, %s \n",count,xmldata); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* sortCust_PO */ + +int numPO(SQLHANDLE hdbc,char *name, char *partid) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + int num; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + SQLCHAR *stmt = (SQLCHAR *)"WITH cid_table AS (SELECT Cid FROM customer" + " WHERE XMLEXISTS('$custinfo/customerinfo[name=$name]'" + " PASSING customer.info AS \"custinfo\", cast(? as varchar(20)) as \"name\"))" + " SELECT count(poid) FROM purchaseorder,cid_table" + " WHERE XMLEXISTS('$po/itemlist/item[partid=$id]'" + " PASSING purchaseorder.porder AS \"po\", cast(? as varchar(20)) as \"id\")" + " AND purchaseorder.custid=cid_table.cid"; + + printf("********************************************************\n"); + printf("RETURN THE NUMBER OF PURCHASEORDER FOR CUSTOMER %s WITH THE PARTID %s", name, partid); + printf(" USING SQL/XML QUERY\n"); + printf("\n%s",stmt); + printf("\nCUSTOMER NAME: %s, PART ID: %s",name,partid); + + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + cliRC = SQLPrepare(hstmt,(SQLCHAR *)stmt,SQL_NTS); + + /* Bind first parameter */ + printf("\nBind the first parameter markers with the value %s\n",name); + SQLBindParameter(hstmt,1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,20,0,name,20,NULL); + + /* Bind second parameter */ + printf("\nBind the second parameter markers with the value %s\n" , partid); + SQLBindParameter(hstmt,2,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,20,0,partid,20,NULL); + + printf("\nExecute the Statement....."); + cliRC = SQLExecute(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_LONG, &num, 4, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + else + printf("\nCount : %d \n",num); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return 0; +} /* numPO */ diff --git a/xml/xquery/cli/utilcli.c b/xml/xquery/cli/utilcli.c new file mode 100644 index 0000000..7f7a1ca --- /dev/null +++ b/xml/xquery/cli/utilcli.c @@ -0,0 +1,638 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilcli.c +** +** SAMPLE: Utility functions used by DB2 CLI samples +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLColAttribute -- Return a Column Attribute +** SQLConnect -- Connect to a Data Source +** SQLDescribeCol -- Return a Set of Attributes for a Column +** SQLDisconnect -- Disconnect from a Data Source +** SQLEndTran -- End Transactions of a Connection +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLFreeStmt -- Free (or Reset) a Statement Handle +** SQLGetDiagRec -- Get Multiple Field Settings of Diagnostic Record +** SQLNumResultCols -- Get Number of Result Columns +** SQLSetConnectAttr -- Set Connection Attributes +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilcli.h" + +/* local functions for utilcli.c */ +void HandleLocationPrint(SQLRETURN, int, char *); +void HandleDiagnosticsPrint(SQLSMALLINT, SQLHANDLE); + +/* funtion used in DB2_API_CHECK */ +void SqlInfoPrint(char *, struct sqlca*, int, char*); + +/* outputs to screen unexpected occurrences with CLI functions */ +int HandleInfoPrint(SQLSMALLINT htype, /* handle type identifier */ + SQLHANDLE hndl, /* handle used by the CLI function */ + SQLRETURN cliRC, /* return code of the CLI function */ + int line, + char *file) +{ + int rc = 0; + + switch (cliRC) + { + case SQL_SUCCESS: + rc = 0; + break; + case SQL_INVALID_HANDLE: + printf("\n-CLI INVALID HANDLE-----\n"); + HandleLocationPrint(cliRC, line, file); + rc = 1; + break; + case SQL_ERROR: + printf("\n--CLI ERROR--------------\n"); + HandleLocationPrint(cliRC, line, file); + HandleDiagnosticsPrint(htype, hndl); + rc = 2; + break; + case SQL_SUCCESS_WITH_INFO: + rc = 0; + break; + case SQL_STILL_EXECUTING: + rc = 0; + break; + case SQL_NEED_DATA: + rc = 0; + break; + case SQL_NO_DATA_FOUND: + rc = 0; + break; + default: + printf("\n--default----------------\n"); + HandleLocationPrint(cliRC, line, file); + rc = 3; + break; + } + + return rc; +} /* HandleInfoPrint */ + +void HandleLocationPrint(SQLRETURN cliRC, int line, char *file) +{ + printf(" cliRC = %d\n", cliRC); + printf(" line = %d\n", line); + printf(" file = %s\n", file); +} /* HandleLocationPrint */ + +void HandleDiagnosticsPrint(SQLSMALLINT htype, /* handle type identifier */ + SQLHANDLE hndl /* handle */ ) +{ + SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; + SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER sqlcode; + SQLSMALLINT length, i; + + i = 1; + + /* get multiple field settings of diagnostic record */ + while (SQLGetDiagRec(htype, + hndl, + i, + sqlstate, + &sqlcode, + message, + SQL_MAX_MESSAGE_LENGTH + 1, + &length) == SQL_SUCCESS) + { + printf("\n SQLSTATE = %s\n", sqlstate); + printf(" Native Error Code = %d\n", sqlcode); + printf("%s\n", message); + i++; + } + + printf("-------------------------\n"); +} /* HandleDiagnosticsPrint */ + +/* free statement handles and print unexpected occurrences */ +/* this function is used in STMT_HANDLE_CHECK */ +int StmtResourcesFree(SQLHANDLE hstmt) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + /* free the statement handle */ + cliRC = SQLFreeStmt(hstmt, SQL_UNBIND); + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, cliRC, __LINE__, __FILE__); + if (rc != 0) + { + return 1; + } + + /* free the statement handle */ + cliRC = SQLFreeStmt(hstmt, SQL_RESET_PARAMS); + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, cliRC, __LINE__, __FILE__); + if (rc != 0) + { + return 1; + } + + /* free the statement handle */ + cliRC = SQLFreeStmt(hstmt, SQL_CLOSE); + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, cliRC, __LINE__, __FILE__); + if (rc != 0) + { + return 1; + } + + return 0; +} /* StmtResourcesFree */ + +/* rollback transactions on a single connection */ +/* this function is used in HANDLE_CHECK */ +void TransRollback(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + rc = HandleInfoPrint(SQL_HANDLE_DBC, hdbc, cliRC, __LINE__, __FILE__); + if (rc == 0) + { + printf(" The transaction rolled back.\n"); + } +} /* TransRollback */ + +/* rollback transactions on mutiple connections */ +/* this function is used in HANDLE_CHECK */ +void MultiConnTransRollback(SQLHANDLE henv) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + printf("\n Rolling back the transactions...\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_ENV, henv, SQL_ROLLBACK); + rc = HandleInfoPrint(SQL_HANDLE_ENV, henv, cliRC, __LINE__, __FILE__); + if (rc == 0) + { + printf(" The transactions are rolled back.\n"); + } +} /* MultiConnTransRollback */ + +/* check command line arguments */ +int CmdLineArgsCheck1(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck1 */ + +/* check command line arguments */ +int CmdLineArgsCheck2(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[], + char remoteNodeName[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + strcpy(remoteNodeName, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + strcpy(remoteNodeName, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + strcpy(remoteNodeName, ""); + break; + case 5: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + strcpy(remoteNodeName, argv[4]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd [remoteNodeName]]]\n", + argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck2 */ + +/* check command line arguments */ +int CmdLineArgsCheck3(int argc, + char *argv[], + char dbAlias1[], + char dbAlias2[], + char user1[], + char pswd1[], + char user2[], + char pswd2[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias1, "sample"); + strcpy(dbAlias2, "sample2"); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 3: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 5: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[3]); + strcpy(pswd2, argv[4]); + break; + case 7: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[5]); + strcpy(pswd2, argv[6]); + break; + default: + printf("\nUSAGE: %s " + "[dbAlias1 dbAlias2 [user1 pswd1 [user2 pswd2]]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck3 */ + +/* initialize a CLI application by: + o allocating an environment handle + o allocating a connection handle + o setting AUTOCOMMIT + o connecting to the database */ +int CLIAppInit(char dbAlias[], + char user[], + char pswd[], + SQLHANDLE *pHenv, + SQLHANDLE *pHdbc, + SQLPOINTER autocommitValue) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + /* allocate an environment handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, pHenv); + if (cliRC != SQL_SUCCESS) + { + printf("\n--ERROR while allocating the environment handle.\n"); + printf(" cliRC = %d\n", cliRC); + printf(" line = %d\n", __LINE__); + printf(" file = %s\n", __FILE__); + return 1; + } + + /* set attribute to enable application to run as ODBC 3.0 application */ + cliRC = SQLSetEnvAttr(*pHenv, + SQL_ATTR_ODBC_VERSION, + (void *)SQL_OV_ODBC3, + 0); + ENV_HANDLE_CHECK(*pHenv, cliRC); + + /* allocate a database connection handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_DBC, *pHenv, pHdbc); + ENV_HANDLE_CHECK(*pHenv, cliRC); + + /* set AUTOCOMMIT off or on */ + cliRC = SQLSetConnectAttr(*pHdbc, + SQL_ATTR_AUTOCOMMIT, + autocommitValue, + SQL_NTS); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + + printf("\n Connecting to %s...\n", dbAlias); + + /* connect to the database */ + cliRC = SQLConnect(*pHdbc, + (SQLCHAR *)dbAlias, + SQL_NTS, + (SQLCHAR *)user, + SQL_NTS, + (SQLCHAR *)pswd, + SQL_NTS); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + printf(" Connected to %s.\n", dbAlias); + + return 0; +} /* CLIAppInit */ + +/* terminate a CLI application by: + o disconnecting from the database + o freeing the connection handle + o freeing the environment handle */ +int CLIAppTerm(SQLHANDLE * pHenv, SQLHANDLE * pHdbc, char dbAlias[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + printf("\n Disconnecting from %s...\n", dbAlias); + + /* disconnect from the database */ + cliRC = SQLDisconnect(*pHdbc); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + + printf(" Disconnected from %s.\n", dbAlias); + + /* free connection handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_DBC, *pHdbc); + DBC_HANDLE_CHECK(*pHdbc, cliRC); + + /* free environment handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_ENV, *pHenv); + ENV_HANDLE_CHECK(*pHenv, cliRC); + + return 0; +} /* CLIAppTerm */ + +/* output result sets */ +int StmtResultPrint(SQLHANDLE hstmt, SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + + SQLSMALLINT i; /* index */ + SQLSMALLINT nResultCols; /* variable for SQLNumResultCols */ + SQLCHAR colName[32]; /* variables for SQLDescribeCol */ + SQLSMALLINT colNameLen; + SQLSMALLINT colType; + SQLUINTEGER colSize; + SQLSMALLINT colScale; + SQLINTEGER colDataDisplaySize; /* maximum size of the data */ + SQLINTEGER colDisplaySize[MAX_COLUMNS]; /* maximum size of the column */ + + struct + { + SQLCHAR *buff; + SQLINTEGER len; + SQLINTEGER buffLen; + } + outData[MAX_COLUMNS]; /* variable to read the results */ + + /* identify the output columns */ + cliRC = SQLNumResultCols(hstmt, &nResultCols); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + printf("\n"); + for (i = 0; i < nResultCols; i++) + { + + /* return a set of attributes for a column */ + cliRC = SQLDescribeCol(hstmt, + (SQLSMALLINT)(i + 1), + colName, + sizeof(colName), + &colNameLen, + &colType, + &colSize, + &colScale, + NULL); + + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* get display size for column */ + cliRC = SQLColAttribute(hstmt, + (SQLSMALLINT)(i + 1), + SQL_DESC_DISPLAY_SIZE, + NULL, + 0, + NULL, + &colDataDisplaySize); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* set "column display size" to max of "column data display size", + and "column name length", plus at least one space between columns */ + colDisplaySize[i] = max(colDataDisplaySize, colNameLen) + 1; + + /* print the column name */ + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], colName); + + /* set "output data buffer length" to "column data display size" + plus one byte for the null terminator */ + outData[i].buffLen = colDataDisplaySize + 1; + + /* allocate memory to bind column */ + outData[i].buff = (SQLCHAR *)malloc((int)outData[i].buffLen); + + /* bind columns to program variables, converting all types to CHAR */ + cliRC = SQLBindCol(hstmt, + (SQLSMALLINT)(i + 1), + SQL_C_CHAR, + outData[i].buff, + outData[i].buffLen, + &outData[i].len); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + printf("\n"); + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + + while (cliRC == SQL_SUCCESS || cliRC == SQL_SUCCESS_WITH_INFO) + { + for (i = 0; i < nResultCols; i++) + { + /* check for NULL data */ + if (outData[i].len == SQL_NULL_DATA) + { + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], "NULL"); + } + else + { + /* print outData for this column */ + printf("%-*.*s", + (int)colDisplaySize[i], + (int)colDisplaySize[i], outData[i].buff); + } + } /* for all columns in this row */ + + printf("\n"); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } /* while rows to fetch */ + + /* free data buffers */ + for (i = 0; i < nResultCols; i++) + { + free(outData[i].buff); + } + + return rc; +} /* StmtResultPrint */ + +/* prints the warning/error details including file name, line number, + sqlcode and SQLSTATE. */ +void SqlInfoPrint(char *appMsg, struct sqlca *pSqlca, int line, char *file) +{ + int rc = 0; + char sqlInfo[1024]; /* string to store all the error information */ + char sqlInfoToken[1024]; /* string to store tokens of information */ + char sqlstateMsg[1024]; /* string to store SQLSTATE message*/ + char errorMsg[1024]; /* string to store error message */ + + if (pSqlca->sqlcode != 0 && pSqlca->sqlcode != 100) + { + strcpy(sqlInfo, ""); + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "\n---- error report -----------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } + else + { + sprintf(sqlInfoToken, + "\n---- warning report ---------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + } /* endif */ + + sprintf(sqlInfoToken, "\napplication message = %s\n", appMsg); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "line = %d\n", line); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "file = %s\n", file); + strcat(sqlInfo, sqlInfoToken); + sprintf(sqlInfoToken, "SQLCODE = %d\n\n", pSqlca->sqlcode); + strcat(sqlInfo, sqlInfoToken); + + /* get error message */ + rc = sqlaintp(errorMsg, 1024, 80, pSqlca); + if (rc > 0) /* return code is the length of the errorMsg string */ + { + sprintf(sqlInfoToken, "%s\n", errorMsg); + strcat(sqlInfo, sqlInfoToken); + } + + /* get SQLSTATE message */ + rc = sqlogstt(sqlstateMsg, 1024, 80, pSqlca->sqlstate); + if (rc > 0) + { + sprintf(sqlInfoToken, "%s\n", sqlstateMsg); + strcat(sqlInfo, sqlInfoToken); + } + + if (pSqlca->sqlcode < 0) + { + sprintf(sqlInfoToken, + "---- end error report ------------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } + else + { + sprintf(sqlInfoToken, + "---- end warning report ----------------------\n"); + strcat(sqlInfo, sqlInfoToken); + printf("%s", sqlInfo); + } /* endif */ + } /* endif */ +} /* SqlInfoPrint */ diff --git a/xml/xquery/cli/utilcli.h b/xml/xquery/cli/utilcli.h new file mode 100644 index 0000000..842026f --- /dev/null +++ b/xml/xquery/cli/utilcli.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilcli.h +** +** SAMPLE: Declaration of utility functions used by DB2 CLI samples +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILCLI_H +#define UTILCLI_H + +#define MAX_UID_LENGTH 18 +#define MAX_PWD_LENGTH 30 +#define MAX_STMT_LEN 255 +#define MAX_COLUMNS 255 +#ifdef DB2WIN +#define MAX_TABLES 50 +#else +#define MAX_TABLES 255 +#endif + +#ifndef max +#define max(a,b) (a > b ? a : b) +#endif + +/* macro for environment handle checking */ +#define ENV_HANDLE_CHECK(henv, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_ENV, henv, \ + cliRC, __LINE__, __FILE__); \ + if (rc != 0) return rc; \ +} + +/* macro for connection handle checking */ +#define DBC_HANDLE_CHECK(hdbc, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_DBC, hdbc, \ + cliRC, __LINE__, __FILE__); \ + if (rc != 0) return rc; \ +} + +/* macro for statement handle checking */ +#define STMT_HANDLE_CHECK(hstmt, hdbc, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, \ + cliRC, __LINE__, __FILE__); \ + if (rc == 2) StmtResourcesFree(hstmt); \ + if (rc != 0) TransRollback(hdbc); \ + if (rc != 0) return rc; \ +} + +/* macro for statement handle checking in + applications with multiple connections */ +#define MC_STMT_HANDLE_CHECK(hstmt, henv, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, \ + cliRC, __LINE__, __FILE__); \ + if (rc == 2) StmtResourcesFree(hstmt); \ + if (rc != 0) MultiConnTransRollback(henv); \ + if (rc != 0) return rc; \ +} + +/* macro for DB2_API checking */ +#define DB2_API_CHECK(MSG_STR) \ +SqlInfoPrint(MSG_STR, &sqlca, __LINE__, __FILE__); \ +if (sqlca.sqlcode < 0) \ +{ \ + return 1; \ +} + +/* macro for expected error checking checking */ +#define EX_STMT_HANDLE_CHECK(hstmt, hdbc, cliRC) \ +if (cliRC != SQL_SUCCESS) \ +{ \ + rc = HandleInfoPrint(SQL_HANDLE_STMT, hstmt, \ + cliRC, __LINE__, __FILE__); \ + if (rc == 2) StmtResourcesFree(hstmt); \ +} + +/* functions used in ...CHECK_HANDLE macros */ +int HandleInfoPrint(SQLSMALLINT, SQLHANDLE, SQLRETURN, int, char *); +void CLIAppCleanUp(SQLHANDLE *, SQLHANDLE a_hdbc[], int); +int StmtResourcesFree(SQLHANDLE); +void TransRollback(SQLHANDLE); +void MultiConnTransRollback(SQLHANDLE); + +/* functions to check the number of command line arguments */ +int CmdLineArgsCheck1(int, char *argv[], char *, char *, char *); +int CmdLineArgsCheck2(int, char *argv[], char *, char *, char *, char *); +int CmdLineArgsCheck3(int, char *argv[], char *, char *, + char *, char *, char *, char *); + +/* function used in DB2_API_CHECK */ +void SqlInfoPrint(char *, struct sqlca*, int, char*); + +/* other utility functions */ +int CLIAppInit(char *, char *, char *, SQLHANDLE *, SQLHANDLE *, SQLPOINTER); +int CLIAppTerm(SQLHANDLE *, SQLHANDLE *, char *); +int StmtResultPrint(SQLHANDLE, SQLHANDLE); + +#endif + diff --git a/xml/xquery/cli/xpath.c b/xml/xquery/cli/xpath.c new file mode 100644 index 0000000..1c1a9c8 --- /dev/null +++ b/xml/xquery/cli/xpath.c @@ -0,0 +1,430 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xpath.c +** +** SAMPLE: How to run queries with a simple path expression +** +** CLI FUNCTIONS USED: +** SQLAllocHandle +** SQLExecDirect +** SQLBindCol +** SQLFetch +** SQLFreeHandle +** +** SQL/XML FUNCTIONS USED: +** xmlcolumn +** +** XQuery functions used: +** distinct-values +** starts-with +** avg +** count +** +** OUTPUT FILE: xpath.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For information on using XQuery statements, see the XQuery Reference +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ + +/* Functions used in the samples */ +/* The CustomerDetails method returns all of the XML data in the INFO column of the CUSTOMER table */ +int CustomerDetails(SQLHANDLE hdbc); + +/* The CustomerFromToronto method returns information about customers from Toronto */ +int CustomerFromToronto(SQLHANDLE hdbc); + +/* The CitiesInCanada method returns a list of cities that are in Canada */ +int CitiesInCanada(SQLHANDLE hdbc); + +/* The CustMobileNum method returns the names of customers whose mobile number starts with 905 */ +int CustMobileNum(SQLHANDLE hdbc); + +/* The AvgPRice method determines the average prive of the products in the 100 series */ +int AvgPrice(SQLHANDLE hdbc); + +/* The NumOfCustInToronto method returns the number of customer from Toronto city */ +int NumOfCustInToronto( SQLHANDLE hdbc); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE DEMONSTRATES HOW THE QUERIES WITH SIMPLE PATH EXPRESSION CAN BE RUN USING CLI"); + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + printf("**********************************\n"); + printf("Select the customer details....."); + rc=CustomerDetails(hdbc); + + printf("**********************************\n"); + printf("Select the customer's cities from Canada .....\n"); + rc=CitiesInCanada(hdbc); + + printf("**********************************\n"); + printf("Select the Average price for all the product in 100 series.....\n"); + rc=AvgPrice(hdbc); + + printf("*********************************\n"); + printf("Select the customer details from Toronto city.......\n"); + rc=CustomerFromToronto(hdbc); + + printf("*********************************\n"); + printf("Select the number of customer from Toronto city.......\n"); + rc= NumOfCustInToronto(hdbc); + + printf("*********************************\n"); + printf("Select the name of the customer with mobile number start from 905.......\n"); + rc=CustMobileNum(hdbc); +} /* main */ + + +/* This function will find out the customer details from CUSTOMER.INFO column */ +int CustomerDetails(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* XPATH statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY " + " for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo " + " order by $cust/@Cid " + " return $cust "; + /* Allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("----------------------------------------------------------------------------\n"); + printf("%s \n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* Free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* CustomerDetails */ + +/* This function will find out the customer's cities from Toronto */ +int CitiesInCanada(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* XPATH statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY for $cty in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/addr[@country=\"Canada\"]/city)" + " order by $cty" + " return $cty"; + /* Allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("%s \n\n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* CitiesInCanada */ + +/* This function will find out the average price of all the product in 100 series */ +int AvgPrice(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[1000]; + + /* XPATH statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY let $prod_price := db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')" + "/product[fn:starts-with(@pid,\"100\")]/description/price" + " return avg($prod_price)"; + + /* Allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + else + printf("%s \n\n",xmldata); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* AvgPrice */ + +/* This function will find out the customer details from Toronto city */ +int CustomerFromToronto(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* XPATH statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY for $cust in db2-fn:xmlcolumn (\"CUSTOMER.INFO\")/customerinfo[addr/city=\"Toronto\"]" + " order by $cust/@Cid" + " return $cust"; + + /* Allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("%s \n\n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* Free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* CustomerFromToronto */ + +int NumOfCustInToronto(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* XPATH statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY fn:count(db2-fn:xmlcolumn(\"CUSTOMER.INFO\") " + " /customerinfo[addr/city=\"Toronto\"])"; + + /* Allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + else + printf("%s \n\n",xmldata); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* NumOfCustInToronto */ + +/* This function will find out the customer names with mobile number start with 905 */ +int CustMobileNum(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* XPATH statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY db2-fn:xmlcolumn(\"CUSTOMER.INFO\")" + "/customerinfo[phone[@type=\"cell\" and fn:starts-with(text(),\"905\")]]"; + /* Allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* Directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* Fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + printf("%s \n\n",xmldata); + + /* fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + return rc; +} /* CustMobileNum */ diff --git a/xml/xquery/cli/xquery.c b/xml/xquery/cli/xquery.c new file mode 100644 index 0000000..e7d6976 --- /dev/null +++ b/xml/xquery/cli/xquery.c @@ -0,0 +1,480 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xquery.c +** +** SAMPLE: How to run a nested XQuery and shows how to pass parameters to +** sqlquery function. +** +** CLI FUNCTIONS USED: +** SQLAllocHandle +** SQLExecDirect +** SQLBindCol +** SQLFetch +** SQLFreeHandle +** +** SQL/XML FUNCTIONS USED: +** xmlcolumn +** sqlquery +** +** XQUERY EXPRESSION USED +** FLWOR Expression +** +** +** OUTPUT FILE: xquery.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using XQuery statements, see the XQuery Reference +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilcli.h" /* Header file for CLI sample code */ + +/* Functions used in the sample */ + +/* The PO_orderbycity function restructures the purchaseorders according to the city. */ +int PO_orderbycity(SQLHANDLE hdbc); + +/* The Customer_orderbyproduct restructures the purchaseorder according to the product */ +int Customer_orderbyproduct(SQLHANDLE hdbc); + +/* The PO_orderbyProvCityStreet function restructures the purchaseorder data according to provience, city and street */ +int PO_orderbyProvCityStreet(SQLHANDLE hdbc); + +/* This CustomerPO function combines the data from customer and product table to create a purchaseorder*/ +int CustomerPO(SQLHANDLE hdbc); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + char id[10]; + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE DEMONSTRATES HOW THE NESTED XQUERIES CAN BE RUN USING CLI"); + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + (SQLPOINTER)SQL_AUTOCOMMIT_ON); + if (rc != 0) + { + return rc; + } + printf("-------------------------------------------------------------\n"); + printf("RESTRUCTURE THE PURCHASEORDERS ACCORDING TO THE CITY....\n"); + rc=PO_orderbycity(hdbc); + + printf("-------------------------------------------------------------\n"); + printf("RESTRUCTURE THE PURCHASEORDER ACCORDING TO THE PRODUCT.....\n"); + rc=Customer_orderbyproduct(hdbc); + + printf("-------------------------------------------------------------\n"); + printf("RESTRUCTURE THE PURCHASEORDER DATA ACCORDING TO PROVIENCE, CITY AND STREET..\n"); + rc=PO_orderbyProvCityStreet(hdbc); + + printf("-------------------------------------------------------------\n"); + printf("COMBINE THE DATA FROM PRODUCT AND CUSTOMER TABLE TO CREATE A PURCHASEORDER..\n"); + rc=CustomerPO(hdbc); +} /* main */ + +int Customer_orderbyproduct(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[5000]; + + /* XQUERY statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"pos\"\"," + + "( XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", c.custid)," + "XMLELEMENT(NAME \"\"order\"\", c.porder)" + " ) ))" + " FROM purchaseorder AS c\" )" + " for $partid in fn:distinct-values(db2-fn:xmlcolumn('PURCHASEORDER.PORDER')/PurchaseOrder/item/partid)" + " order by $partid" + " return" + " " + " " + " {" + " for $id in fn:distinct-values($po[order/PurchaseOrder/item/partid=$partid]/custid)" + " let $order:=" + " {fn:sum($po[custid=$id]/order/PurchaseOrder/item[partid=$partid]/quantity)}" + " ," + " $cust:=db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[@Cid=$id]" + " order by $id" + " return" + " " + " {$order}" + " {$cust}" + " " + " }" + " " + ""; + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n\n", stmt); + + /* directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 2000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch each row and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("%s \n\n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* Customer_orderbyproduct */ + +int PO_orderbycity(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt, hstmt1; /* statement handles */ + SQLVARCHAR xmldata[3000]; + + /* XQUERY statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY " + " for $city in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/addr/city)" + " order by $city" + " return" + " " + "{" + " for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[addr/city=$city]" + " let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"pos\"\"," + " (XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", c.custid)," + "XMLELEMENT(NAME \"\"order\"\", c.porder)" + " ) ))" + " FROM purchaseorder AS c\")" + " let $id:=$cust/@Cid," + " $order:=$po/pos[custid=$id]/order" + " order by $cust/@Cid" + " return" + " " + " {$cust/name}" + " {$cust/addr}" + " {$order}" + " }" + " "; + + SQLCHAR *stmt1 = (SQLCHAR *)"XQUERY " + "for $city in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO') /customerinfo/addr/city)" + " order by $city " + "return" + "" + "{" + "for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo [addr/city=$city]" + "let $po:=db2-fn:sqlquery(\"SELECT porder FROM PURCHASEORDER WHERE custid=parameter(1)\",$cust/@Cid)," + " $order:=$po/order" + " order by $cust/@Cid" + " return" + " " + " {$cust/name}" + " {$cust/Addr}" + " {$order}" + " }" + " "; + + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n\n", stmt); + + /* directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 2000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch the result and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("%s \n\n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + } + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt1); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n\nThe following query shows how to pass parameters to"); + printf(" sqlquery function which is an enhancement in Viper2"); + printf("\n--------------------------------------------------"); + printf("\n Directly execute the statement\n"); + printf(" %s\n\n", stmt1); + + cliRC = SQLExecDirect(hstmt1, stmt1, SQL_NTS); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt1, 1, SQL_C_CHAR, &xmldata, 1000, NULL); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + /* fetch the result and display */ + cliRC = SQLFetch(hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + while (cliRC != SQL_NO_DATA_FOUND) + { + /* Print the data */ + printf("%s \n\n",xmldata); + + /* Fetch next row */ + cliRC = SQLFetch(hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + } + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt1); + STMT_HANDLE_CHECK(hstmt1, hdbc, cliRC); + + return rc; + +} /* PO_orderbycity */ + +int PO_orderbyProvCityStreet(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[5000]; + + /* XQUERY statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY " + " let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"pos\"\"," + "( XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", c.custid)," + "XMLELEMENT(NAME \"\"order\"\", c.porder)" + ") ))" + " FROM PURCHASEORDER as c ORDER BY poid\")," + " $addr:=db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/addr" + " for $prov in distinct-values($addr/prov-state)" + " return" + " " + " {" + " for $city in fn:distinct-values($addr[prov-state=$prov]/city)" + " order by $city" + " return" + " " + " {" + " for $s in fn:distinct-values($addr/street) where $addr/city=$city" + " order by $s" + " return" + " " + " {" + " for $info in $addr[prov-state=$prov and city=$city and street=$s]/.." + " order by $info/@Cid" + " return" + " " + " {$info/name}" + " {" + " let $id:=$info/@Cid, $order:=$po[custid=$id]/order" + " return $order" + " }" + " " + " }" + " " + " }" + " " + " }" + " "; + + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n\n", stmt); + + /* directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 5000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch the result and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + printf("%s \n\n",xmldata); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* PO_orderbyProvCityStreet */ + + +int CustomerPO(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE hstmt; /* statement handle */ + SQLVARCHAR xmldata[3000]; + + /* XQUERY statement to be executed */ + SQLCHAR *stmt = (SQLCHAR *)"XQUERY " + "" + "{" + " for $ns1_customerinfo0 in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo" + " where ($ns1_customerinfo0/@Cid=1001)" + " return" + " " + " {$ns1_customerinfo0/name}" + "
" + " {$ns1_customerinfo0/addr/street}" + " {$ns1_customerinfo0/addr/city}" + " {" + " if($ns1_customerinfo0/addr/@country=\"US\")" + " then" + " $ns1_customerinfo0/addr/prov-state" + " else()" + " }" + " {" + " fn:concat ($ns1_customerinfo0/addr/pcode-zip/text(),\",\",fn:upper-case($ns1_customerinfo0/addr/@country))}" + "
" + "
" + " }" + " {" + " for $ns2_product0 in db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product" + " where ($ns2_product0/@pid=\"100-100-01\")" + " return" + " $ns2_product0" + " }" + "
"; + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n\n", stmt); + + /* directly execute the statement */ + cliRC = SQLExecDirect(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind column 1 to variable */ + cliRC = SQLBindCol(hstmt, 1, SQL_C_CHAR, &xmldata, 3000, NULL); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* fetch the result and display */ + cliRC = SQLFetch(hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + if (cliRC == SQL_NO_DATA_FOUND) + { + printf("\n Data not found.\n"); + } + printf("%s \n\n",xmldata); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; + +} /* CustomerPO */ + + diff --git a/xml/xquery/cli/xquery_xmlproc.c b/xml/xquery/cli/xquery_xmlproc.c new file mode 100644 index 0000000..d5569cb --- /dev/null +++ b/xml/xquery/cli/xquery_xmlproc.c @@ -0,0 +1,859 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xquery_xmlproc.c +** +** SAMPLE: Code implementation of Supp_XML_Proc_CLI stored procedure +** +** The stored procedure defined in this program is called by the +** client application xquery_xmlproc_client.c. Before building and running +** xquery_xmlproc_client.c, build the shared library by completing the +** following steps: +** +** BUILDING THE SHARED LIBRARY: +** 1. Ensure the Database Manager Configuration file has the keyword +** KEEPFENCED set to "no". This allows shared libraries to be unloaded +** while you are developing stored procedures. You can view the file's +** settings by issuing the command: "db2 get dbm cfg". You can set +** KEEPFENCED to "no" with this command: "db2 update dbm cfg using +** KEEPFENCED no". NOTE: Setting KEEPFENCED to "no" reduces performance +** the performance of accessing stored procedures, because they have +** to be reloaded into memory each time they are called. If this is a +** concern, set KEEPFENCED to "yes", stop and then restart DB2 before +** building the shared library, by entering "db2stop" followed by +** "db2start". This forces DB2 to unload shared libraries and enables +** the build file or the makefile to delete a previous version of the +** shared library from the "sqllib/function" directory. +** 2. To build the shared library, enter "bldrtn xquery_xmlproc", or use the +** makefile: "make xquery_xmlproc"(UNIX) or "nmake xquery_xmlproc"(Windows). +** +** CATALOGING THE STORED PROCEDURES +** 1. The stored procedures are cataloged automatically when you build +** the client application "xquery_xmlproc_client" using the appropriate +** "make" utility for your Operating System and the "makefile" provided with +** these samples. If you wish to catalog or recatalog them manually, enter +** "spcat_xquery". The spcat_xquery script (UNIX) or spcat_xquery.bat batch +** file (Windows) connects to the database, runs xquery_xmlproc_drop.db2 to +** uncatalog the stored procedures if they were previously cataloged, then +** runs xquery_xmlproc_create.db2 which catalogs the stored procedures, +** then disconnects from the database. +** +** CALLING THE STORED PROCEDURES IN THE SHARED LIBRARY: +** 1. Compile the xquery_xmlproc_client program with "bldapp xquery_xmlproc_client" +** or use the makefile: "make xquery_xmlproc_client" (UNIX) or +** "nmake xquery_xmlproc_client" (Windows). +** 2. Run xquery_xmlproc_client: "xquery_xmlproc_client" (if calling remotely add +** the parameters for database, user ID and password.) +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLBindParameter -- Bind a Parameter Marker to a Buffer or +** LOB locator +** SQLConnect -- Connect to a Data Source +** SQLDisconnect -- Disconnect from a Data Source +** SQLExecDirect -- Execute a Statement Directly +** SQLExecute -- Execute a Statement +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLPrepare -- Prepare a Statement +** SQLSetConnectAttr -- Set Connection Attributes +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilcli.h" + +/* macros for handle checking */ +#define SRV_HANDLE_CHECK(htype, hndl, CLIrc, henv, hdbc) \ +if (CLIrc == SQL_INVALID_HANDLE) \ +{ \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} \ +if (CLIrc == SQL_ERROR) \ +{ \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} + +#define \ +SRV_HANDLE_CHECK_SETTING_SQLST(htype, hndl, CLIrc, henv, hdbc, sqlstate) \ +if (CLIrc == SQL_INVALID_HANDLE) \ +{ \ + memset(sqlstate, '0', 6); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} \ +if (CLIrc == SQL_ERROR) \ +{ \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} + +#define \ +SRV_HANDLE_CHECK_SETTING_SQLRC_AND_MSG(htype, \ + hndl, \ + CLIrc, \ + henv, \ + hdbc, \ + outReturnCode, \ + outErrorMsg, \ + inMsg) \ +if (CLIrc == SQL_INVALID_HANDLE) \ +{ \ + *outReturnCode = 0; \ + strcpy(outErrorMsg, inMsg); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} \ +if (CLIrc == SQL_ERROR) \ +{ \ + *outReturnCode = -1; \ + strcat(outErrorMsg, inMsg); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} + +#define \ +SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(htype, \ + hndl, \ + CLIrc, \ + henv, \ + hdbc, \ + sqlstate, \ + outMsg, \ + inMsg) \ +if (CLIrc == SQL_INVALID_HANDLE) \ +{ \ + memset(sqlstate, '0', 6); \ + strcpy(outMsg, inMsg); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} \ +if (CLIrc != 0 && CLIrc != SQL_NO_DATA_FOUND ) \ +{ \ + SetErrorMsg(htype, hndl, henv, hdbc, outMsg, inMsg); \ + StpCleanUp(henv, hdbc); \ + return (0); \ +} + +void StpCleanUp(SQLHANDLE henv, SQLHANDLE hdbc) +{ + /* disconnect from a data source */ + SQLDisconnect(hdbc); + + /* free the database handle */ + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + + /* free the environment handle */ + SQLFreeHandle(SQL_HANDLE_ENV, henv); +} + +void SetErrorMsg(SQLSMALLINT htype, + SQLHANDLE hndl, + SQLHANDLE henv, + SQLHANDLE hdbc, + char *outMsg, + char *inMsg) +{ + SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; + SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER sqlcode; + SQLSMALLINT length; + SQLGetDiagRec(htype, + hndl, + 1, + sqlstate, + &sqlcode, + message, + SQL_MAX_MESSAGE_LENGTH + 1, + &length); + sprintf(outMsg, "%ld: ", sqlcode); + strcat(outMsg, inMsg); +} + +/************************************************************************** +** Stored procedure: xquery_proc +** +** Scenario: +** Some of the suppliers have extended the promotional price date for +** their products. Getting all the customer's Information who purchased +** these products in the extended period will help the financial department +** to return the excess amount paid by those customers. The supplier +** information along with extended date's for the products is provided +** in an XML document and the customer wants to have the information +** of all the customers who has paid the excess amount by purchasing those +** products in the extended period. +** +** This procedure will return an XML document containing customer info +** along with the the excess amount paid by them. +** +** Shows how to: +** - define XML type parameters in a Stored Procedure +** +** Parameters: +** +** IN: inXML - Products information with extended promodate as +** an XML document +** OUT: outXML - Customers information with excess amount to be paid +** to them as an XML document +** +** When the PARAMETER STYLE SQL clause is specified +** in the CREATE PROCEDURE statement for the procedure +** (see the script xquery_xmlproc_create.db2), in addition to the +** parameters passed at procedure invocation time, the +** following parameters are passed to the routine +** in the following order: +** - one null indicator for each IN/INOUT/OUT parameter +** is specified in the same order as the corresponding +** parameter declarations. +** - sqlstate: to be returned to the caller to indicate +** state (output) +** - routine-name: qualified name of the routine (input) +** - specific-name: the specific name of the routine (input) +** - diagnostic-message: an optional text string returned to the +** caller (output) +** See the actual parameter declarations below to see +** the recommended datatypes and sizes for them. +** +** CODE TIP: +** -------- +** As an alternative to coding the non-functional parameters +** required with parameter style SQL (sqlstate, routine-name, +** specific-name, diagnostic-message), you can use a macro: +** SQLUDF_TRAIL_ARGS. This macro is defined in DB2 include +** file sqludf.h +** +**************************************************************************/ + +SQL_API_RC SQL_API_FN xquery_proc ( SQLUDF_CLOB* inXML, + SQLUDF_CLOB* outXML, + sqlint16 *inXML_ind, + sqlint16 *outXML_ind, + char sqlstate[6], + char qualName[28], + char specName[19], + char diagMsg[71]) +{ + SQLHANDLE henv; + SQLHANDLE hdbc = 0; + SQLHANDLE hstmt,hstmt1,hstmt2,hstmt3,hstmt4,hstmt5; + SQLRETURN cliRC; + SQLCHAR stmt1[1000],stmt2[1000],stmt3[1000],stmt4[1000]; + SQLCHAR stmt5[1000],stmt6[1000],stmt7[1000],stmt8[1000]; + SQLCHAR prodid[12],partid[12]; + SQLREAL originalPrice,promoPrice,excessamount; + SQLCHAR oldPromoDate[11],newPromoDate[11]; + SQLBIGINT custid; + SQLINTEGER quantity; + + /* Initialize output parameters to NULL*/ + memset(outXML->data,'\0',5000); + *outXML_ind=-1; + + /* Initialize the application variables */ + originalPrice=0; + promoPrice =0; + excessamount =0; + custid=0; + quantity=0; + memset(partid, '\0', 12); + memset(prodid, '\0', 12); + memset(oldPromoDate, '\0', 11); + memset(newPromoDate, '\0', 11); + + /* allocate the environment handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + SRV_HANDLE_CHECK(SQL_HANDLE_ENV, henv, cliRC, henv, hdbc); + + /* allocate the database handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); + SRV_HANDLE_CHECK(SQL_HANDLE_ENV, henv, cliRC, henv, hdbc); + + /* set AUTOCOMMIT off */ + cliRC = SQLSetConnectAttr(hdbc, + SQL_ATTR_AUTOCOMMIT, + SQL_AUTOCOMMIT_OFF, + SQL_NTS); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* issue NULL Connect, because in CLI a statement handle is + required and thus a connection handle and environment handle. + A connection is not established; rather the current + connection from the calling application is used. */ + + /* connect to a data source */ + cliRC = SQLConnect(hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle for hstmt */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle for hstmt1 */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt1); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle for hstmt3 */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt3); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle for hstmt4 */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt4); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* allocate the statement handle for hstmt5 */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt5); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* create the table temp_table1 for storing intermediate results */ + strcpy((char *)stmt1,"CREATE TABLE temp_table1(custid INT,partid VARCHAR(12)," + "excessamount DECIMAL(5,2))"); + cliRC = SQLExecDirect(hstmt, stmt1, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "CREATE statement(temp_table1) failed."); + + /* create the table temp_table2 */ + strcpy((char *)stmt2,"CREATE TABLE temp_table2(cid INT,total DECIMAL(5,2))"); + cliRC = SQLExecDirect(hstmt, stmt2, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "CREATE statement(temp_table2) failed."); + /* an XQUERY statement to restructure all the PurchaseOrders + into the following form + + + XXXX + XXX-XXX-XX + XX + ............................... + ................. + store the above XML document in an application variable "orders" */ + sprintf((char *) stmt3,"XQUERY let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"porders\"\"," + "( XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", p.custid), p.porder))) " + "FROM PURCHASEORDER as p\") return {for $i in $po for $j in " + "$po[custid=$i/custid]/PurchaseOrder[@PoNum=$i/PurchaseOrder/@PoNum]/item " + "return {$i/PurchaseOrder/@OrderDate}{$i/custid}{$j/partid}" + "{$j/quantity}}"); + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt3, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "Prepare statement failed."); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "XQUERY statement failed."); + /* bind column to a variable*/ + cliRC = SQLBindCol(hstmt, + 1, + SQL_C_CHAR, + &(outXML->data), + 5000, + (SQLINTEGER*)&(outXML->length)); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + /* fetch the data */ + cliRC = SQLFetch(hstmt); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + + /* select the oldpromodate, newpromodate, price and promoprice + for the products for which the promodate is extended + using input XML document */ + strcpy((char *)stmt4, "SELECT Pid,PromoEnd,Price,PromoPrice,XMLCAST(XMLQUERY(" + "'$info/Suppliers/Supplier/Products/Product[@id=$pid]/ExtendedDate' " + "passing cast(? as XML) as \"info\", pid as \"pid\") as DATE) FROM " + "product WHERE XMLEXISTS('for $prod in $info//Product[@id=$pid] return" + " $prod' passing by ref cast(? as XML) as \"info\", pid as \"pid\")"); + /* prepare the statement */ + cliRC = SQLPrepare(hstmt1, stmt4, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "Prepare statement failed."); + cliRC = SQLBindParameter(hstmt1, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(inXML->data), + inXML->length, + (SQLINTEGER *)&(inXML->length)); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter1"); + cliRC = SQLBindParameter(hstmt1, + 2, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(inXML->data), + inXML->length, + (SQLINTEGER *)&(inXML->length)); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter2"); + /* execute the statement */ + cliRC = SQLExecute(hstmt1); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement failed."); + cliRC = SQLBindCol(hstmt1, 1, SQL_C_CHAR, prodid, 12, NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindCol"); + cliRC = SQLBindCol(hstmt1, 2, SQL_C_CHAR, oldPromoDate, 11, NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindCol"); + cliRC = SQLBindCol(hstmt1, 3, SQL_C_FLOAT, &originalPrice, 0, NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindCol"); + cliRC = SQLBindCol(hstmt1, 4, SQL_C_FLOAT, &promoPrice , 0, NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindCol"); + cliRC = SQLBindCol(hstmt1, 5, SQL_C_CHAR, newPromoDate, 11, NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt1, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindCol"); + /* fetch a row */ + cliRC = SQLFetch(hstmt1); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt1, cliRC, henv, hdbc); + while (cliRC != SQL_NO_DATA_FOUND) + { + /* finding out the toatal quantity of the product purchased by a customer + if that order is made in between oldpromodate and extended promodate. + this query will return the custid, product id and total quantity of + that product purchased in all his orders. */ + + strcpy( (char *)stmt5,"WITH temp1 AS (SELECT cid,partid,quantity,orderdate " + "FROM XMLTABLE('$od//item' passing cast(? as XML) as \"od\" COLUMNS cid BIGINT path " + "'./custid', partid VARCHAR(20) path './partid', orderdate DATE path" + "'./@OrderDate',quantity BIGINT path './quantity') as temp2) " + "SELECT temp1.cid, temp1.partid, sum(temp1.quantity) as quantity " + "FROM temp1 WHERE partid=? and orderdate>cast(? as DATE) and orderdatedata), + outXML->length, + (SQLINTEGER *)&(outXML->length)); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt2, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter1"); + cliRC = SQLBindParameter(hstmt2, 2, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_CHAR, + 12, + 0, + prodid, + 12, + NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt2, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter2"); + cliRC = SQLBindParameter(hstmt2, 3, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_CHAR, + 11, + 0, + oldPromoDate, + 11, + NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt2, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter3"); + cliRC = SQLBindParameter(hstmt2,4, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_CHAR, + 11, + 0, + newPromoDate, + 11, + NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt2, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter4"); + /* execute the statement */ + cliRC = SQLExecute(hstmt2); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt2, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement failed."); + /* bind columns */ + cliRC = SQLBindCol(hstmt2, 1, SQL_C_SBIGINT, &custid, 0, NULL); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt2, cliRC, henv, hdbc); + cliRC = SQLBindCol(hstmt2, 2, SQL_C_CHAR, partid, 12, NULL); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt2, cliRC, henv, hdbc); + cliRC = SQLBindCol(hstmt2, 3, SQL_C_LONG, &quantity, 0, NULL); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt2, cliRC, henv, hdbc); + /* fetch a row */ + cliRC = SQLFetch(hstmt2); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt2, cliRC, henv, hdbc); + + while (cliRC != SQL_NO_DATA_FOUND) + { + excessamount = ((originalPrice - promoPrice)*quantity); + strcpy((char *)stmt6, "INSERT INTO temp_table1(custid,partid,excessamount) " + "values(?,?,?)"); + /* prepare the statement */ + cliRC = SQLPrepare(hstmt3, stmt6, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt3, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "INSERT statement failed."); + /* bind the parameter to the statement */ + cliRC = SQLBindParameter(hstmt3, + 1, + SQL_PARAM_INPUT, + SQL_C_SBIGINT, + SQL_BIGINT, + 0, + 0, + &custid, + 0, + NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt3, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter"); + cliRC = SQLBindParameter(hstmt3, 2, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_CHAR, + 12, + 0, + partid, + 12, + NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt3, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter"); + cliRC = SQLBindParameter(hstmt3, + 3 , + SQL_PARAM_INPUT, + SQL_C_FLOAT, + SQL_REAL, + 0, + 0, + &excessamount, + 0, + NULL); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt3, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SQLBindParameter"); + cliRC = SQLExecute(hstmt3); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt3, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "INSERT statement failed."); + cliRC = SQLFetch(hstmt2); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt2, cliRC, henv, hdbc); + } + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt2); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + + cliRC = SQLFetch(hstmt1); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt2, cliRC, henv, hdbc); + } + strcpy((char *)stmt7, "INSERT INTO temp_table2( SELECT custid, sum(excessamount) " + "FROM temp_table1 GROUP BY custid)"); + cliRC = SQLPrepare(hstmt4, stmt7, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt4, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "INSERT statement failed."); + cliRC = SQLExecute(hstmt4); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt4, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "INSERT statement failed."); + + /* format the results into an XML document of the following form + + + XXXX + XXXX.XXXX + + xxxx xxx + ......... + + + ............ + */ + strcpy((char *)stmt8,"XQUERY let $res:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME " + "\"\"Customer\"\",( XMLCONCAT(XMLELEMENT(NAME \"\"Custid\"\", t.cid)," + "XMLELEMENT( NAME \"\"Total\"\", t.total),c.info))) " + "FROM temp_table2 AS t,customer AS c WHERE t.cid = c.cid\") " + "return {$res}"); + cliRC = SQLPrepare(hstmt5, stmt8, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt5, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "Prepare statement failed."); + /* execute the statement */ + cliRC = SQLExecute(hstmt5); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt5, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "SELECT statement failed."); + cliRC = SQLBindCol(hstmt5, + 1, + SQL_C_CHAR, + &(outXML->data), + 5000, + (SQLINTEGER*)&(outXML->length)); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt5, cliRC, henv, hdbc); + + /* fetch a row */ + cliRC = SQLFetch(hstmt5); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt5, cliRC, henv, hdbc); + + *outXML_ind=-0; + + /* drop the temporary tables */ + strcpy((char *)stmt1,"DROP TABLE temp_table1"); + cliRC = SQLExecDirect(hstmt, stmt1, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "DROP statement failed."); + + /* create the table temp_table2 */ + strcpy((char *)stmt2,"DROP TABLE temp_table2"); + cliRC = SQLExecDirect(hstmt, stmt2, SQL_NTS); + SRV_HANDLE_CHECK_SETTING_SQLST_AND_MSG(SQL_HANDLE_STMT, + hstmt, + cliRC, + henv, + hdbc, + sqlstate, + diagMsg, + "DROP statement failed."); + + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt1); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt3); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt4); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt5); + SRV_HANDLE_CHECK(SQL_HANDLE_STMT, hstmt, cliRC, henv, hdbc); + + /* disconnect from the data source */ + cliRC = SQLDisconnect(hdbc); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* free the database handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + SRV_HANDLE_CHECK(SQL_HANDLE_DBC, hdbc, cliRC, henv, hdbc); + + /* free the environment handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_ENV, henv); + SRV_HANDLE_CHECK(SQL_HANDLE_ENV, henv, cliRC, henv, hdbc); + + return (0); +} /* end of the procedure */ diff --git a/xml/xquery/cli/xquery_xmlproc.exp b/xml/xquery/cli/xquery_xmlproc.exp new file mode 100644 index 0000000..c56a855 --- /dev/null +++ b/xml/xquery/cli/xquery_xmlproc.exp @@ -0,0 +1 @@ +xquery_proc diff --git a/xml/xquery/cli/xquery_xmlproc_client.c b/xml/xquery/cli/xquery_xmlproc_client.c new file mode 100644 index 0000000..df25a9e --- /dev/null +++ b/xml/xquery/cli/xquery_xmlproc_client.c @@ -0,0 +1,226 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: xquery_xmlproc_client.c +** +** SAMPLE: Call the stored procedure implemented in xquery_xmlproc.c +** +** To run this sample, peform the following steps: +** (1) see and complete the instructions in xquery_xmlproc.c for building +** the shared library +** (2) compile xquery_xmlproc_client.c (nmake xquery_xmlproc_client (Windows) +** or make xquery_xmlproc_client(UNIX), or bldapp xquery_xmlproc_client +** for the Microsoft Visual C++ compiler on Windows) +** (3) run xquery_xmlproc_client (xquery_xmlproc_client) +** +** xquery_xmlproc_client.c uses a function to call stored procedure defined +** in xquery_xmlproc.c. +** +** callxquery_proc: Calls the stored procedure defined in +** xquery_xmlproc.c and returns the details of the customers +** with excess amount paid by them. +** +** Parameter types used: +** IN XML AS CLOB(5000) +** IN XML AS CLOB(5000) +** OUT INTEGER +** +** CLI FUNCTIONS USED: +** SQLAllocHandle -- Allocate Handle +** SQLBindCol -- Bind a Column to an Application Variable or +** LOB locator +** SQLBindParameter -- Bind a Parameter Marker to a Buffer or +** LOB locator +** SQLEndTran -- End Transactions of a Connection +** SQLExecute -- Execute a Statement +** SQLFetch -- Fetch Next Row +** SQLFreeHandle -- Free Handle Resources +** SQLPrepare -- Prepare a Statement +** +** EXTERNAL DEPENDENCIES: +** Ensure that the stored procedures called from this program have +** been built and cataloged with the database (see the instructions in +** xquery_xmlproc.c). +** +** OUTPUT FILE: xquery_xmlproc_client.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on developing CLI applications, see the CLI Guide +** and Reference. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "utilcli.h" + +int callxquery_proc(SQLHANDLE); + +int main(int argc, char *argv[]) +{ + SQLRETURN cliRC = SQL_SUCCESS; + int rc = 0; + SQLHANDLE henv; /* environment handle */ + SQLHANDLE hdbc; /* connection handle */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + /* initialize the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + SQL_AUTOCOMMIT_OFF); + if (rc != 0) + { + return rc; + } + + /********************************************************\ + * calling stored procedure * + \********************************************************/ + rc = callxquery_proc(hdbc); + + /* rollback any changes to the database made by this sample */ + printf("\nRoll back the transaction.\n"); + + /* end transactions on the connection */ + cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* terminate the CLI application by calling a helper + utility function defined in utilcli.c */ + rc = CLIAppTerm(&henv, &hdbc, dbAlias); + + return rc; +} /* end main */ + + +/* call the Supp_XML_Proc_CLI stored procedure */ +int callxquery_proc(SQLHANDLE hdbc) +{ + SQLRETURN cliRC = SQL_SUCCESS; + SQLHANDLE hstmt; /* statement handle */ + int rc = 0; + char temp[5000]=""; + + struct inXML_t + { + sqluint32 length; + char data[5000]; + } inXML; + + struct outXML_t + { + sqluint32 length; + char data[5000]; + } outXML; + + char procName[] = "Supp_XML_Proc_CLI"; + SQLCHAR *stmt = (SQLCHAR *)"CALL Supp_XML_Proc_CLI(?,?)"; + + strcpy( inXML.data, " " + " 2006-01-02" + " 2006-08-02 " + " " + "2006-09-22 " + " "); + inXML.length=strlen(inXML.data); + + printf("\n ******************************************************************************\n"); + printf("\n CALL stored procedure: %s\n", procName); + + /* allocate a statement handle */ + cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + DBC_HANDLE_CHECK(hdbc, cliRC); + + /* prepare the statement */ + cliRC = SQLPrepare(hstmt, stmt, SQL_NTS); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* bind the parameters to the statement */ + cliRC = SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(inXML.data), + 5000, + (SQLINTEGER *)&(inXML.length)); + + STMT_HANDLE_CHECK(hstmt,hdbc,cliRC); + + cliRC = SQLBindParameter(hstmt, + 2, + SQL_PARAM_OUTPUT, + SQL_C_CHAR, + SQL_XML, + 5000, + 0, + &(outXML.data), + 5000, + (SQLINTEGER*)&(outXML.length)); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + /* execute the statement */ + cliRC = SQLExecute(hstmt); + + /* place the results into application variables */ + strncpy(temp, outXML.data, outXML.length); + temp[outXML.length] = '\n'; + + printf("\n Stored procedure Returned: \n"); + + printf("\n Customers are: \n %s", temp); + + /* free the statement handle */ + cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + STMT_HANDLE_CHECK(hstmt, hdbc, cliRC); + + return rc; +} /* end callxquery_proc */ + + + diff --git a/xml/xquery/cli/xquery_xmlproc_create.db2 b/xml/xquery/cli/xquery_xmlproc_create.db2 new file mode 100644 index 0000000..009d0a4 --- /dev/null +++ b/xml/xquery/cli/xquery_xmlproc_create.db2 @@ -0,0 +1,55 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xquery_xmlproc_create.db2 +-- +-- SAMPLE: How to catalog the DB2 CLI stored procedure contained in +-- xquery_xmlproc.c +-- +-- To run this script from the CLP, issue the command +-- db2 -td@ -vf xquery_xmlproc_create.db2 +---------------------------------------------------------------------------- +-- For more information on the sample programs, see the README file. +-- +-- For information on developing CLI applications, see the CLI Guide +-- and Reference. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- creating procedure +CREATE PROCEDURE Supp_XML_Proc_CLI( IN inXML XML as CLOB(5000), + OUT outXML XML as CLOB(5000)) +LANGUAGE C +PARAMETER STYLE SQL +FENCED +PARAMETER CCSID UNICODE +EXTERNAL NAME 'xquery_xmlproc!xquery_proc'@ + +CONNECT RESET@ + + diff --git a/xml/xquery/cli/xquery_xmlproc_drop.db2 b/xml/xquery/cli/xquery_xmlproc_drop.db2 new file mode 100644 index 0000000..4411be2 --- /dev/null +++ b/xml/xquery/cli/xquery_xmlproc_drop.db2 @@ -0,0 +1,35 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xquery_xmlproc_drop.db2 +-- +-- SAMPLE: Uncatalog the DB2 CLI stored procedure contained in xquery_xmlproc.c +-- +-- To run this script from the CLP, issue the command +-- "db2 -td@ -vf xquery_xmlproc_drop.db2" +---------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- drop the procedure +DROP PROCEDURE Supp_XML_Proc_CLI ( XML as CLOB(5000), + XML as CLOB(5000))@ +CONNECT RESET@ diff --git a/xml/xquery/clp/flwor.db2 b/xml/xquery/clp/flwor.db2 new file mode 100644 index 0000000..e10749a --- /dev/null +++ b/xml/xquery/clp/flwor.db2 @@ -0,0 +1,113 @@ +--------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: flwor.db2 +-- +-- SAMPLE: Simple FLWOR expression Queries +-- +-- SQL/XML FUNCTIONS USED +-- xmlcolumn +-- +-- XQUERY FUNCTIONS/EXPRESSIONS USED +-- flwor expression +-- conditional expression +-- arithmatic expression +-- +-- SAMPLE EXECUTION: +-- Run the samples with following command +-- db2 -td@ -vf flwor.db2 +-- +-- OUTPUT FILE: flwor.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using XQUERY statements, see the XQUERY Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to sample database +CONNECT TO SAMPLE@ + +-- List down the name of customer in Canada in alphabetical order +XQUERY for $custinfo in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[addr/@country="Canada"] + order by $custinfo/name,$custinfo/@Cid + return $custinfo/name @ + +-- List down the name and the address of the customer having cid greater then 1000 +-- and wrap the result in an element customer. +XQUERY for $customer in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo where ($customer/@Cid > 1002) + order by $customer/@Cid + return + + + {$customer/name} + {$customer/addr} + @ + +-- List down the street and city of the customers when the following conditions are met +-- Cid > 1000 +-- Country attribute is not equal to US. +XQUERY for $customer in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo + where ($customer/@Cid > 1002) and ($customer/addr/@country !="US") + order by $customer/@Cid + return + + {$customer/name} +
+ {$customer/addr/street} + {$customer/addr/city} +
+
@ + +-- Find the product with highest price. +-- The following Query will give the first product as output if their are 2 products wit same max price +XQUERY let $prod := for $product in db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product/description + order by fn:number($product/price) descending + return $product + return + + {$prod[1]/name} + @ + +-- The following Query will give all the product with the same max price +XQUERY let $prod := db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product/description + let $price := max($prod/price) + return + + {$prod[price=$price]/name} + @ + +-- Find names of all the products wrap it in product element +-- having an attribute "basic" with value true if the price < 10 otherwise false +XQUERY for $prod in db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product/description + order by $prod/name + return ( + if ($prod/price < 10) + then {fn:data($prod/name)} + else {fn:data($prod/name)})@ + +-- Reset the connection +CONNECT RESET@ + diff --git a/xml/xquery/clp/sqlxquery.db2 b/xml/xquery/clp/sqlxquery.db2 new file mode 100644 index 0000000..862529d --- /dev/null +++ b/xml/xquery/clp/sqlxquery.db2 @@ -0,0 +1,89 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: sqlxquery.db2 +-- +-- SAMPLE: SQL/XML Queries +-- +-- SQL/XML FUNCTIONS USED +-- sqlquery +-- xmlexists +-- xmlquery +-- +-- SQL STATEMETNS USED +-- SELECT +-- +-- SAMPLE EXECUTION: +-- Run the samples with following command +-- db2 -td@ -vf sqlxquery.db2 +-- +-- OUTPUT FILE: xpath.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using XQUERY statements, see the XQUERY Reference. +-- +-- For information on using SQL statements, see the SQL Reference. + +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to sample database +CONNECT TO SAMPLE@ + +-- Find out first purchaseorders of the customer with name Robert Shoemaker +SELECT XMLQUERY('$p/PurchaseOrder/item[1]' PASSING p.porder AS "p") + FROM purchaseorder AS p, customer AS c + WHERE XMLEXISTS('$custinfo/customerinfo[name="Robert Shoemaker" and @Cid = $cid]' + PASSING c.info AS "custinfo", p.custid AS "cid")@ + +-- Return the first item in the purchaseorder and the history of all the customer +-- when the following conditions are met +-- 1. Customer ID in the sequence (1000,1002,1003) or +-- 2. Name is sequece (X,Y,Z) +SELECT XMLQUERY('$p/PurchaseOrder/item[1]' passing p.porder as "p"),XMLQUERY('$x/history' passing c.history as "x") + FROM purchaseorder as p,customer as c + WHERE XMLEXISTS('$custinfo/customerinfo[name=(X,Y,Z) or @Cid=(1000,1002,1003) and @Cid=$cid ]' + PASSING c.info AS "custinfo", p.custid AS "cid")@ + +-- Find out all the customer names and sort them according to number of orders +WITH count_table AS ( SELECT count(poid) AS c,custid + FROM purchaseorder,customer + WHERE cid=custid GROUP BY custid ) + SELECT c,custid, XMLQUERY('$s/customerinfo[@Cid=$id]/name' + PASSING customer.info AS "s", count_table.custid AS "id") + FROM customer,count_table + WHERE custid=cid ORDER BY custid@ + +-- Find out the number of purchaseorder having item with partid 100-101-01 for customer Robert Shoemaker +WITH cid_table AS (SELECT Cid FROM customer + WHERE XMLEXISTS('$custinfo/customerinfo[name="Robert Shoemaker"]' PASSING customer.info AS "custinfo")) + SELECT count(poid) FROM purchaseorder,cid_table + WHERE XMLEXISTS('$po/itemlist/item[partid="100-101-01"]' PASSING purchaseorder.porder AS "po") + AND purchaseorder.custid=cid_table.cid@ + +-- Reset the connection +CONNECT RESET@ + + diff --git a/xml/xquery/clp/xpath.db2 b/xml/xquery/clp/xpath.db2 new file mode 100644 index 0000000..f16af73 --- /dev/null +++ b/xml/xquery/clp/xpath.db2 @@ -0,0 +1,93 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xpath.db2 +-- +-- SAMPLE: Simple XPath Queries +-- +-- SQL/XML FUNCTIONS USED +-- xmlcolumn +-- sqlquery +-- NOTE : Both the above functions are case sensitive. +-- +-- XQUERY FUNCTIONS USED +-- count +-- avg +-- start-with +-- distinct-values +-- NOTE : All the xquery functions are case sensitive + +-- SAMPLE EXECUTION: +-- Run the samples with following command +-- db2 -td@ -vf xpath.db2 +-- +-- OUTPUT FILE: xpath.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using XQUERY statements, see the XQUERY Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to sample database +CONNECT TO SAMPLE@ + +-- Find out the information of all the customer +-- Both the queries below will give the same result +XQUERY for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo + order by xs:double($cust/@Cid) + return $cust@ + +XQUERY db2-fn:sqlquery("select info from customer order by cid")@ + +-- Find out the customers information from Toronto city +-- Both the queries below will give the same result + +XQUERY for $nme in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[addr/city="Toronto"]/name + order by $nme + return $nme@ + +XQUERY for $nme in db2-fn:xmlcolumn('CUSTOMER.INFO')//city[text()="Toronto"]/../../name + order by $nme + return $nme@ + +-- Find out all the customer cities from country Canada + +XQUERY for $cty in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/addr[@country="Canada"]/city) + order by $cty + return $cty@ + +-- Find out number of customer in Toronto city +XQUERY fn:count(db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[addr/city="Toronto"])@ + +-- Find out all the customer names whose mobile number starts with 905 +XQUERY db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[phone[@type="cell" and fn:starts-with(text(),"905")]]@ + +-- Find out the average price for all the products in 100 series +XQUERY let $prod_price := db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product[fn:starts-with(@pid,"100")]/description/price + return avg($prod_price)@ + +-- Reset the connection +CONNECT RESET@ diff --git a/xml/xquery/clp/xquery.db2 b/xml/xquery/clp/xquery.db2 new file mode 100644 index 0000000..6387ee9 --- /dev/null +++ b/xml/xquery/clp/xquery.db2 @@ -0,0 +1,199 @@ +--------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xquery.db2 +-- +-- SAMPLE: How to run a nested XQuery and shows how to pass parameters to +-- sqlquery function. +-- +-- SQL/XML FUNCTIONS USED +-- xmlcolumn +-- sqlquery +-- +-- XQUERY FUNCTIONS/EXPRESSIONS USED +-- distinct-values +-- concat +-- upper-case +-- flwor expression +-- conditional expression +-- arithmatic expression +-- +-- SAMPLE EXECUTION: +-- Run the samples with following command +-- db2 -td! -vf xquery.db2 +-- +-- OUTPUT FILE: xquery.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using XQUERY statements, see the XQUERY Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- Connect to sample database +CONNECT TO SAMPLE! + +-- Find out all the purchaseorders city wise +XQUERY for $city in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/addr/city) + order by $city + return + + { + for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[addr/city=$city] + let $po:=db2-fn:sqlquery("SELECT XMLELEMENT( NAME ""pos"", + (XMLCONCAT( XMLELEMENT(NAME ""custid"", c.custid), + XMLELEMENT(NAME ""order"", c.porder) + ) )) + FROM purchaseorder AS c") + let $id:=$cust/@Cid, + $order:=$po/pos[custid=$id]/order + order by $cust/@Cid + return + + {$cust/name} + {$cust/addr} + {$order} + } + ! + +-- In Viper2 the above query can be written as follows +XQUERY for $city in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO') /customerinfo/addr/city) + order by $city + return + + { + for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo [addr/city=$city] + let $po:=db2-fn:sqlquery("SELECT porder FROM PURCHASEORDER WHERE custid=parameter(1)",$cust/@Cid), + $order:=$po/order + order by $cust/@Cid + return + + {$cust/name} + {$cust/Addr} + {$order} + } + ! + +-- Find out all the customer product wise +XQUERY let $po:=db2-fn:sqlquery("SELECT XMLELEMENT( NAME ""pos"", + ( XMLCONCAT( XMLELEMENT(NAME ""custid"", c.custid), + XMLELEMENT(NAME ""order"", c.porder) + ) )) + FROM purchaseorder AS c" ) + for $partid in fn:distinct-values(db2-fn:xmlcolumn('PURCHASEORDER.PORDER')/PurchaseOrder/item/partid) + order by $partid + return + + + { + for $id in fn:distinct-values($po[order/PurchaseOrder/item/partid=$partid]/custid) + let $order:= + {fn:sum($po[custid=$id]/order/PurchaseOrder/item[partid=$partid]/quantity)} + , + $cust:=db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[@Cid=$id] + order by $id + return + + {$order} + {$cust} + + } + + ! + + +-- Find out all the purchaseorders province wise, then city wise and then street wise. +XQUERY let $po:=db2-fn:sqlquery("SELECT XMLELEMENT( NAME ""pos"", + ( XMLCONCAT( XMLELEMENT(NAME ""custid"", c.custid), + XMLELEMENT(NAME ""order"", c.porder) + ) )) + FROM PURCHASEORDER as c ORDER BY poid"), + $addr:=db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/addr + for $prov in distinct-values($addr/prov-state) + return + + { + for $city in fn:distinct-values($addr[prov-state=$prov]/city) + order by $city + return + + { + for $s in fn:distinct-values($addr/street) where $addr/city=$city + order by $s + return + + { + for $info in $addr[prov-state=$prov and city=$city and street=$s]/.. + order by $info/@Cid + return + + {$info/name} + { + let $id:=$info/@Cid, $order:=$po[custid=$id]/order + return $order + } + + } + + } + + } + ! + + +-- Combine XML data from customer.info and product.description to for the customer id 1000. +XQUERY + { + for $ns1_customerinfo0 in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo + where ($ns1_customerinfo0/@Cid=1001) + return + + {$ns1_customerinfo0/name} +
+ {$ns1_customerinfo0/addr/street} + {$ns1_customerinfo0/addr/city} + { + if($ns1_customerinfo0/addr/@country="US") + then + $ns1_customerinfo0/addr/prov-state + else() + } + { + fn:concat ($ns1_customerinfo0/addr/pcode-zip/text(),",",fn:upper-case($ns1_customerinfo0/addr/@country +))} +
+
+ } + { + for $ns2_product0 in db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product + where ($ns2_product0/@pid="100-100-01") + return + $ns2_product0 + } +
! + +-- Reset the connection +CONNECT RESET! + diff --git a/xml/xquery/clp/xquery_explain.db2 b/xml/xquery/clp/xquery_explain.db2 new file mode 100644 index 0000000..b5f82f3 --- /dev/null +++ b/xml/xquery/clp/xquery_explain.db2 @@ -0,0 +1,124 @@ + +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xquery_explain.db2 +-- +-- SAMPLE: How to get the explain information of a SQL/XML or XQuery statement +-- +-- SAMPLE EXECUTION: +-- Run the samples with following command +-- db2 -td@ -vf xquery_explain.db2 +-- +-- PREREQUISITE : Explain tables should be created before running this sample +-- Use the following command to create the Explain Table +-- +-- db2 -tf EXPLAIN.DDL +-- EXPLAIN.DDL file can be found in sqllib/misc directory +-- +-- OUTPUT FILE: xquery_explain.out (available in the online documentation) +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using XQUERY statements, see the XQUERY Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the database +CONNECT TO SAMPLE@ + +-- set CURRENT EXPLAIN MODE to EXPLAIN. +SET CURRENT EXPLAIN MODE = EXPLAIN@ + +-- run a dynamic statement. as CURRENT EXPLAIN MODE is set to EXPLAIN, +-- query will not run only the explain information will be captured +XQUERY for $custinfo in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[addr/@country="Canada"] + order by $custinfo/name + return $custinfo/name @ + +-- format the explain tables, explain plan will be found in file explain_result1 +!db2exfmt -d sample -e newton -f O -g OTI -n %% -s %% -o explain_result1 -w -1 -# 0@ + +-- set CURRENT EXPLAIN MODE to YES +SET CURRENT EXPLAIN MODE = YES@ + +-- run a dynamic statement. as CURRENT EXPLAIN MODE is set to YES, +-- query will be executed and the explain information will be captured +XQUERY let $prod_price := db2-fn:xmlcolumn('PRODUCT.DESCRIPTION') + /product[fn:starts-with(@pid,"100")]/description/price + return avg($prod_price)@ + +-- format the explain tables, explain plan will be found in file explain_result2 +!db2exfmt -d sample -e newton -f O -g OTI -n %% -s %% -o explain_result2 -w -1 -# 0@ + +-- explain a SQL/XML statement using EXPLAIN PLAN statement +EXPLAIN PLAN SELECTION FOR SELECT XMLQUERY + ('$p/PurchaseOrder/item[1]' + PASSING p.porder AS "p") + FROM purchaseorder AS p, customer AS c + WHERE XMLEXISTS('$custinfo/customerinfo[name="Robert Shoemaker" and @Cid = $cid]' + PASSING c.info AS "custinfo", p.custid AS "cid")@ + +-- format the explain tables, explain plan will be found in file explain_result3 +!db2exfmt -d sample -e newton -f O -g OTI -n %% -s %% -o explain_result3 -w -1 -# 0@ + +-- explain an SQL/XML statement +EXPLAIN PLAN SELECTION FOR WITH count_table AS ( SELECT count(poid) AS c,custid + FROM purchaseorder,customer + WHERE cid=custid GROUP BY custid ) + SELECT c,custid, XMLQUERY('$s/customerinfo[@Cid=$id]/name' + PASSING customer.info AS "s", count_table.custid AS "id") + FROM customer,count_table + WHERE custid=cid ORDER BY c@ + +-- format the explain tables, explain plan will be found in file explain_result4 +!db2exfmt -d sample -e newton -f O -g OTI -n %% -s %% -o explain_result4 -w -1 -# 0@ + +-- explain a simple XQuery statement +EXPLAIN PLAN SELECTION FOR XQUERY 'let $prod_price := db2-fn:xmlcolumn("PRODUCT.DESCRIPTION") + /product[fn:starts-with(@pid,"100")]/description/price + return avg($prod_price)'@ + +-- format the explain tables, explain plan will be found in file explain_result5 +!db2exfmt -d sample -e newton -f O -g OTI -n %% -s %% -o explain_result5 -w -1 -# 0@ + +-- explain an XQuery statement with FLWOR expression +EXPLAIN PLAN SELECTION FOR XQUERY 'for $customer in db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo + where ($customer/@Cid gt 1002) and ($customer/addr/@country !="US") + return + + {$customer/name} +
+ {$customer/addr/street} + {$customer/addr/city} +
+
'@ + +-- format the explain tables, explain plan will be found in file explain_result6 +!db2exfmt -d sample -e newton -f O -g OTI -n %% -s %% -o explain_result6 -w -1 -# 0@ + + +CONNECT RESET@ + diff --git a/xml/xquery/clp/xquery_xmlproc.db2 b/xml/xquery/clp/xquery_xmlproc.db2 new file mode 100644 index 0000000..0221f97 --- /dev/null +++ b/xml/xquery/clp/xquery_xmlproc.db2 @@ -0,0 +1,246 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: xquery_xmlproc.db2 +-- +-- SAMPLE: An application sample developed using SQL stored procedure with +-- XML type parameters and complex XQueries. +-- +-- SCENARIO: +-- Some of the suppliers have extended the promotional price date for +-- their products. Getting all the customer's Information who purchased +-- these products in the extended period will help the financial department +-- to return the excess amount paid by those customers. The supplier +-- information along with extended date's for the products is provided +-- in an XML document and the client wants to have the information +-- of all the customers who has paid the excess amount by purchasing these +-- products in the extended period. +-- +-- This procedure will return an XML document containing customer +-- information along with the the excess amount paid by them. +-- +-- SQL STATEMENTS USED: +-- CREATE PROCEDURE +-- DROP PROCEDURE +-- PREPARE +-- OPEN +-- FETCH +-- INSERT +-- SELECT +-- +-- To run this script from the CLP, issue the command +-- "db2 -td@ -vf xquery_xmlproc.db2" +----------------------------------------------------------------------------- +-- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +----------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- drop the procedure if exists +DROP PROCEDURE Supp_XmlProc@ + +-- procedure definition +CREATE PROCEDURE Supp_XmlProc(IN inXML XML ,OUT Customers XML) +LANGUAGE SQL +BEGIN + +DECLARE SQLCODE INTEGER; +DECLARE data XML; +DECLARE prodid VARCHAR (12); +DECLARE partid VARCHAR (12); +DECLARE oldPromoDate DATE; +DECLARE newPromoDate DATE; +DECLARE originalPrice DECIMAL(30,2); +DECLARE promoPrice DECIMAL(30,2); +DECLARE custid INTEGER; +DECLARE quantity INTEGER; +DECLARE excessamount DECIMAL(30,2); +DECLARE orders XML; +DECLARE stmt_xq1 VARCHAR (1024); +DECLARE stmt_xq2 VARCHAR (1024); +DECLARE stmt_xq3 VARCHAR (1024); +DECLARE stmt_xq4 VARCHAR (1024); +DECLARE stmt1 STATEMENT; +DECLARE stmt2 STATEMENT; +DECLARE stmt3 STATEMENT; +DECLARE stmt4 STATEMENT; +DECLARE cur_xq1 CURSOR FOR stmt1; +DECLARE cur_xq2 CURSOR FOR stmt2; +DECLARE cur_xq3 CURSOR FOR stmt3; +DECLARE cur_xq4 CURSOR FOR stmt4; + +-- set the input XML document to an application variable +SET data = inXML; + +-- an XQUERY statement to restructure all the PurchaseOrders +-- into the following form +-- +-- +-- XXXX +-- XXX-XXX-XX +-- XX +-- ............................... +-- ................. +-- store the above XML document in an application varible "orders" + +SET stmt_xq1= 'XQUERY let $po:=db2-fn:sqlquery("SELECT XMLELEMENT( NAME ""porders"", + ( XMLCONCAT( XMLELEMENT(NAME ""custid"", p.custid), p.porder) )) + FROM PURCHASEORDER as p") return {for $i in $po, $j in + $po[custid=$i/custid]/PurchaseOrder[@PoNum=$i/PurchaseOrder/@PoNum]/item + return {$i/PurchaseOrder/@OrderDate}{$i/custid}{$j/partid} + {$j/quantity}}'; +PREPARE stmt1 FROM stmt_xq1; +OPEN cur_xq1; +FETCH FROM cur_xq1 INTO orders; +CLOSE cur_xq1; + +-- select the oldpromodate, newpromodate, price and promoprice +-- for the products for which the promodate is extended +-- using input XML document + +SET stmt_xq2 = 'SELECT Pid,PromoEnd,Price,PromoPrice, + XMLCAST(XMLQUERY(''$info/Suppliers/Supplier/Products/ + Product[@id=$pid]/ExtendedDate'' passing cast(? as XML) as "info", + pid as "pid") as DATE) FROM product WHERE XMLEXISTS(''for $prod in + $info//Product[@id=$pid] return $prod'' passing by ref cast(? as XML) + as "info", pid as "pid")'; +PREPARE stmt2 FROM stmt_xq2; +OPEN cur_xq2 USING data,data; +FETCH FROM cur_xq2 INTO prodid,oldPromoDate,originalPrice,promoPrice,newPromoDate; + +-- create two temporary tables +CREATE TABLE temp_table1(custid INT,partid VARCHAR(12),excessamount DECIMAL(30,2)); +CREATE TABLE temp_table2(cid INT,total DECIMAL(30,2)); + +-- repeat the above for all products +WHILE (SQLCODE = 0) Do + + -- finding out the toatal quantity of the product purchased by a customer + -- if that order is made in between oldpromodate and extended promodate. + -- this query will return the custid, product id and total quantity of + -- that product purchased in all his orders. + + SET stmt_xq3 = 'WITH temp1 AS (SELECT cid,partid,quantity,orderdate + FROM XMLTABLE(''$od/item'' passing cast(? as XML) as "od" + COLUMNS cid BIGINT path ''./custid'', partid VARCHAR(20) path + ''./partid'', orderdate DATE path ''./@OrderDate'', + quantity BIGINT path ''./quantity'') as temp2 ) SELECT temp1.cid, + temp1.partid, sum(temp1.quantity) as quantity FROM temp1 WHERE partid=? + and orderdate>? and orderdate +-- +-- XXXX +-- XXXX.XXXX +-- +-- xxxx xxx +-- ......... +-- +-- +-- ............ +-- + +SET stmt_xq4='XQUERY let $res:=db2-fn:sqlquery("SELECT XMLELEMENT( NAME ""Customer"",( XMLCONCAT(XMLELEMENT(NAME ""Custid"", t.cid),XMLELEMENT(NAME ""Total"", t.total),c.info))) FROM temp_table2 AS t,customer AS c WHERE t.cid = c.cid") return {$res}'; + +PREPARE stmt4 FROM stmt_xq4; +OPEN cur_xq4; +FETCH FROM cur_xq4 INTO Customers; + +-- close the cursor cur_xq4 +CLOSE cur_xq4; + +-- drop the temporary tables created +DROP TABLE temp_table1; +DROP TABLE temp_table2; + +-- end of the procedure +END@ + +-- calling the procedure with necessary options +CALL Supp_XmlProc(xmlparse(document ' + + + + + 2007-01-02 + + + 2007-05-02 + + + + + + + 2007-08-22 + + + + +'),?)@ + +-- rollback the work to keep database consistent +ROLLBACK@ + +CONNECT RESET@ + diff --git a/xml/xquery/clp/xqueryparam.db2 b/xml/xquery/clp/xqueryparam.db2 new file mode 100644 index 0000000..a307a49 --- /dev/null +++ b/xml/xquery/clp/xqueryparam.db2 @@ -0,0 +1,193 @@ +----------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +----------------------------------------------------------------------------- +-- +-- SAMPLE FILE NAME: xqueryparam.db2 +-- +-- PURPOSE: This sample shows how to pass parameters to the +-- db2-fn:sqlquery function. +-- +-- USAGE SCENARIO: The super market manager maintains database with +-- "employee" and "dept_location" tables. "Employee" table +-- contains employee ID and employee address. +-- "dept_location" table contains the department and +-- and it's location details.He will query +-- these tables to get information about employees, their +-- department details. +-- The last XQuery exprepression in this sample shows +-- purchaseorder details from the sample database +-- purchaseorder table. +-- +-- PREREQUISITE: Sample database should exist before running this sample. +-- +-- EXECUTION: db2 -td@ -vf xqueryparam.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Queries will display the results. +-- +-- OUTPUT FILE: xqueryparam.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- CREATE TABLE +-- INSERT +-- DROP +-- +-- SQL/XML FUNCTIONS USED: +-- SQLQUERY +-- XMLCOLUMN +-- +----------------------------------------------------------------------------- +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- +-- For information on using SQL statements, see the SQL Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- +----------------------------------------------------------------------------- +-- SAMPLE DESCRIPTION +-- +----------------------------------------------------------------------------- +-- 1. Passing single parameter to SQL fullselect db2-fn:sqlquery function. +-- +-- 2. Passing multiple parameters to SQL fullselect in db2-fn:sqlquery function. +-- +----------------------------------------------------------------------------- +-- SETUP +----------------------------------------------------------------------------- +-- Connect to sample database +CONNECT TO sample@ +-- + +-- Create table "employee" +CREATE TABLE employees(empid int, addr XML)@ + +-- Create table "dept_location" +CREATE TABLE dept_location(dept_name varchar(20), + branch_name varchar(50), + block_no varchar(20), street + varchar(20), city varchar(20), + zip_code varchar(20), + dept_details XML)@ + +-- Insert row into table "dept_location" +INSERT INTO dept_location +VALUES ('DB2', 'EGL', 'B', 'Koramangala', 'Bangalore', '500042', +XMLPARSE(document + ' + Peter suzanski + + Samples + testing + Development + + 140 + ' ))@ + +-- Insert row into table "dept_location" +INSERT INTO dept_location +VALUES ('Informix','MANYATA', 'D2', 'Hebbal', 'Bangalore', '500067', +XMLPARSE(document +' + Jeff + + bird + QA + + 60 + ' ))@ + +-- Insert row into table "employee" +INSERT INTO employees +VALUES (1005, XMLPARSE(document +' + Ravi varma + + Hebbal + Bangalore + Karnataka + 500067 + +'))@ + +-- Insert row into table "employee" +INSERT INTO employees +VALUES (1006, XMLPARSE(document +' + Oswal Menard + + Koramangala + Bangalore + Karnataka + 500042 + +'))@ + +----------------------------------------------------------------------------- +-- 1. Passing single parameter to SQL fullselect in db2-fn:sqlquery function. +----------------------------------------------------------------------------- +-- The following XQuery expression returns an employee's postal code +-- and department details when the employee and the department are in +-- the same location (defined by zip code). +XQUERY declare default element namespace "http://posample.org"; + for $pcode in db2-fn:xmlcolumn("EMPLOYEES.ADDR")/employeeinfo/addr/pcode-zip + for $deptinfo in db2-fn:sqlquery( "SELECT dept_details FROM dept_location + WHERE zip_code = parameter(1)", $pcode) + order by $pcode + return {$pcode, $deptinfo }@ + +------------------------------------------------------------------------------ +-- 2. Passing multiple parameters to SQL fullselect in db2-fn:sqlquery function. +------------------------------------------------------------------------------ +-- The following XQuery expression returns an employee's postal code,department +-- name and department details, when an employee and a department are in same +-- location, and the employee belongs to one of the following departments: +-- DB2, Informix or CM. +XQUERY declare default element namespace "http://posample.org"; +for $pcode in db2-fn:xmlcolumn("EMPLOYEES.ADDR")/employeeinfo/addr/pcode-zip, + $dept in ('DB2', 'Informix', 'CM') + for $deptinfo in db2-fn:sqlquery( + "SELECT dept_details FROM dept_location + WHERE zip_code = parameter(1) and dept_name = parameter(2)", $pcode, $dept) +order by $pcode +return + {$pcode} + {$dept} + {$deptinfo} + @ + +-- The following XQuery expression uses the purchaseorder table from the sample +-- database. +-- The XQuery expression returns all purchase orders made by +-- customers after the date "2005-11-18". +XQUERY for $ponum in db2-fn:xmlcolumn("PURCHASEORDER.PORDER")/PurchaseOrder/@PoNum + for $x in db2-fn:sqlquery("SELECT porder FROM purchaseorder + WHERE OrderDate > parameter(1) and poid = parameter(2)", '2005-11-18', $ponum) +order by $ponum +return {$x} @ + +------------------------------------------------------------------------ +-- CLEANUP +------------------------------------------------------------------------ + +DROP TABLE employees@ +DROP TABLE dept_location@ diff --git a/xml/xquery/clp/xupdate.db2 b/xml/xquery/clp/xupdate.db2 new file mode 100644 index 0000000..0ef236d --- /dev/null +++ b/xml/xquery/clp/xupdate.db2 @@ -0,0 +1,275 @@ +--/************************************************************************* +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +-- ************************************************************************* +-- +-- SAMPLE FILE NAME: xupdate.db2 +-- +-- PURPOSE: To demonstrate how to insert, delete, update, replace, and rename +-- one or more XML documents or document fragments using transform +-- expressions. +-- +-- USAGE SCENARIO: The orders made by customers are stored in the existing +-- PurchaseOrder system. A customer has ordered some items initially, +-- and now the customer wants to add some more items and remove some +-- items from the list. This sample will show how the order is modified +-- using the XQuery transform expression and updating expressions. +-- +-- PREREQUISITE: NONE +-- +-- EXECUTION: db2 -tvf xupdate.db2 +-- +-- INPUTS: NONE +-- +-- OUTPUTS: Successful updation of the purchase orders. +-- +-- OUTPUT FILE: xupdate.out (available in the online documentation) +-- +-- SQL STATEMENTS USED: +-- INSERT +-- UPDATE +-- DROP +-- +-- SQL/XML FUNCTIONS USED: +-- XMLQUERY +-- +-- ************************************************************************* +-- For more information about the command line processor (CLP) scripts, +-- see the README file. +-- For information on using SQL statements, see the SQL Reference. +-- For information about XQuery expressions see the XQuery Reference. +-- +-- For the latest information on programming, building, and running DB2 +-- applications, visit the DB2 application development website: +-- http://www.software.ibm.com/data/db2/udb/ad +-- ************************************************************************* +-- +-- SAMPLE DESCRIPTION +-- +-- ************************************************************************* +-- 1. Insert Expression -- Insert a new element to the existing XML document/fragment. +-- 2. Delete Expression -- Delete some elements from the exisitng XML document/fragment. +-- 3. Replace value of Expression -- i) Replace the value of an element +-- ii) Replace the value of attribute +-- 4. Replace Expression -- Replace an element and attribute +-- 5. Rename Expression -- i) Rename an element in the existing XML document/fragment. +-- ii) Rename an attribute in the existing XML document/fragment. +-- 6. Insert and Replace Expressions -- Combination of transform expressions. +-- *************************************************************************/ + +-- Connect to the database +CONNECT TO sample; + +-- Insert an XML document into the purchaseorder table +DELETE FROM purchaseorder WHERE poid=5012; +INSERT INTO PURCHASEORDER(poid, status, porder, orderdate, comments, custid) + values(5012,'Unshipped',XMLPARSE(DOCUMENT(' + + + 100-100-01 + Snow Shovel, Basic 22 inch + 3 + 9.99 + + + 100-101-01 + Snow Shovel, Deluxe 24 inch + 1 + 19.99 + + + 100-201-01 + Ice Scraper, Windshield 4 inch + 5 + 3.99 + ')), '2006-02-18','THIS IS A NEW PURCHASE ORDER',1002); + + + +-- /************************************************************************* +-- 1. Insert Expression -- Insert a new element to the existing XML document/fragment. +-- *************************************************************************/ + +-- add a new item element +SELECT xmlquery('transform + copy $po := $order + modify do insert + document { + 100-103-01 + Snow Shovel, Super Deluxe 26 inch + 2 + 49.99 + } + as last into $po + return $po' passing purchaseorder.porder as "order") +from purchaseorder where poid=5012; + + +-- Add one item to the XML document and update in the database +UPDATE purchaseorder SET porder = + xmlquery('transform + copy $po := $order + modify do insert + document { + 100-103-01 + Snow Shovel, Super Deluxe 26 inch + 4 + 49.99 + } + into $po/PurchaseOrder return $po' + passing purchaseorder.porder as "order") where poid=5012; + +-- verify the result +SELECT porder FROM purchaseorder WHERE poid=5012; + +-- ************************************************************************** +-- 2. Delete Expression -- Delete some items from the exisitng XML document/fragment. +-- ************************************************************************** + +-- Delete some items basing on a condition +XQUERY transform + copy $po := db2-fn:sqlquery('select porder from purchaseorder where poid=5012') + modify do delete $po/PurchaseOrder/item[partid = '100-201-01'] + return $po; + +-- Update the table with deleted items +UPDATE purchaseorder SET porder = + xmlquery('transform + copy $po := $order + modify do delete $po/PurchaseOrder/item[partid = ''100-201-01''] + return $po' + passing porder as "order") + WHERE poid=5012; + +-- Cross verify the result +SELECT porder FROM purchaseorder WHERE poid=5012; + +-- ************************************************************************** +-- 3. Replace value of Expression -- i) Replace the value of an element +-- ************************************************************************** + +-- Update element values in an existing document +UPDATE purchaseorder SET porder = + xmlquery('transform + copy $po := $order + modify + for $i in $po/PurchaseOrder/item[1]//price + return do replace value of $i with $i*0.8 + return $po' + passing porder as "order") WHERE poid=5012; + +-- Cross verify the result +SELECT porder FROM purchaseorder WHERE poid=5012; + +-- ************************************************************************** +-- 3. Replace value of Expression -- ii) Replace the value of an attribute +-- ************************************************************************** + +-- Replace the value of an attribute +UPDATE purchaseorder +SET porder = + xmlquery('transform + copy $po := $order + modify do replace value of $po/PurchaseOrder/@Status with "Shipped" + return $po' + passing porder as "order") WHERE poid=5012; + +-- Cross verify the result +SELECT porder FROM purchaseorder WHERE poid=5012; + +-- ************************************************************************** +-- 4. Replace Expression -- i) Replace an element and attribute. +-- ************************************************************************** + +-- Replace an element and attribute +XQUERY for $k in db2-fn:sqlquery("SELECT porder FROM purchaseorder WHERE poid < 5002") + order by $k//@PoNum + return transform + copy $i := $k + modify (do replace $i//PurchaseOrder/@OrderDate with + ( + attribute BilledDate {"12-12-2007"} + ), + do replace $i//item[1]/price with $k//item[1]/price + ) + return $i//PurchaseOrder; + +-- Cross verify the result +SELECT porder FROM purchaseorder WHERE poid < 5002 ORDER BY poid; + +-- ************************************************************************* +-- 5. Rename Expression -- i) Rename an element. +-- *************************************************************************/ + +-- Rename the elements +UPDATE purchaseorder SET porder = + xmlquery ('transform + copy $po := $order + modify + for $i in $po//item[quantity > 1] + return do rename $i as "items" + return $po' passing porder as "order") +WHERE poid=5012; + +-- Cross verify the result +SELECT porder FROM purchaseorder WHERE poid=5012; + +-- ************************************************************************* +-- 5. Rename Expression -- ii) Rename an attribute and element. +-- *************************************************************************/ + +-- Rename an attribute, Insert a new attribute and rename an element +XQUERY for $k in db2-fn:sqlquery("SELECT porder FROM purchaseorder WHERE poid = 5004") + return transform + copy $i := $k + modify (do rename $i//*:PurchaseOrder/@OrderDate as "BilledDate", + do insert attribute Totalcost {"405.99"} + into $i//*:PurchaseOrder, + do rename $i//*:PurchaseOrder/item[2]/*:partid as "productid" + ) + return $i//*:PurchaseOrder; + + +-- ************************************************************************* +-- 6. Insert and Replace Expressions -- Combination of updating expressions. +-- *************************************************************************/ + +-- Insert and Replace Expressions +UPDATE purchaseorder SET porder = + xmlquery ('transform + copy $po := $order + modify + ( for $i in $po/PurchaseOrder/item[1]//price + return do replace value of $i with $i*0.8, + do insert document { + + 100-103-01 + Snow Shovel, Super Deluxe 26 inch + 2 + 49.99 + } + as last into $po/PurchaseOrder + ) + return $po' passing porder as "order") WHERE poid = 5012; + +-- Cross verify the result +SELECT porder FROM purchaseorder WHERE poid=5012; + +CONNECT RESET; + +TERMINATE; diff --git a/xml/xquery/java/jdbc/Flwor.java b/xml/xquery/java/jdbc/Flwor.java new file mode 100644 index 0000000..1feb346 --- /dev/null +++ b/xml/xquery/java/jdbc/Flwor.java @@ -0,0 +1,397 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Flwor.java +// +// SAMPLE: How to use XQuery FLWOR expressions +// +// SQL Statements USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// SQL/XML FUNCTIONS USED: +// xmlcolumn +// xmlquery +// +// XQuery function used: +// data +// string +// +// OUTPUT FILE: Flwor.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For information on using XQuery statements, see the XQuery Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; + +class Flwor +{ + private static int cid=1002; + private static String country="US"; + private static float price=10; + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + System.out.println(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + {} + System.exit(1); + } + catch(Exception e) + {} + System.out.println("----------------------------------------------------------------"); + System.out.println("Return customer information in alphabetical order by customer name ....."); + orderCustDetails(con); + + System.out.println("----------------------------------------------------------------"); + System.out.println("Return information for customers whose customer ID is greater than "+ cid +"....."); + conditionalCustDetails1(con, cid); + + System.out.println("----------------------------------------------------------------"); + cid=1000; + System.out.println("Return information for customers whose customer ID is greater than "+ cid +" and"); + System.out.println(" who do not live in country "+ country +"....."); + conditionalCustDetails2(con, cid, country); + + System.out.println("----------------------------------------------------------------"); + System.out.println("Select the product with maximun price......"); + maxpriceproduct(con); + + System.out.println("----------------------------------------------------------------"); + System.out.println("Select the product with basic price "+ price +"........"); + basicproduct(con, price); + } //main + + // The orderCustDetails method returns customer information in alphabetical order by customer name + static void orderCustDetails(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY "+ + "for $custinfo in db2-fn:xmlcolumn('CUSTOMER.INFO')"+ + "/customerinfo[addr/@country=\"Canada\"]"+ + " order by $custinfo/name,fn:number($custinfo/@Cid)"+ + " return $custinfo"; + System.out.println(); + System.out.println(query); + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the XQUERY statement + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as DB2 XML String + + System.out.println(); + System.out.println(data.getDB2XmlString()); + } + + // Close the result set + rs.close(); + + // Close the statement object + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // orderCustDetails + + // The conditionalCustDetails1 returns information for customers whose customer ID is greater than + // the cid value passed as an argument + static void conditionalCustDetails1(Connection con, int cid) + { + try + { + Statement stmt = con.createStatement(); + String query="select xmlquery('"+ + " for $customer in $cust/customerinfo"+ + " where ($customer/@Cid > $id)"+ + " order by $customer/@Cid "+ + " return "+ + " {$customer/name} {$customer/addr} '"+ + " passing by ref customer.info as \"cust\", cast(? as integer) as \"id\")"+ + " from customer ORDER BY cid"; + System.out.println(); + System.out.println(query); + + // Prepare the statement + PreparedStatement pstmt = con.prepareStatement(query); + + // Set the value for the parameter marker + System.out.println("Set the paramter value: "+ cid); + pstmt.setInt(1,cid); + ResultSet rs = pstmt.executeQuery(); + + // retrieve and display the result from the XQUERY statement + while (rs.next()) + { + // Retrive the data a binary stream + InputStream data=rs.getBinaryStream(1); + + System.out.println(); + + // print the result + dispValue(data); + } + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // conditionalCustDetails1 + + // The conditionalCustDetails2 method returns information for customers whose customer ID is greater than + // the cid value passed to the function and who dont live in the country + static void conditionalCustDetails2(Connection con, int cid, String country) + { + try + { + Statement stmt = con.createStatement(); + String query="select xmlquery('"+ + " for $customer in db2-fn:xmlcolumn(\"CUSTOMER.INFO\")/customerinfo"+ + " where (xs:integer($customer/@Cid) > $id) and ($customer/addr/@country !=$c)"+ + " order by $customer/@Cid "+ + " return "+ + " {$customer/name}"+ + "
{$customer/addr/street}"+ + " {$customer/addr/city}
'"+ + " passing by ref cast(? as integer) as \"id\","+ + " cast(? as varchar(10)) as \"c\")"+ + " from SYSIBM.SYSDUMMY1"; + System.out.println(); + System.out.println(query); + + // Prepare the statement + PreparedStatement pstmt = con.prepareStatement(query); + + // Set the first parameter marker + System.out.println(); + System.out.println("Set the first parameter value : "+ cid); + pstmt.setInt(1,cid); + + // Set the second parameter marker + System.out.println(); + System.out.println("Set the second parameter value: "+ country); + pstmt.setString(2,country); + ResultSet rs = pstmt.executeQuery(); + + // retrieve and display the result from the query + while (rs.next()) + { + // retrieve the data as a string object + String data= rs.getString(1); + System.out.println(); + System.out.println(data); + } + + // Close the result set + rs.close(); + + // Close the statement object + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // conditionalCustDetails2 + + // The maxpriceproduct function returns the product details with maximun price + static void maxpriceproduct(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY "+ + " let $prod := for $product in db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product/description"+ + " order by fn:number($product/price) descending return $product"+ + " return {$prod[1]/name} "; + System.out.println(); + System.out.println(query); + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the XQUERY statement + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + System.out.println(); + System.out.println(data.getDB2String()); + } + + // Close the result set + rs.close(); + + // Close the statement object + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // maxpriceproduct + + // The basicproduct function returns the product with basic attribute value true + // if the price is less then price parameter otherwiese false + static void basicproduct(Connection con, double price) + { + try + { + Statement stmt = con.createStatement(); + String query="select xmlquery('"+ + "for $prod in db2-fn:xmlcolumn(\"PRODUCT.DESCRIPTION\")/product/description"+ + " order by $prod/name "+ + " return ( if ($prod/price < $price)"+ + " then {fn:data($prod/name)}"+ + " else {fn:data($prod/name)})'"+ + " passing by ref cast(? as float) as \"price\")"+ + " from SYSIBM.SYSDUMMY1"; + System.out.println(); + System.out.println(query); + + // Prepare the statement + PreparedStatement pstmt = con.prepareStatement(query); + + // Set the parameter value + System.out.println("Set the parameter value: "+ price); + pstmt.setDouble(1,price); + ResultSet rs = pstmt.executeQuery(); + + // retrieve and display the result from the XQUERY statement + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // print the result as DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + + } + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // basicproduct + + public static void dispValue(InputStream in) + { + int size; + byte buf; + int count = 0; + try + { + size = in.available(); + byte ary[] = new byte[size]; + buf = (byte) in.read(); + while(buf!=-1) + { + ary[count] = buf; + count++; + buf = (byte) in.read(); + } + System.out.println(new String(ary)); + } + catch (Exception e) + { + System.out.println("Error occured while reading stream ... \n"); + } + } // dispValue + +} // Flwor diff --git a/xml/xquery/java/jdbc/SqlXQuery.java b/xml/xquery/java/jdbc/SqlXQuery.java new file mode 100644 index 0000000..38de23d --- /dev/null +++ b/xml/xquery/java/jdbc/SqlXQuery.java @@ -0,0 +1,378 @@ +/*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: SqlXQuery.java +// +// SAMPLE: How to run SQL/XML Queries +// +// SQL Statements USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// SQL/XML STATEMENTS USED: +// XMLQUERY +// XMLEXISTS +// +// +// OUTPUT FILE: SqlXQuery.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; + +class SqlXQuery +{ + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + String custName=null; + String partID=null; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + System.out.println(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + System.out.println("---------------------------------------------------------------------------"); + custName="Robert Shoemaker"; + System.out.println("RETURN THE FIRST ITEM IN THE PURCHASEORDER FOR THE CUSTOMER "+custName+"......"); + System.out.println(); + firstPO1(con,custName); + + System.out.println("---------------------------------------------------------------------------"); + System.out.println("RETURN THE FIRST ITEM IN THE PURCHASEORDER WHEN THE CUSTOMER IS IN SEQUENCE (X,Y,Z)"); + System.out.println(" AND CUSTOMER ID IN THE SEQUENCE (1001,1002,1003) ........"); + System.out.println(); + firstPO2(con); + + System.out.println("--------------------------------------------------------------------------"); + System.out.println("SORT THE CUSTOMERS ACCORDING TO THE NUMBER OF PURCHASEORDERS..........."); + System.out.println(); + sortCust_PO(con); + + System.out.println("---------------------------------------------------------------------------"); + partID="100-101-01"; + System.out.println("RETURN THE NUMBER OF PURCHASEORDER FOR THE CUSTOMER "+custName+" HAVING THE"); + System.out.println(" PARTID " + partID +"......"); + System.out.println(); + numPO(con, custName, partID); + + } //main + + // The firstPO1 function returns the first item in the purchase order for customer custName passed as an argument + static void firstPO1(Connection con, String custName) + { + try + { + Statement stmt = con.createStatement(); + String query="SELECT XMLQUERY('$p/PurchaseOrder/item[1]' PASSING p.porder AS \"p\")"+ + " FROM purchaseorder AS p, customer AS c"+ + " WHERE XMLEXISTS('$custinfo/customerinfo[name=$c and @Cid = $cid]'"+ + " PASSING c.info AS \"custinfo\", p.custid AS \"cid\", cast(? as varchar(20)) as \"c\")"; + + System.out.println(query); + + // Prepare the SQL/XML query + PreparedStatement pstmt = con.prepareStatement(query); + + // Set the value of parameter marker + System.out.println(); + System.out.println("Set the value of the parameter : " + custName); + pstmt.setString(1,custName); + + ResultSet rs = pstmt.executeQuery(); + + // retrieve and display the result from the SQL/XML statement + while (rs.next()) + { + // retrieve the data as character stream + java.io.Reader data= rs.getCharacterStream(1); + + // Print the result + System.out.println(); + char[] readerData=new char[500]; + data.read(readerData); + System.out.println(readerData); + + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + catch (IOException e) {System.out.println("Error Msg: "+ e.getMessage()); + e.printStackTrace();} + } // firstPO1 + + // The firstPO2 function returns the first item in the purchaseorder when + // Name is from the sequence (X,Y,Z) + // or the customer id is from the sequence (1000,1002,1003) + static void firstPO2(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="SELECT cid, XMLQUERY('$custinfo/customerinfo/name' passing c.info as \"custinfo\"),"+ + "XMLQUERY('$p/PurchaseOrder/item[1]' passing p.porder as \"p\"),"+ + "XMLQUERY('$x/history' passing c.history as \"x\")"+ + " FROM purchaseorder as p,customer as c"+ + " WHERE XMLEXISTS('$custinfo/customerinfo[name=(X,Y,Z)"+ + " or @Cid=(1000,1002,1003) and @Cid=$cid ]'"+ + " PASSING c.info AS \"custinfo\", p.custid AS \"cid\") ORDER BY cid"; + + System.out.println(query); + + // Execute the query + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the SQL/XML statement + while (rs.next()) + { + // Retrieve the customer id + int cid=rs.getInt(1); + + // Retrieve the name of the customer as a string object + String name=rs.getString(2); + + // Retrieve the first item in the purchaseorder for the customer + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(3); + + // Retrieve the history for the customer + com.ibm.db2.jcc.DB2Xml history=(com.ibm.db2.jcc.DB2Xml) rs.getObject(4); + + System.out.println(); + System.out.println(); + // Print the customer id + System.out.println("Cid:"+ cid); + + // Print the name as DB2 String + System.out.println("Name:"+ name); + + // Print the first item in the purchaseorder as DB2 XML String + System.out.println("First Item in purchaseorder : " + data.getDB2XmlString()); + + // Print the history of the customer as DB2 XML String + System.out.println("History:" + history.getDB2XmlString()); + } + + + // Close the result set and statement object + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // firstPO2 + + // The sortCust_PO function sort the customers according to the number of purchaseorders + static void sortCust_PO(Connection con) + { + try + { + int count=0; + Statement stmt = con.createStatement(); + String query="WITH count_table AS ( SELECT count(poid) as c,custid"+ + " FROM purchaseorder,customer"+ + " WHERE cid=custid group by custid )"+ + " SELECT c, xmlquery('$s/customerinfo[@Cid=$id]/name'"+ + " passing customer.info as \"s\", count_table.custid as \"id\")"+ + " FROM customer,count_table"+ + " WHERE custid=cid ORDER BY custid"; + + System.out.println(query); + + // Execute the query + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the SQL/XML statement + while (rs.next()) + { + // Retrieve the count + count = rs.getInt(1); + + // Retrieve the Customer name as a binary stream + InputStream name= rs.getBinaryStream(2); + + System.out.println(); + // Print the customer names in order of number of purchase orders + System.out.println("COUNT : " + count + " CUSTOMER : " ); + dispValue(name); + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // sortCust_PO + + // The numPO function returns the number of purchaseorder having specific partid + // for the specific customer passed as an argument to the function + static void numPO(Connection con, String name, String partId) + { + try + { + Statement stmt = con.createStatement(); + String query="WITH cid_table AS (SELECT Cid FROM customer"+ + " WHERE XMLEXISTS('$custinfo/customerinfo[name=$name]'"+ + " PASSING customer.info AS \"custinfo\", cast(? as varchar(20)) as \"name\"))"+ + " SELECT count(poid) FROM purchaseorder,cid_table"+ + " WHERE XMLEXISTS('$po/PurchaseOrder/item[partid=$id]'"+ + " PASSING purchaseorder.porder AS \"po\", cast(? as varchar(20)) as \"id\")"+ + " AND purchaseorder.custid=cid_table.cid"; + + System.out.println(query); + + // Prepare the statement + PreparedStatement pstmt = con.prepareStatement(query); + + // Set the first parameter value value + System.out.println(); + System.out.println("set the first parameter value : " + name); + pstmt.setString(1,name); + + // Set the second parameter value + System.out.println(); + System.out.println("set the second paramter value : " +partId); + pstmt.setString(2,partId); + + ResultSet rs = pstmt.executeQuery(); + + // retrieve and display the result from the SQL/XML statement + while (rs.next()) + { + int count=rs.getInt(1); + + // Print the number of purchase order + System.out.println("Number of purchase order with partid " + partId + " for customer " + name +" : " + count); + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // numPO + + public static void dispValue(InputStream in) + { + int size; + byte buf; + int count = 0; + try + { + size = in.available(); + byte ary[] = new byte[size]; + buf = (byte) in.read(); + while(buf!=-1) + { + ary[count] = buf; + count++; + buf = (byte) in.read(); + } + System.out.println(new String(ary)); + } + catch (Exception e) + { + System.out.println("Error occured while reading stream ... \n"); + } + + } // dispValue +} // SqlXQuery diff --git a/xml/xquery/java/jdbc/XPath.java b/xml/xquery/java/jdbc/XPath.java new file mode 100644 index 0000000..a581724 --- /dev/null +++ b/xml/xquery/java/jdbc/XPath.java @@ -0,0 +1,400 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XPath.java +// +// SAMPLE: How to run Queries with a simple path expression +// +// EXTERNAL DEPENDECIES: NULL +// +// SQL STATEMENTS USED: +// SELECT +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// SQL/XML STATEMENTS USED: +// xmlcolumn +// +// XQuery FUNCTIONS USED: +// distinct-values +// starts-with +// avg +// count +// +// OUTPUT FILE: XPath.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For information on using XQuery statements, see the XQuery Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; + +class XPath +{ + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + System.out.println(); + System.out.println("This sample will demonstrate how to use simple path expression in XQuery"); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + System.out.println("----------------------------------------------------------------"); + System.out.println("Select the customer information ........"); + CustomerDetails(con); + + System.out.println("------------------------------------------------------------------"); + System.out.println("Select the customer's cities from Canada ....."); + CitiesInCanada(con); + + System.out.println("-------------------------------------------------------------------"); + System.out.println("Return the name of customers whose mobile number starts with 905......."); + CustMobileNum(con); + + System.out.println("--------------------------------------------------------------------"); + System.out.println("Return the average price of all products in the 100 series....."); + AvgPrice(con); + + System.out.println("---------------------------------------------------------------------"); + System.out.println("Return the customers from Toronto......."); + CustomerFromToronto(con); + + System.out.println("--------------------------------------------------------------------"); + System.out.println("Return the number of customers from Toronto......."); + NumOfCustInToronto(con); + }// main + + //The CustomerDetails method returns all of the XML data in the INFO column of the CUSTOMER table + static void CustomerDetails(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY "+ + "for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo "+ + "order by xs:double($cust/@Cid) "+ + "return $cust"; + System.out.println(); + System.out.println(query); + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the xquery + while (rs.next()) + { + // getting the XML value in a string object + String data=rs.getString(1); + + // Print the result + System.out.println(); + System.out.println(data); + } + + // Close the result set + rs.close(); + + // Close the statement + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // CustomerDetails + + //The CitiesInCanada method returns a list of cities that are in Canada + static void CitiesInCanada(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY "+ + "for $cty in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO')"+ + "/customerinfo/addr[@country=\"Canada\"]/city) "+ + "order by $cty "+ + "return $cty"; + System.out.println(); + System.out.println(query); + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the query + while (rs.next()) + { + // retrieve the data as binary stream + InputStream data=rs.getBinaryStream(1); + + // Print the result + System.out.println(); + dispValue(data); + } + + // Close the resultset + rs.close(); + + // Close the statement + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // CitiesInCanada + + //The CustMobileNum method returns the names of customers whose mobile number starts with 905 + static void CustMobileNum(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY db2-fn:xmlcolumn(\"CUSTOMER.INFO\")"+ + "/customerinfo[phone[@type=\"cell\" and fn:starts-with(text(),\"905\")]]"; + System.out.println(); + System.out.println(query); + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the query + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as DB2 XML String + System.out.println(); + System.out.println(data.getDB2String()); + } + + // Close the result set + rs.close(); + + // Close the statement + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // CustMobileNum + + // The AvgPRice method determines the average prive of the products in the 100 series + static void AvgPrice(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY let $prod_price := db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')"+ + "/product[fn:starts-with(@pid,\"100\")]/description/price"+ + " return avg($prod_price)"; + System.out.println(); + System.out.println(query); + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the query + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as DB2 String + System.out.println(); + System.out.println(data.getDB2String()); + } + + // Close the result set + rs.close(); + + // Close the statement + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // AvgPrice + + //The CustomerFromToronto method returns information about customers from Toronto + static void CustomerFromToronto(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY "+ + "for $custinfo in db2-fn:xmlcolumn (\"CUSTOMER.INFO\")/customerinfo[addr/city=\"Toronto\"] "+ + "order by xs:double($custinfo/@Cid) "+ + "return $custinfo"; + System.out.println(); + System.out.println(query); + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the query + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as DB2 String + System.out.println(); + System.out.println(data.getDB2String()); + } + + // Close the result set + rs.close(); + + // Close the statement + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // CustomerFromToronto + + // The NumOfCustInToronto method returns the number of customer from Toronto city + static void NumOfCustInToronto(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY fn:count(db2-fn:xmlcolumn(\"CUSTOMER.INFO\")/customerinfo[addr/city=\"Toronto\"])"; + System.out.println(); + System.out.println(query); + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the query + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as DB2 String + System.out.println(); + System.out.println(data.getDB2String()); + } + + // Close the result set + rs.close(); + + // Close the statement + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // NumOfCustInToronto + public static void dispValue(InputStream in) + { + int size; + byte buf; + int count = 0; + try + { + size = in.available(); + byte ary[] = new byte[size]; + buf = (byte) in.read(); + while(buf!=-1) + { + ary[count] = buf; + count++; + buf = (byte) in.read(); + } + System.out.println(new String(ary)); + } + catch (Exception e) + { + System.out.println("Error occured while reading stream ... \n"); + } + } // dispValue +} //XPath diff --git a/xml/xquery/java/jdbc/XQuery.java b/xml/xquery/java/jdbc/XQuery.java new file mode 100644 index 0000000..d8d6d03 --- /dev/null +++ b/xml/xquery/java/jdbc/XQuery.java @@ -0,0 +1,412 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XQuery.java +// +// SAMPLE: How to run an nested XQuery and shows how to pass parameters to +// sqlquery function. +// +// XQUERY EXPRESSION USED +// FLWOR Expression +// +// JAVA 2 CLASSES USED: +// Statement +// PreparedStatement +// ResultSet +// +// +// OUTPUT FILE: XQuery.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using XQUERY statements, see the XQUERY Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; + +class XQuery +{ + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + System.out.println(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + + System.out.println("-------------------------------------------------------------"); + System.out.println("RESTRUCTURE THE PURCHASEORDERS ACCORDING TO THE CITY...."); + System.out.println(); + PO_OrderByCity(con); + + System.out.println("-------------------------------------------------------------"); + System.out.println("RESTRUCTURE THE PURCHASEORDER ACCORDING TO THE PRODUCT....."); + System.out.println(); + CustomerOrderByProduct(con); + + System.out.println("-------------------------------------------------------------"); + System.out.println("RESTRUCTURE THE PURCHASEORDER DATA ACCORDING TO PROVIENCE, CITY AND STREET.."); + System.out.println(); + PO_OrderByProvCityStreet(con); + System.out.println("-------------------------------------------------------------"); + System.out.println("COMBINE THE DATA FROM PRODUCT AND CUSTOMER TABLE TO CREATE A PURCHASEORDER.."); + CustomerPO(con); + } // main + + // The PO_OrderByCity method returns the purchaseorder city wise + static void PO_OrderByCity(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY for $city in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO')"+ + "/customerinfo/addr/city)"+ + " return"+ + " "+ + "{"+ + " for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[addr/city=$city]"+ + " let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"pos\"\","+ + " (XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", c.custid),"+ + "XMLELEMENT(NAME \"\"order\"\", c.porder)"+ + " ) ))"+ + " FROM purchaseorder AS c\")"+ + " let $id:=$cust/@Cid,"+ + " $order:=$po/pos[custid=$id]/order" + + " return"+ + " "+ + " {$cust/name}"+ + " {$cust/addr}"+ + " {$order}"+ + " }"+ + " "; + + System.out.println(query); + + // Execute the query + PreparedStatement pstmt = con.prepareStatement(query); + ResultSet rs = pstmt.executeQuery(); + + // Retrieve and display the result from the query + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + } + + System.out.println("\n\nThe following query shows how to pass parameters to "); + System.out.print(" sqlquery function which is an enhancement in Viper2"); + System.out.println("\n-------------------------------------------------\n"); + + // In Viper2 the above query can be written as follows. + query = "XQUERY "+ + "for $city in fn:distinct-values(db2-fn:xmlcolumn('CUSTOMER.INFO') /customerinfo/addr/city)"+ + "return"+ + ""+ + "{"+ + "for $cust in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo [addr/city=$city]"+ + "let $po:=db2-fn:sqlquery(\"SELECT porder FROM PURCHASEORDER "+ + "WHERE custid=parameter(1)\",$cust/@Cid),"+ + " $order:=$po/order"+ + " return"+ + " "+ + " {$cust/name}"+ + " {$cust/Addr}"+ + " {$order}"+ + " }"+ + " "; + System.out.println("\n----------------------------------"); + System.out.println(query); + System.out.println("\n----------------------------------"); + + // Execute the query + PreparedStatement pstmt1 = con.prepareStatement(query); + ResultSet rs1 = pstmt1.executeQuery(); + + // Retrieve and display the result from the query + while (rs1.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs1.getObject(1); + + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + } + + // Close the result set and statement + rs.close(); + rs1.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // PO_OrderByCity + + // This CustomerOrderByProduct function returns the purchaseorders product wise + static void CustomerOrderByProduct(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"pos\"\","+ + "( XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", c.custid),"+ + "XMLELEMENT(NAME \"\"order\"\", c.porder)"+ + " ) ))"+ + " FROM purchaseorder AS c\" )"+ + " for $partid in fn:distinct-values(db2-fn:xmlcolumn('PURCHASEORDER.PORDER')/PurchaseOrder/item/partid)"+ + " return"+ + " "+ + " "+ + " {"+ + " for $id in fn:distinct-values($po[order/PurchaseOrder/item/partid=$partid]/custid)"+ + " let $order:="+ + " {fn:sum($po[custid=$id]/order/PurchaseOrder/item[partid=$partid]/quantity)}"+ + " ,"+ + " $cust:=db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo[@Cid=$id]"+ + " return"+ + " "+ + " {$order}"+ + " {$cust}"+ + " "+ + " }"+ + " "+ + ""; + + System.out.println(query); + System.out.println(); + + // Execute the query + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the XQuert statement + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as an DB2 XML string + System.out.println(); + System.out.println(data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // CustomerOrderByProduct + + + // This PO_OrderByProvCityStreet function returns the purchaseorder province, city and stree wise + static void PO_OrderByProvCityStreet(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY let $po:=db2-fn:sqlquery(\"SELECT XMLELEMENT( NAME \"\"pos\"\","+ + "( XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", c.custid),"+ + "XMLELEMENT(NAME \"\"order\"\", c.porder)"+ + ") ))"+ + " FROM PURCHASEORDER as c\"),"+ + " $addr:=db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/addr"+ + " for $prov in distinct-values($addr/prov-state)"+ + " return"+ + " "+ + " {"+ + " for $city in fn:distinct-values($addr[prov-state=$prov]/city)"+ + " return"+ + " "+ + " {"+ + " for $s in fn:distinct-values($addr/street) where $addr/city=$city"+ + " return"+ + " "+ + " {"+ + " for $info in $addr[prov-state=$prov and city=$city and street=$s]/.."+ + " return"+ + " "+ + " {$info/name}"+ + " {"+ + " let $id:=$info/@Cid, $order:=$po[custid=$id]/order"+ + " return $order"+ + " }"+ + " "+ + " }"+ + " "+ + " }"+ + " "+ + " }"+ + " "; + + System.out.println(query); + + // Execute the query + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the XQuert statement + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as an DB2 XML String + System.out.println(data.getDB2XmlString()); + + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } + + // The CustomerPO function creates the purchaseorder XML document + static void CustomerPO(Connection con) + { + try + { + Statement stmt = con.createStatement(); + String query="XQUERY "+ + "{"+ + " for $ns1_customerinfo0 in db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo"+ + " where ($ns1_customerinfo0/@Cid=1001)"+ + " return"+ + " "+ + " {$ns1_customerinfo0/name}"+ + "
"+ + " {$ns1_customerinfo0/addr/street}"+ + " {$ns1_customerinfo0/addr/city}"+ + " {"+ + " if($ns1_customerinfo0/addr/@country=\"US\")"+ + " then"+ + " $ns1_customerinfo0/addr/prov-state"+ + " else()"+ + " }"+ + " {"+ + " fn:concat ($ns1_customerinfo0/addr/pcode-zip/text(),\",\",fn:upper-case($ns1_customerinfo0/addr/@country))}"+ + "
"+ + "
"+ + " }"+ + " {"+ + " for $ns2_product0 in db2-fn:xmlcolumn('PRODUCT.DESCRIPTION')/product"+ + " where ($ns2_product0/@pid=\"100-100-01\")"+ + " return"+ + " $ns2_product0"+ + " }"+ + "
"; + + System.out.println(query); + System.out.println(); + + // Execute the query + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the XQuert statement + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as an DB2 XML string + System.out.println(); + System.out.println(data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + + } +} // XQuery diff --git a/xml/xquery/java/jdbc/XQueryParam.java b/xml/xquery/java/jdbc/XQueryParam.java new file mode 100644 index 0000000..82d9efd --- /dev/null +++ b/xml/xquery/java/jdbc/XQueryParam.java @@ -0,0 +1,435 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SAMPLE FILE NAME: XQueryParam.java +// +// PURPOSE: This sample shows how to pass parameters to db2-fn:sqlquery +// function. +// +// USAGE SCENARIO: The super market manager maintains database with +// "employee" and "dept_location" tables. "Employee" table +// contains employee ID and employee address. +// "dept_location" table contains the department and +// and it's location details.He will query +// these tables to get information about employees and +// their department details. +// The last XQuery exprepression in this sample shows +// purchaseorder details from the sample database +// purchaseorder table. +// +// PREREQUISITE: NONE +// +// EXECUTION: javac XQuerypParam.java +// java XQueryParam +// +// INPUTS: NONE +// +// OUTPUTS: Queries will display the results. +// +// OUTPUT FILE: XQueryParam.out (available in the online documentation) +// +// +// SQL STATEMENTS USED: +// CREATE TABLE +// INSERT +// DROP +// +// SQL/XML FUNCTIONS USED: +// SQLQUERY +// XMLCOLUMN +// +// +//*************************************************************************** +// For more information about the command line processor (CLP) scripts, +// see the README file. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, building, and running DB2 +// applications, visit the DB2 application development website: +// http://www.software.ibm.com/data/db2/udb/ad +// +//*************************************************************************** +// SAMPLE DESCRIPTION +// +//*************************************************************************** +// 1. Passing single parameter to SQL fullselect in db2-fn:sqlquery function. +// +// 2. Passing multiple parameters to SQL fullselect in db2-fn:sqlquery +// function. +// +//*************************************************************************** + + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; + +class XQueryParam +{ + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + System.out.println(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + System.out.println("This sample shows how to pass parameters to "); + System.out.println(" sqlquery function"); + System.out.println("--------------------------------------------"); + System.out.println(); + + createTables(con); + passSingleParam(con); + passTwoParams(con); + cleanup(con); + + } //main + + static void createTables(Connection con) + { + Statement stmt = null; + + try + { + stmt = con.createStatement(); + String str = "CREATE TABLE employee(empid int, addr XML)"; + System.out.println(str); + System.out.println(); + + stmt.executeUpdate(str); + + str = "CREATE TABLE dept_location(dept_name varchar(20),"+ + " branch_name varchar(50),"+ + " block_no varchar(20), street "+ + " varchar(20), city varchar(20), "+ + " zip_code varchar(20), "+ + " dept_details XML)"; + + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + str = "INSERT INTO dept_location "+ + "VALUES ('DB2', 'EGL', 'B', 'Koramangala', 'Bangalore', '500042',"+ + "XMLPARSE(document "+ + "'"+ + "Peter suzanski"+ + ""+ + "Samples"+ + "testing"+ + "Development"+ + ""+ + "140"+ + "' ))"; + + System.out.println(str); + System.out.println(); + + stmt.executeUpdate(str); + + str ="INSERT INTO dept_location "+ + "VALUES ('Informix','MANYATA', 'D2', 'Hebbal', 'Bangalore', '500067',"+ + "XMLPARSE(document"+ + "'"+ + "Jeff "+ + ""+ + "bird"+ + "QA"+ + ""+ + "60"+ + "' ))"; + + System.out.println(str); + System.out.println(); + + stmt.executeUpdate(str); + + str = "INSERT INTO employee "+ + "VALUES (1005, XMLPARSE(document "+ + "'"+ + "Ravi varma "+ + " "+ + "Koramangala "+ + "Bangalore"+ + "Karnataka"+ + "500042"+ + ""+ + "'))"; + System.out.println(str); + System.out.println(); + + stmt.executeUpdate(str); + + str = "INSERT INTO employee "+ + "VALUES (1006, XMLPARSE(document "+ + "'"+ + "Oswal Menard"+ + ""+ + "Hebbal"+ + "Bangalore"+ + "Karnataka"+ + "500067"+ + ""+ + "'))"; + System.out.println(str); + System.out.println(); + stmt.executeUpdate(str); + + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //createTables + + //-------------------------------------------------------------------------- + // 1. Passing single parameter to SQL fullselect in db2-fn:sqlquery function. + //-------------------------------------------------------------------------- + + static void passSingleParam(Connection con) + { + try + { + System.out.println("The following XQuery expression returns an "); + System.out.println("employee's postal code and department details "); + System.out.println("when the employee and the department are in same "); + System.out.println("location (defined by zip code)"); + System.out.println(); + + String str = "XQUERY "+ + "declare default element namespace \"http://posample.org\";"+ + "for $pcode in db2-fn:xmlcolumn(\"EMPLOYEE.ADDR\")"+ + "/employeeinfo/addr/pcode-zip "+ + "for $deptinfo in db2-fn:sqlquery( "+ + "\"SELECT dept_details FROM dept_location "+ + "WHERE zip_code = parameter(1)\", $pcode)"+ + "return "+ + "{$pcode, $deptinfo }"; + System.out.println(str); + System.out.println(); + + PreparedStatement pstmt = con.prepareStatement(str); + ResultSet rs = pstmt.executeQuery(); + + System.out.println("-------------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + } + System.out.println("-------------------------------------------------"); + + rs.close(); + pstmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //passSingleParam + + //------------------------------------------------------------------------------ + // 2. Passing multiple parameters to SQL fullselect in db2-fn:sqlquery + // function. + //------------------------------------------------------------------------- + + static void passTwoParams(Connection con) + { + try + { + System.out.println("The following XQuery expression returns an employee's"); + System.out.println(" postal code,department name and department details,"); + System.out.println(" when an employee and a department are in same "); + System.out.println(" location, and the employee belongs to one of the "); + System.out.println(" following departments: DB2, Informix or CM."); + System.out.println(); + + String str = "XQUERY "+ + "declare default element namespace \"http://posample.org\";"+ + "for $pcode in db2-fn:xmlcolumn(\"EMPLOYEE.ADDR\")"+ + "/employeeinfo/addr/pcode-zip,"+ + "$dept in ('DB2', 'Informix', 'CM')"+ + "for $deptinfo in db2-fn:sqlquery("+ + "\"SELECT dept_details FROM dept_location "+ + "WHERE zip_code = parameter(1) and dept_name = parameter(2)\","+ + " $pcode, $dept) "+ + "return "+ + ""+ + "{$pcode}"+ + "{$dept}"+ + "{$deptinfo}"+ + ""; + System.out.println(str); + System.out.println(); + + PreparedStatement pstmt = con.prepareStatement(str); + ResultSet rs = pstmt.executeQuery(); + + System.out.println("-------------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + } + System.out.println("-------------------------------------------------"); + + System.out.println("The following XQuery expression uses the purchase"); + System.out.println("order table from the sample database."); + + System.out.println("The XQuery expression returns all purchase orders "); + System.out.println(" made by customers after date \"2005-11-18\"."); + System.out.println(); + + str = "XQUERY "+ + "for $ponum in db2-fn:xmlcolumn(\"PURCHASEORDER.PORDER\")"+ + "/PurchaseOrder/@PoNum "+ + "for $x in db2-fn:sqlquery(\"SELECT porder FROM purchaseorder "+ + "WHERE OrderDate > parameter(1) and poid = parameter(2)\","+ + " '2005-11-18', $ponum) "+ + "return "+ + " {$x} "; + System.out.println(str); + System.out.println(); + + PreparedStatement pstmt1 = con.prepareStatement(str); + rs = pstmt1.executeQuery(); + System.out.println("-------------------------------------------------"); + while (rs.next()) + { + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + // Print the result as an DB2 XML String + System.out.println(); + System.out.println(data.getDB2XmlString()); + } + System.out.println("-------------------------------------------------"); + + rs.close(); + pstmt.close(); + pstmt1.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //passTwoParams + + static void cleanup(Connection con) + { + Statement stmt = null; + try + { + stmt = con.createStatement(); + String str = "DROP TABLE employee"; + System.out.println(str); + System.out.println(); + + stmt.executeUpdate(str); + + str = "DROP TABLE dept_location"; + System.out.println(str); + System.out.println(); + + stmt.executeUpdate(str); + + stmt.close(); + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //cleanup +} //XQueryParam diff --git a/xml/xquery/java/jdbc/XUpdate.java b/xml/xquery/java/jdbc/XUpdate.java new file mode 100644 index 0000000..8143d8e --- /dev/null +++ b/xml/xquery/java/jdbc/XUpdate.java @@ -0,0 +1,483 @@ +///************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +// ************************************************************************* +// +// SAMPLE FILE NAME: XUpdate.java +// +// PURPOSE: To demonstrate how to insert, delete, update, replace, and rename +// one or more XML documents or document fragments using transform +// expressions. +// +// USAGE SCENARIO: The orders made by customers are stored in the existing +// PurchaseOrder system. A customer has ordered some items initially, +// and now the customer wants to add some more items and remove some +// items from the list. This sample will show how the order is modified +// using the XQuery transform expression and updating expressions. +// +// PREREQUISITE: NONE +// +// EXECUTION: javac XUpdate.java (Compile the sample) +// java XUpdate (Run the sample) +// +// INPUTS: NONE +// +// OUTPUTS: Successful updation of the purchase orders. +// +// OUTPUT FILE: XUpdate.out (available in the online documentation) +// +// SQL STATEMENTS USED: +// INSERT +// UPDATE +// DROP +// +// SQL/XML FUNCTIONS USED: +// XMLQUERY +// +// ************************************************************************* +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +// ************************************************************************* +// +// SAMPLE DESCRIPTION +// +// ************************************************************************* +// 1. Insert Expression -- Insert a new element to the existing XML document/fragment. +// 2. Delete Expression -- Delete some elements from the exisitng XML document/fragment. +// 3. Replace value of Expression -- i) Replace the value of an element +// ii) Replace the value of attribute +// 4. Replace Expression -- Replace an element and attribute +// 5. Rename Expression -- i) Rename an element in the existing XML document/fragment. +// ii) Rename an attribute in the existing XML document/fragment. +// 6. Insert and Replace Expressions -- Combination of transform expressions. +// *************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; + +class XUpdate +{ + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + String custName=null; + String partID=null; + Connection con=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + System.out.println(); + + } + catch (SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + System.out.println("-----------------------------------------------------------------------"); + System.out.println("Insert Expression -- Insert a new element to the existing XML document/fragment."); + System.out.println("-----------------------------------------------------------------------"); + System.out.println(); + insertExpr(con); + + System.out.println("-----------------------------------------------------------------------"); + System.out.println("Delete Expression -- Delete some items from the exisitng XML document/fragment."); + System.out.println("-----------------------------------------------------------------------"); + System.out.println(); + deleteExpr(con); + + System.out.println("-----------------------------------------------------------------------"); + System.out.println("Replace Expression -- Replace/replace value of an element/attribute of an XML document/fragment."); + System.out.println("-----------------------------------------------------------------------"); + System.out.println(); + replaceExpr(con); + + System.out.println("-----------------------------------------------------------------------"); + System.out.println("Rename Expression -- Rename an element/attribute of an XML document/fragment."); + System.out.println("-----------------------------------------------------------------------"); + System.out.println(); + renameExpr(con); + + System.out.println("-----------------------------------------------------------------------"); + System.out.println("Insert and Replace Expressions -- Combination of transform expressions."); + System.out.println("-----------------------------------------------------------------------"); + System.out.println(); + combinationExpr(con); + + } //main + + static void insertExpr(Connection con) + { + try + { + Statement stmt = con.createStatement(); + + // Insert an item into the XML document as last child of the PurchaseOrder + String query="SELECT xmlquery('transform copy $po := $order modify do insert document { 100-103-01 Snow Shovel, Super Deluxe 26 inch 2 49.99 } as last into $po return $po' passing purchaseorder.porder as \"order\") from purchaseorder where poid=5004"; + + System.out.println("Query: \n" + query); + + // Execute the query + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result from the SQL/XML statement + while (rs.next()) + { + // Retrieve the result of purchase order + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + System.out.println(); + + // Print the purchaseorder as DB2 XML String + System.out.println("Data after inserting Item :\n" + data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // insertExpr + +static void deleteExpr(Connection con) + { + try + { + + // Delete an item from the PurchaseOrder + String query = "UPDATE purchaseorder SET porder = xmlquery('transform copy $po := $order modify do delete $po/PurchaseOrder/item[partid = ''100-201-01''] return $po' passing porder as \"order\") WHERE poid=5004"; + + System.out.println("Query: \n" + query); + // Execute the query + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate(query); + + // retrieve and display the result + stmt1 = con.createStatement(); + query = "SELECT porder FROM purchaseorder WHERE poid=5004"; + ResultSet rs = stmt1.executeQuery(query); + + while (rs.next()) + { + // Retrieve the result of purchase order + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + System.out.println(); + + // Print the purchaseorder as DB2 XML String + System.out.println("Data after Deleting an Item : \n" + data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt1.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // deleteExpr + +static void replaceExpr(Connection con) + { + try + { + System.out.println("------------------------------------------------------"); + System.out.println("Replace value of an element..."); + System.out.println("------------------------------------------------------"); + + // Replace value of an element + String query = "UPDATE purchaseorder SET porder = xmlquery('transform copy $po := $order modify for $i in $po/PurchaseOrder/item[1]//price return do replace value of $i with $i*0.8 return $po' passing porder as \"order\") WHERE poid > 5004"; + System.out.println("Query: \n" + query); + + // Execute the query + Statement stmt1 = con.createStatement(); + stmt1.executeUpdate(query); + + stmt1 = con.createStatement(); + query = "SELECT porder FROM purchaseorder WHERE poid > 5004"; + ResultSet rs = stmt1.executeQuery(query); + + System.out.println("Data after replacing value of an element : "); + + // retrieve and display the result + while (rs.next()) + { + // Retrieve the result of purchase order + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + System.out.println(); + // Print the purchaseorder as DB2 XML String + System.out.println(data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt1.close(); + + System.out.println("------------------------------------------------------"); + System.out.println("Replace value of an attribute..."); + System.out.println("------------------------------------------------------"); + + // Replace value of an attribute + query = "UPDATE purchaseorder SET porder = xmlquery('transform copy $po := $order modify do replace value of $po/PurchaseOrder/@Status with \"Shipped\" return $po' passing porder as \"order\") WHERE poid < 5002"; + + System.out.println("Query: \n" + query); + + // Execute the query + stmt1 = con.createStatement(); + stmt1.executeUpdate(query); + + stmt1 = con.createStatement(); + query = "SELECT porder FROM purchaseorder WHERE poid < 5002"; + rs = stmt1.executeQuery(query); + + System.out.println("Data after replacing value of an attribute : "); + // retrieve and display the result + while (rs.next()) + { + // Retrieve the result of purchase order + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + System.out.println(); + + // Print the purchaseorder as DB2 XML String + System.out.println(data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt1.close(); + + System.out.println("------------------------------------------------------"); + System.out.println("Replace an element and attribute..."); + System.out.println("------------------------------------------------------"); + + // Replace an element and attribute + query = "XQUERY for $k in db2-fn:sqlquery(\"select porder from purchaseorder where poid = 5004\") return transform copy $i := $k modify (do replace $i//PurchaseOrder/@OrderDate with ( attribute BilledDate {\"12-12-2007\"}), do replace $i//item[1]/price with $k//item[1]/price) return $i//PurchaseOrder"; + + System.out.println("Query: \n" + query); + + stmt1 = con.createStatement(); + rs = stmt1.executeQuery(query); + System.out.println("Data after replacing an element and attribute : "); + + // retrieve and display the result + while (rs.next()) + { + // Retrieve the result of purchase order + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + System.out.println(); + + // Print the purchaseorder as DB2 XML String + System.out.println(data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt1.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // replaceExpr + +static void renameExpr(Connection con) + { + try + { + + System.out.println("------------------------------------------------------"); + System.out.println("Rename an element..."); + System.out.println("------------------------------------------------------"); + + // Rename an element + String query = "UPDATE purchaseorder SET porder = xmlquery('transform copy $po := $order modify for $i in $po//item[quantity > 1] return do rename $i as \"items\" return $po' passing porder as \"order\") WHERE poid=5002"; + + System.out.println("Query: \n" + query); + + // Execute the query + Statement stmt = con.createStatement(); + stmt.executeUpdate(query); + + stmt = con.createStatement(); + query = "SELECT porder FROM purchaseorder WHERE poid=5002"; + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result + while (rs.next()) + { + // Retrieve the result of purchase order + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + System.out.println(); + + // Peint the purchaseorder as DB2 XML String + System.out.println("Data after renaming an element : \n " + data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + + System.out.println("------------------------------------------------------"); + System.out.println("Rename an attribute, insert a new attribute and rename an element..."); System.out.println("------------------------------------------------------"); + + // Rename an attribute, Insert a new attribute and rename an element + query = "XQUERY for $k in db2-fn:sqlquery(\"select porder from purchaseorder where poid=5003\") return transform copy $i := $k modify (do rename $i//*:PurchaseOrder/@OrderDate as \"BilledDate\", do insert attribute Totalcost {\"405.99\"} into $i//*:PurchaseOrder, do rename $i//*:PurchaseOrder//*:partid as \"productid\") return $i//*:PurchaseOrder"; + + System.out.println("Query: \n" + query); + + stmt = con.createStatement(); + rs = stmt.executeQuery(query); + + System.out.println("Data after rename element and attribute : "); + + // retrieve and display the result + while (rs.next()) + { + // Retrieve the result of purchase order + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + System.out.println(); + + // Print the purchaseorder as DB2 XML String + System.out.println(data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // renameExpr + + +static void combinationExpr(Connection con) + { + try + { + + // Insert and Replace Expressions + String query = " UPDATE purchaseorder SET porder = xmlquery ('transform copy $po := $order modify ( for $i in $po/PurchaseOrder/item[1]//price return do replace value of $i with $i*0.8, do insert document { 100-103-01 Snow Shovel, Super Deluxe 26 inch 2 49.99 } as last into $po/PurchaseOrder) return $po' passing porder as \"order\") WHERE poid = 5004 "; + + System.out.println("Query: \n" + query); + + // Execute the query + Statement stmt = con.createStatement(); + stmt.executeUpdate(query); + + stmt = con.createStatement(); + query = "SELECT porder FROM purchaseorder WHERE poid=5004"; + ResultSet rs = stmt.executeQuery(query); + + // retrieve and display the result + while (rs.next()) + { + // Retrieve the result of purchase order + com.ibm.db2.jcc.DB2Xml data=(com.ibm.db2.jcc.DB2Xml) rs.getObject(1); + + System.out.println(); + + // Print the purchaseorder as DB2 XML String + System.out.println("Data after insert and replace: \n" + data.getDB2XmlString()); + } + + // Close the result set and statement object + rs.close(); + stmt.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { con.rollback(); } + catch (Exception e) {} + System.exit(1); + } + } // combinationExpr + +} // XUpdate + diff --git a/xml/xquery/java/jdbc/Xquery_XmlProc.java b/xml/xquery/java/jdbc/Xquery_XmlProc.java new file mode 100644 index 0000000..08840ab --- /dev/null +++ b/xml/xquery/java/jdbc/Xquery_XmlProc.java @@ -0,0 +1,292 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: Xquery_XmlProc.java +// +// SAMPLE: Code implementation of stored procedure Supp_XML_Proc_Java +// The stored procedures defined in this program are called by the +// client application Xquery_XmlProc_Client.java. Before building and +// running Xquery_XmlProc_Client.java, build the shared library by +// completing the following steps: +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file Xquery_XmlProc.java (this will +// also erase the existing library/class files and copy the newly +// compiled class files, Xquery_XmlProc.class, from the current +// directory to the $(DB2PATH)\function directory): +// nmake/make Xquery_XmlProc +// 2. Compile the client source file Xquery_XmlProc_Client.java (this +// will also call the script 'spcat_xquery' to create and catalog +// the stored procedures): +// nmake/make Xquery_XmlProc_Client +// 3. Run the client Xquery_XmlProc_Client: +// java Xquery_XmlProc_Client +// +// II) If you don't have a compatible make/nmake program on your +// system do the following: +// 1. Compile the server source file with: +// javac Xquery_XmlProc.java +// 2. Erase the existing library/class files (if exists), +// Xquery_XmlProc.class from the following path, +// $(DB2PATH)\function. +// 3. Copy the class files, Xquery_XmlProc.class from the current +// directory to the $(DB2PATH)\function. +// 4. Catalog the stored procedures in the database with the script: +// spcat_xquery +// 5. Compile Xquery_XmlProc_Client with: +// javac Xquery_XmlProc_Client.java +// 6. Run Xquery_XmlProc_Client with: +// java Xquery_XmlProc_Client +// +// Class Xquery_XmlProc contains one method which solves the following scenario: +// Some of the suppliers have extended the promotional price date for +// their products. Getting all the customer's Information who purchased +// these products in the extended period will help the financial department +// to return the excess amount paid by those customers. The supplier +// information along with extended date's for the products is provided +// in an XML document and the client wants to have the information +// of all the customers who has paid the excess amount by purchasing those +// products in the extended period. +// +// This procedure will return an XML document containing customer info +// along with the the excess amount paid by them. +// +// SQL Statements USED: +// CREATE +// SELECT +// INSERT +// +// OUTPUT FILE: Xquery_XmlProc_Client.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.sql.*; // JDBC classes +import java.io.*; // Input/Output classes +import java.lang.*; // for String class +import COM.ibm.db2.app.StoredProc; // Stored Proc classes +import com.ibm.db2.jcc.DB2Xml; // XML classes +import COM.ibm.db2.app.Clob; // CLOB classes +import java.math.BigDecimal; // Basic Arithmetic + +// Java stored procedure in this class +public class Xquery_XmlProc extends StoredProc +{ + + Connection con; + public void Xquery_Proc ( com.ibm.db2.jcc.DB2Xml inXML, + com.ibm.db2.jcc.DB2Xml outXML, + int retcode ) + throws Exception + { + String prodid = null ; + java.sql.Date oldPromoDate = null; + com.ibm.db2.jcc.DB2Xml orders = null; + com.ibm.db2.jcc.DB2Xml tempXML = null; + java.sql.Date newPromoDate = null; + float originalPrice =0; + float promoPrice =0; + long custid=0; + String partid = null; + int quantity=0; + float excessamount =0; + String sql =null; + + // get caller's connection to the database + con = DriverManager.getConnection("jdbc:default:connection"); + + // get the input XML document into an application variable + String ipdata = inXML.getDB2String() ; + + // an XQUERY statement to restructure all the PurchaseOrders + // into the following form + // + // + // XXXX + // XXX-XXX-XX + // XX + // ............................... + // ................. + // store the above XML document in an application varible "orders" + + String query1 = "XQUERY let $po:=db2-fn:sqlquery( \"SELECT XMLELEMENT( NAME \"\"porders\"\", " + + "( XMLCONCAT( XMLELEMENT(NAME \"\"custid\"\", p.custid), p.porder) )) " + + " FROM PURCHASEORDER as p\") return {for $i in $po, $j in " + + " $po[custid=$i/custid]/PurchaseOrder[@PoNum=$i/PurchaseOrder/@PoNum]/item " + + " return {$i/PurchaseOrder/@OrderDate}{$i/custid}{$j/partid}" + + " {$j/quantity}}"; + + PreparedStatement stmt1 = con.prepareStatement(query1); + ResultSet rs1 = stmt1.executeQuery(); + + if(rs1.next()) + { + orders = (DB2Xml) rs1.getObject(1) ; + } + String temporders=orders.getDB2XmlString(); + rs1.close() ; + stmt1.close(); + + // select the oldpromodate, newpromodate, price and promoprice + // for the products for which the promodate is extended + // using input XML document + + String query2 = "SELECT Pid,PromoEnd,Price,PromoPrice,XMLCAST(XMLQUERY(" + + "'$info/Suppliers/Supplier/Products/Product[@id=$pid]/ExtendedDate' " + + "passing cast(? as XML) as \"info\", pid as \"pid\") as DATE) FROM " + + "product WHERE XMLEXISTS('for $prod in $info//Product[@id=$pid] " + + "return $prod' passing by ref cast(? as XML) as \"info\", pid as \"pid\")"; + + PreparedStatement stmt2 = con.prepareStatement(query2); + stmt2.setString (1, ipdata); + stmt2.setString (2, ipdata); + ResultSet rs2 = stmt2.executeQuery(); + + // create two temporary tables to store intermediate results + Statement create1 = con.createStatement(); + create1.executeUpdate( "CREATE TABLE temp_table1(custid INT,partid VARCHAR(12)," + + "excessamount DECIMAL(30,2))"); + create1.close(); + Statement create2 = con.createStatement(); + create2.executeUpdate( "CREATE TABLE temp_table2(cid INT,total DECIMAL(30,2))"); + create2.close(); + + // repeat the above for all products + while(rs2.next()) + { + prodid = rs2.getString(1); + oldPromoDate = rs2.getDate(2); + originalPrice = rs2.getFloat(3); + promoPrice = rs2.getFloat(4); + newPromoDate = rs2.getDate(5); + + // finding out the toatal quantity of the product purchased by a customer + // if that order is made in between oldpromodate and extended promodate. + // this query will return the custid, product id and total quantity of + // that product purchased in all his orders. + String query3 = "WITH temp1 AS (SELECT cid,partid,quantity,orderdate " + + "FROM XMLTABLE('$od//item' passing cast(? as XML)" + + " as \"od\" COLUMNS cid BIGINT path './custid', partid VARCHAR(20)" + + "path './partid', orderdate DATE path './@OrderDate',quantity BIGINT" + + " path './quantity') as temp2) SELECT temp1.cid, temp1.partid, " + + "sum(temp1.quantity) as quantity FROM temp1 WHERE partid=? and " + + "orderdate>cast(? as DATE) and orderdate + // + // XXXX + // XXXX.XXXX + // + // xxxx xxx + // ......... + // + // + // ............ + // + + String query4 = "XQUERY let $res:=db2-fn:sqlquery(\"SELECT XMLELEMENT( " + + "NAME \"\"Customer\"\",( XMLCONCAT(XMLELEMENT(NAME \"\"Custid\"\", " + + "t.cid),XMLELEMENT( NAME \"\"Total\"\", t.total),c.info))) FROM " + + "temp_table2 AS t,customer AS c WHERE t.cid = c.cid\") " + + "return {$res}"; + + PreparedStatement stmt6 = con.prepareStatement(query4); + ResultSet rs4 = stmt6.executeQuery(); + if(rs4.next()) + { + tempXML = (DB2Xml) rs4.getObject(1) ; + } + // assign the result XML document to parameters + set( 2, tempXML); + + rs4.close() ; + stmt6.close(); + + //drop the temporary tables + Statement drop1 = con.createStatement(); + drop1.executeUpdate( "DROP TABLE temp_table1"); + drop1.close(); + Statement drop2 = con.createStatement(); + drop2.executeUpdate( "DROP TABLE temp_table2"); + drop2.close(); + + set( 3, 0); + con.close(); + + return ; + } +} + diff --git a/xml/xquery/java/jdbc/Xquery_XmlProc_Client.java b/xml/xquery/java/jdbc/Xquery_XmlProc_Client.java new file mode 100644 index 0000000..b60c52d --- /dev/null +++ b/xml/xquery/java/jdbc/Xquery_XmlProc_Client.java @@ -0,0 +1,204 @@ +//************************************************************************* +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//************************************************************************* +// +// SOURCE FILE NAME: Xquery_XmlProc_Client.java +// +// SAMPLE: Call the stored procedure implemented in Xquery_XmlProc.java +// +// Steps to run the sample with command line window: +// I) If you have a compatible make/nmake program on your system, +// do the following: +// 1. Compile the server source file Xquery_XmlProc.java, +// erase the existing library/class files and copy the newly +// compiled class files, Xquery_XmlProc.class, from the current +// directory to the $(DB2PATH)\function directory): +// nmake/make Xquery_XmlProc +// 2. Compile the client source file Xquery_XmlProc_Client.java (this +// will also call the script 'spcat_xquery' to create and catalog +// the stored procedures): +// nmake/make Xquery_XmlProc_Client +// 3. Run the client Xquery_XmlProc_Client: +// java Xquery_XmlProc_Client +// +// II) If you don't have a compatible make/nmake program on your +// system do the following: +// 1. Compile the server source file with: +// javac Xquery_XmlProc.java +// 2. Erase the existing library/class files (if exists), +// Xquery_XmlProc.class from the following path, +// $(DB2PATH)\function. +// 3. Copy the class files, Xquery_XmlProc.class from the current +// directory to the $(DB2PATH)\function. +// 4. Catalog the stored procedures in the database with: +// spcat_xquery +// 5. Compile Xquery_XmlProc_Client with: +// javac Xquery_XmlProc_Client.java +// 6. Run Xquery_XmlProc_Client with: +// java Xquery_XmlProc_Client +// +// Xquery_XmlProc_Client calls callSupp_XML_Proc_Java method that calls the +// stored procedure: callSupp_XML_Proc_Java. +// Calls a stored procedure that accepts an XML document with extended +// promodate for the products and returns another XML document +// with Customer Information and excess amount paid by them. +// Parameter types used: IN XML AS CLOB(5000) +// OUT XML AS CLOB(5000) +// OUT INTEGER +// SQL Statements USED: +// CALL +// +// OUTPUT FILE: Xquery_XmlProc_Client.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//************************************************************************* +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; // for String class +import java.io.*; // for ...Stream classes +import COM.ibm.db2.app.StoredProc; // Stored Proc classes +import java.sql.*; // for JDBC classes +import com.ibm.db2.jcc.*; // for XML class +import COM.ibm.db2.app.Clob; // for CLOB class +import java.util.*; // Utility classes + +class Xquery_XmlProc_Client +{ + + public static void main(String argv[]) + { + Connection con = null; + // connect to sample database + String url = "jdbc:db2:sample"; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + } + catch (Exception e) + { + System.out.println(" Error loading DB2 Driver...\n"); + System.out.println(e); + System.exit(1); + } + try + { + con = DriverManager.getConnection(url); + con.setAutoCommit(false); + } + catch (SQLException e) + { + System.out.println("Connection to sample db can't be established."); + System.err.println(e) ; + System.exit(1); + } + + // call the procedure to call stored procedure + callSupp_XML_Proc_Java(con); + + return ; + } // end main + + // callSupp_XML_Proc_Java procedure to call the stored procedure + public static void callSupp_XML_Proc_Java(Connection con) + { + try + { + // prepare the CALL statement + String procName = "Supp_XML_Proc_Java"; + String sql = "CALL " + procName + "( ?, ?, ?)"; + + CallableStatement callStmt = con.prepareCall(sql); + + // input data + String inXml = " " + + "" + + " 2007-01-02 2007-02-02" + + " " + + " 2007-03-22" + + " "; + + callStmt.setString (1, inXml ) ; + + // register the output parameter + callStmt.registerOutParameter(2, com.ibm.db2.jcc.DB2Types.XML); + callStmt.registerOutParameter(3, Types.INTEGER); + + // call the stored procedure + System.out.println(); + System.out.println("Calling stored procedure " + procName); + System.out.println( procName +"(" ) ; + System.out.println(" "+ inXml + "," ) ; + System.out.println( " ?, ?)" ) ; + + callStmt.execute(); + + // retrieve output parameters + com.ibm.db2.jcc.DB2Xml outXML = (DB2Xml) callStmt.getObject(2); + + System.out.println(procName + " completed successfully"); + System.out.println("\n \n Customers Information " + " : " + + outXML.getDB2String()); + int retcode = callStmt.getInt(3); + System.out.println("\n \n Return code " + " : " + + retcode ); + + // Rollback the transactions to keep database consistent + System.out.println("\n \n --Rollback the transaction-----"); + con.rollback(); + System.out.println(" Rollback done!"); + + // clean up resources + callStmt.close(); + + } + catch (SQLException e) + { + System.out.println(e.getMessage()); + System.out.println(); + + if (con != null) + { + try + { + System.out.println("--Rollback the transaction-----"); + con.rollback(); + System.out.println(" Rollback done!"); + } + catch (Exception error ) + { + } + } + System.out.println("--FAILED----"); + } + + return ; + } +} + diff --git a/xml/xquery/java/jdbc/Xquery_XmlProc_Create.db2 b/xml/xquery/java/jdbc/Xquery_XmlProc_Create.db2 new file mode 100644 index 0000000..2ae1b3e --- /dev/null +++ b/xml/xquery/java/jdbc/Xquery_XmlProc_Create.db2 @@ -0,0 +1,47 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: Xquery_XmlProc_Create.db2 +-- +-- SAMPLE: How to catalog the stored procedure contained in Xquery_XmlProc.java +-- +-- To run this script from the CLP, +-- issue the command "db2 -td@ -vf Xquery_XmlProc_Create.db2" +---------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- create the procedure +CREATE PROCEDURE Supp_XML_Proc_Java( IN data XML as CLOB(5000), + OUT CustInfo XML as CLOB(5000), + OUT RetCode INTEGER) +DYNAMIC RESULT SETS 0 +NOT DETERMINISTIC +LANGUAGE JAVA +PARAMETER STYLE DB2GENERAL +NO DBINFO +FENCED +THREADSAFE +MODIFIES SQL DATA +PROGRAM TYPE SUB +EXTERNAL NAME 'Xquery_XmlProc.Xquery_Proc'@ + +CONNECT RESET@ diff --git a/xml/xquery/java/jdbc/Xquery_XmlProc_Drop.db2 b/xml/xquery/java/jdbc/Xquery_XmlProc_Drop.db2 new file mode 100644 index 0000000..9a15b1e --- /dev/null +++ b/xml/xquery/java/jdbc/Xquery_XmlProc_Drop.db2 @@ -0,0 +1,38 @@ +---------------------------------------------------------------------------- +-- (c) Copyright IBM Corp. 2007 All rights reserved. +-- +-- The following sample of source code ("Sample") is owned by International +-- Business Machines Corporation or one of its subsidiaries ("IBM") and is +-- copyrighted and licensed, not sold. You may use, copy, modify, and +-- distribute the Sample in any form without payment to IBM, for the purpose of +-- assisting you in the development of your applications. +-- +-- The Sample code is provided to you on an "AS IS" basis, without warranty of +-- any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +-- IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +-- not allow for the exclusion or limitation of implied warranties, so the above +-- limitations or exclusions may not apply to you. IBM shall not be liable for +-- any damages you suffer as a result of using, copying, modifying or +-- distributing the Sample, even if IBM has been advised of the possibility of +-- such damages. +---------------------------------------------------------------------------- +-- +-- SOURCE FILE NAME: Xquery_XmlProc_Drop.db2 +-- +-- SAMPLE: How to uncatalog the stored procedure in Xquery_XmlProc.java +-- +-- To run this script from the CLP, +-- issue the command "db2 -td@ -vf Xquery_XmlProc_Drop.db2" +---------------------------------------------------------------------------- + +-- connect to the SAMPLE database +CONNECT TO sample@ + +-- drop the procedure +DROP PROCEDURE Supp_XML_Proc_Java( XML AS CLOB(5000), + XML AS CLOB(5000), + INTEGER)@ + +CONNECT RESET@ + diff --git a/xml/xquery/java/jdbc/makefile b/xml/xquery/java/jdbc/makefile new file mode 100644 index 0000000..a943659 --- /dev/null +++ b/xml/xquery/java/jdbc/makefile @@ -0,0 +1,171 @@ +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# +# MAKEFILE for JDBC XQUERY samples on UNIX +# +# Enter one of the following commands +# +# make - Builds the program designated by . +# +# make all - Builds all supplied sample programs +# +# make srv - Builds sample that can only be run on the server, +# (stored procedure) +# +# make all_client - Builds all client samples (all programs in the +# 'call_rtn' and 'client_run' categories). +# +# make call_rtn - Builds client programs that call stored procedure +# +# make client_run - Builds all programs that run completely on the +# client (not ones that call stored procedure) +# +# make clean - Erases all intermediate files produced in the +# build process. +# +# make cleanall - Erases all files produced in the build process +# (all files except the original source files). +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +############################################################################## +# 1 -- VARIABLES +############################################################################## + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +COPY=cp +ERASE=rm -f + +############################################################################# +# Generic rule to make a class from a java source file +############################################################################# + +.SUFFIXES : .class .java + +.java.class : + javac $< + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all (srv + all_client) +# 2b - make srv +# 2c - make all_client (call_rtn + client_run + java_beans) +# 2d - make call_rtn +# 2e - make client_run +# 2f - make clean +# 2g - make cleanall +############################################################################# + +#**************************************************************************** +# 2a - make all (srv + all_client) +#**************************************************************************** + +all : \ + srv \ + all_client + +#**************************************************************************** +# 2b - make srv +#**************************************************************************** + +srv : \ + Xquery_XmlProc + +#**************************************************************************** +# 2c - make all_client (call_rtn + client_run + java_beans) +#**************************************************************************** + +all_client : \ + call_rtn \ + client_run + +#**************************************************************************** +# 2d - make call_rtn +#**************************************************************************** + +call_rtn : \ + Xquery_XmlProc_Client +#**************************************************************************** +# 2e - make client_run +#**************************************************************************** + +client_run : \ + XPath Flwor SqlXQuery XQuery XQueryParam XUpdate +#**************************************************************************** +# 2f - make clean +#**************************************************************************** + +clean : + +#**************************************************************************** +# 2g - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) *.class + $(ERASE) $(DB2PATH)/function/Xquery_XmlProc.class + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - standalone applications +# 3b - client/server applications +############################################################################# + + +#**************************************************************************** +# 3a - standalone applications +#**************************************************************************** + +XPath : XPath.class + +Flwor : Flwor.class + +SqlXQuery : SqlXQuery.class + +XQuery : XQuery.class + +XQueryParam : XQueryParam.class + +XUpdate : XUpdate.class + +#**************************************************************************** +# 3b - client/server applications +#**************************************************************************** + +#--------------------SpClient / SpServer------------------------------------# +# Note: before you execute SpClient for the first time, you must call the +# SpCreate.db2 CLP script to catalog the methods in SpServer as stored +# procedures. Call SpDrop.db2 to uncatalog the methods in SpServer. + +Xquery_XmlProc_Client : Xquery_XmlProc_Client.class + +Xquery_XmlProc : Xquery_XmlProc.class + $(ERASE) $(DB2PATH)/function/Xquery_XmlProc.class + $(COPY) Xquery_XmlProc.class $(DB2PATH)/function + spcat_xquery diff --git a/xml/xquery/java/jdbc/spcat_xquery b/xml/xquery/java/jdbc/spcat_xquery new file mode 100644 index 0000000..536251d --- /dev/null +++ b/xml/xquery/java/jdbc/spcat_xquery @@ -0,0 +1,31 @@ +#! /bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: spcat_xquery +# To catalog JDBC stored procedures on UNIX +# Catalogs the stored procedures in the Xquery_XmlProc library +# Xquery_XmlProc_Drop.db2 uncatalogs the stored procedures if previously cataloged +# Xquery_XmlProc_Create.db2 catologs the stored procedures +# Both CLP scripts can be run on their own +# Usage: spcat_xquery + +db2 -td@ -vf Xquery_XmlProc_Drop.db2 +db2 -td@ -vf Xquery_XmlProc_Create.db2 + diff --git a/xml/xquery/java/sqlj/Flwor.sqlj b/xml/xquery/java/sqlj/Flwor.sqlj new file mode 100644 index 0000000..0609d06 --- /dev/null +++ b/xml/xquery/java/sqlj/Flwor.sqlj @@ -0,0 +1,403 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: Flwor.sqlj +// +// SAMPLE: How to embed simple FLWOR expression of XQuery in SQLj +// +// SQL Statements USED: +// SELECT +// FETCH +// +// SQL/XML FUNCTIONS USED: +// xmlcolumn +// xmlquery +// +// XQUERY FUNCTION USED: +// data +// string +// +// OUTPUT FILE: Flwor.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For information on using XQuery statements, see the XQuery Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +// Define the iterator to use in the functions +#sql iterator Positioned_Iterator(Object); + +class Flwor +{ + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + DefaultContext ctx=null; + int cid; + float price; + String country; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + + // select the default context + ctx= new DefaultContext(con); + + // set the default context for the sample + DefaultContext.setDefaultContext(ctx); + System.out.println(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + System.out.println("----------------------------------------------------------------"); + System.out.println("Select the customer details in order of their customer ID....."); + orderCustDetails(); + + cid=1002; + System.out.println("----------------------------------------------------------------"); + System.out.println("Select the customer details with customer ID greater then "+ cid +"....."); + conditionalCustDetails1(cid); + + cid=1002; + country="US"; + System.out.println("----------------------------------------------------------------"); + System.out.println("Select the customer details with customer ID greater then "+ cid +" and"); + System.out.println(" country not equal to "+ country +"....."); + conditionalCustDetails2(cid, country); + + System.out.println("----------------------------------------------------------------"); + System.out.println("Select the product with maximun price......"); + maxpriceproduct(); + + price=10; + System.out.println("----------------------------------------------------------------"); + System.out.println("Select the product with basic price "+ price +"........"); + basicproduct(price); + } // main + + // This function will find out the customer details in order of their name + static void orderCustDetails() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator custIter=null; + + // Run the query with default context + #sql custIter = {SELECT XMLQUERY('for $custinfo in $cust/customerinfo[addr/@country="Canada"] + return $custinfo' + passing by ref customer.info as "cust") FROM customer order by cid}; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + // print the reslt as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + // close the cursor + custIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // orderCustDetails + + // This function will find out the customer details based on the condition + // customer id is greater then the value passed to method (cid) + static void conditionalCustDetails1(int cid) + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator custIter=null; + + // Run the query with default context + #sql custIter = {SELECT XMLQUERY('for $customer in $cust/customerinfo + where ($customer/@Cid > $id) + order by $customer/@Cid + return + {$customer/name} {$customer/addr} ' + passing by ref customer.info as "cust", cast(:cid as integer) as "id") + from customer order by cid}; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + // print the reslt as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2String()); + } + + // close the cursor + custIter.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // conditionalCustDetails1 + + // This function will find out the customer details based on the condition + // customer id is greater then cid value passed to the function and + // country is not equal to country parameter value + static void conditionalCustDetails2(int cid, String country) + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator custIter=null; + + // Run the query with default context + #sql custIter = {select xmlquery('for $customer in $cust/customerinfo + where ($customer/@Cid > $id) and ($customer/addr/@country !=$c) + order by $customer/@Cid + return + {$customer/name} +
{$customer/addr/street} + {$customer/addr/city}
' + passing by ref customer.info as "cust", + cast(:cid as integer) as "id", + cast(:country as varchar(10)) as "c") + from customer order by cid}; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + + // print the result as DB2 string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2String()); + } + + // close the cursor + custIter.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // conditionalCustDetails2 + + // This function will return the product details with maximun price + static void maxpriceproduct() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator priceIter=null; + + // Run the query with default context + #sql priceIter = {SELECT XMLQUERY('let $prod:=for $product in + db2-fn:xmlcolumn("PRODUCT.DESCRIPTION")/product/description + order by fn:number($product/price) descending return $product + return {$prod[1]/name} ') + FROM sysibm.sysdummy1}; + + while (true) + { + // fetch the cursor + #sql {FETCH :priceIter INTO :data}; + + if (priceIter.endFetch()) + { + break; + } + + // print the reslt as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + // close the cursor + priceIter.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // maxpriceproduct + + + // This function will return the product with basic attribute value true + // if the price is less then price parameter otherwiese false + static void basicproduct(float price) + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator prodIter=null; + + // Run the query with default context + #sql prodIter = {select xmlquery('for $prod in db2-fn:xmlcolumn("PRODUCT.DESCRIPTION")/product/description + order by $prod/name + return ( if ($prod/price < $price) + then {fn:data($prod/name)} + else {fn:data($prod/name)})' + passing by ref cast(:price as float) as "price") + from SYSIBM.SYSDUMMY1}; + while (true) + { + // fetch the cursor + #sql {FETCH :prodIter INTO :data}; + + if (prodIter.endFetch()) + { + break; + } + + // print the reslt as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + // close the cursor + prodIter.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // basicproduct +} // Flwor + diff --git a/xml/xquery/java/sqlj/SqlXQuery.sqlj b/xml/xquery/java/sqlj/SqlXQuery.sqlj new file mode 100644 index 0000000..9bbe2ee --- /dev/null +++ b/xml/xquery/java/sqlj/SqlXQuery.sqlj @@ -0,0 +1,343 @@ +/*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: SqlXQuery.sqlj +// +// SAMPLE: How to run SQL/XML Queries +// +// SQL Statements USED: +// SELECT +// +// SQL/XML STATEMENTS USED: +// XMLQUERY +// XMLEXISTS +// +// +// OUTPUT FILE: SqlXQuery.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + + +// Define the iterator to use in the functions +#sql iterator Positioned_Iterator1(Object); +#sql iterator Positioned_Iterator2(int,Object,Object,Object); +#sql iterator Positioned_Iterator3(int); +#sql iterator Positioned_Iterator4(int, Object); + +class SqlXQuery +{ + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + DefaultContext ctx=null; + String custName=null; + String partID=null; + + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + + // select the default context + ctx= new DefaultContext(con); + + // set the default context for the sample + DefaultContext.setDefaultContext(ctx); + System.out.println(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + System.out.println("---------------------------------------------------------------------------"); + custName="Robert Shoemaker"; + System.out.println("SELECT THE FIRST ITEM IN THE PURCHASEORDER FOR THE CUSTOMER "+custName+"......"); + System.out.println(); + firstPO1(custName); + + System.out.println("---------------------------------------------------------------------------"); + System.out.println("SELECT THE FIRST ITEM IN THE PURCHASEORDER WHEN THE CUSTOMER IS IN SEQUENCE (X,Y,Z)"); + System.out.println(" AND CUSTOMER ID IN THE SEQUENCE (1000,1002,1003) ........"); + System.out.println(); + firstPO2(); + + System.out.println("--------------------------------------------------------------------------"); + System.out.println("SORT THE CUSTOMERS ACCORDING TO THE NUMBER OF PURCHASEORDERS..........."); + System.out.println(); + sortCust_PO(); + + System.out.println("---------------------------------------------------------------------------"); + partID="100-101-01"; + System.out.println("SELECT THE NUMBER OF PURCHASEORDER FOR THE CUSTOMER "+custName+" HAVING THE"); + System.out.println(" PARTID " + partID +"......"); + System.out.println(); + numPO(custName, partID); + + } //main + + // This function will find out the first item in the purchase order for customer + // The name of the customer is passed as an argument to the function + static void firstPO1(String custName) + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator1 custIter=null; + + // Run the query with default context + #sql custIter = {SELECT XMLQUERY('$p/PurchaseOrder/item[1]' PASSING p.porder AS "p") + FROM purchaseorder AS p, customer AS c + WHERE XMLEXISTS('$custinfo/customerinfo[name=$c and @Cid = $cid]' + PASSING c.info AS "custinfo", p.custid AS "cid", cast(:custName as varchar(20)) as "c")}; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + // print the result as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + // close the cursor + custIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // firstPO1 + + // This function will find out the first item in the purchaseorder when + // Name is from the sequence + // or the customer id is from the sequence (1000,1002,1003) + static void firstPO2() + { + try + { + Object data=null; + int cid=0; + Object name=null; + Object history=null; + + // declare an iterator + Positioned_Iterator2 custIter=null; + + // Run the query with default context + #sql custIter = {SELECT cid, XMLQUERY('$custinfo/customerinfo/name' passing c.info as "custinfo"), + XMLQUERY('$p/PurchaseOrder/item[1]' passing p.porder as "p"), + XMLQUERY('$x/history' passing c.history as "x") + FROM purchaseorder as p,customer as c + WHERE XMLEXISTS('$custinfo/customerinfo[name=(X,Y,Z) + or @Cid=(1000,1002,1003) and @Cid=$cid ]' + PASSING c.info AS "custinfo", p.custid AS "cid") ORDER BY cid}; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :cid,:name,:data,:history}; + + if (custIter.endFetch()) + { + break; + } + + System.out.println(); + + // Print the customer id + System.out.println("Cid: " +cid); + + // Print the name as DB2 String + System.out.println("NAME: " +((com.ibm.db2.jcc.DB2Xml)name).getDB2String()); + + // Print the first item in the purchaseorder as DB2 XML String + System.out.println("First Item in the purchaseorder: " +((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + // Print the history of the customer as DB2 XML String + System.out.println("History: " +((com.ibm.db2.jcc.DB2Xml)history).getDB2XmlString()); + } + + // close the cursor + custIter.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // firstPO2 + static void numPO(String custName, String partID) + { + try + { + int count=0; + // declare an iterator + Positioned_Iterator3 custIter=null; + + // Run the query with default context + #sql custIter = {WITH cid_table AS (SELECT Cid FROM customer + WHERE XMLEXISTS('$custinfo/customerinfo[name=$name]' + PASSING customer.info AS "custinfo", cast(:custName as varchar(20)) as "name")) + SELECT count(poid) FROM purchaseorder,cid_table + WHERE XMLEXISTS('$po/PurchaseOrder/item[partid=$id]' + PASSING purchaseorder.porder AS "po", cast(:partID as varchar(20)) as "id") + AND purchaseorder.custid=cid_table.cid}; + + // fetch the cursor + #sql {FETCH :custIter INTO :count}; + + // print the result + System.out.println(); + System.out.println("Number of purchaseorder with partid "+partID+" for customer "+custName+" :"+ count); + + // close the cursor + custIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + } // numPO + + static void sortCust_PO() + { + try + { + Object data=null; + int count=0; + + // declare an iterator + Positioned_Iterator4 custIter=null; + + // Run the query with default context + #sql custIter = {WITH count_table AS ( SELECT count(poid) as c,custid + FROM purchaseorder,customer + WHERE cid=custid group by custid ) + SELECT c, xmlquery('$s/customerinfo[@Cid=$id]/name' passing customer.info as "s", + count_table.custid as "id") + FROM customer,count_table WHERE custid=cid ORDER BY custid}; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :count, :data}; + + if (custIter.endFetch()) + { + break; + } + // print the result as an XML string + System.out.println(); + System.out.println("Count :"+count+" Name :"+ ((com.ibm.db2.jcc.DB2Xml)data).getDB2String()); + } + + // close the cursor + custIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + } // sortCust_PO +} // SqlXQuery diff --git a/xml/xquery/java/sqlj/XPath.sqlj b/xml/xquery/java/sqlj/XPath.sqlj new file mode 100644 index 0000000..fef9144 --- /dev/null +++ b/xml/xquery/java/sqlj/XPath.sqlj @@ -0,0 +1,416 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XPath.sqlj +// +// SAMPLE: How to run simple XPath Queries. +// +// SQL STATEMENTS USED: +// SELECT +// +// SQL/XML STATEMENTS USED: +// xmlcolumn +// +// XQuery FUNCTIONS USED: +// distinct-values +// starts-with +// avg +// count +// +// +// OUTPUT FILE: XPath.out (available in the online documentation) +// Output will vary depending on the JDBC driver connectivity used. +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing SQLJ applications, see the Application +// Development Guide. +// +// For information on using XQuery statements, see the XQuery Reference. +// +// For information on using SQL statements, see the SQL Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; +import com.ibm.db2.jcc.DB2Xml; + +// Define the iterator to use in the functions +#sql iterator Positioned_Iterator(Object); +#sql iterator Positioned_Iterator2(com.ibm.db2.jcc.DB2Xml); +class XPath +{ + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + DefaultContext ctx=null; + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + + // get the default context + ctx= new DefaultContext(con); + + // set the default context for the sample + DefaultContext.setDefaultContext(ctx); + System.out.println(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + + System.out.println("----------------------------------------------------------------"); + System.out.println("SELECT THE CUSTOMER DETAILS........"); + CustomerDetails(); + + System.out.println("------------------------------------------------------------------"); + System.out.println("SELECT THE CUSTOMER'S CITIES FROM CANADA ....."); + CitiesInCanada(); + + System.out.println("-------------------------------------------------------------------"); + System.out.println("SELECT THE NAME OF THE CUSTOMER WITH MOBILE NUMBER START FROM 905......."); + CustMobileNum(); + + System.out.println("--------------------------------------------------------------------"); + System.out.println("SELECT THE AVERAGE PRICE FOR ALL THE PRODUCT IN 100 SERIES....."); + AvgPrice(); + + System.out.println("---------------------------------------------------------------------"); + System.out.println("SELECT THE CUSTOMER FROM TORONTO CITY......."); + CustomerFromToronto(); + + System.out.println("--------------------------------------------------------------------"); + System.out.println("SELECT THE NUMBER OF CUSTOMER FROM TORONTO CITY......."); + NumOfCustInToronto(); + + } + static void CustomerDetails() + { + try + { + com.ibm.db2.jcc.DB2Xml data=null; + + // declare an iterator + Positioned_Iterator2 custIter=null; + + // Run the query with default context + #sql custIter = {SELECT XMLQUERY('$custinfo' PASSING BY REF customer.info as "custinfo") from customer order by cid}; + while (true) + { + + // fetch the cursor + #sql {FETCH :custIter into :data}; + if (custIter.endFetch()) + { + break; + } + + // print the reslt as an XML string + System.out.println(); + System.out.println(data.getDB2XmlString()); + } + + // close the cursor + custIter.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // CustomerDetails + + static void CitiesInCanada() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator citiesIter=null; + + // Run the query with default context + #sql citiesIter = {SELECT XMLQUERY('for $cty in fn:distinct-values(db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo/addr[@country="Canada"] + /city) order by $cty return $cty') FROM SYSIBM.SYSDUMMY1}; + + while (true) + { + // fetch the cursor + #sql {FETCH :citiesIter INTO :data}; + + if (citiesIter.endFetch()) + { + break; + } + + // print the reslt as DB2 string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + // close the cursor + citiesIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //CitiesInCanada + + static void CustMobileNum() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator mobileIter=null; + + // Run the query with default context + #sql mobileIter = {SELECT XMLQUERY('$custinfo/customerinfo[phone[@type="cell" and + fn:starts-with(text(),"905")]]' passing by ref customer.info as "custinfo") from customer}; + + while (true) + { + // fetch the cursor + #sql {FETCH :mobileIter INTO :data}; + + if (mobileIter.endFetch()) + { + break; + } + + // print the reslt as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2String()); + } + + // close the cursor + mobileIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } + + static void AvgPrice() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator priceIter=null; + + // Run the query with default context + #sql priceIter= {SELECT XMLQUERY('let $prod_price:=db2-fn:xmlcolumn("PRODUCT.DESCRIPTION") + /product[fn:starts-with(@pid,"100")]/description/price + return avg($prod_price)') FROM sysibm.sysdummy1}; + + while (true) + { + // fetch the cursor + #sql {FETCH :priceIter INTO :data}; + + if (priceIter.endFetch()) + { + break; + } + + // print the result as DB2 string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2String()); + } + + // close the cursor + priceIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // AvgPrice + + static void CustomerFromToronto() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator custIter=null; + + // Run the query with default context + #sql custIter = {SELECT XMLQUERY('$custinfo/customerinfo[addr/city="Toronto"]/name' + passing by ref customer.info as "custinfo") from customer ORDER BY cid desc}; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + + // print the result as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2String()); + } + + // close the cursor + custIter.close(); + + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // CustomerFromToronto + + static void NumOfCustInToronto() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator custIter=null; + + // Run the query with default context + #sql custIter = { SELECT XMLQUERY('fn:count(db2-fn:xmlcolumn("CUSTOMER.INFO") + /customerinfo[addr/city="Toronto"])') + from sysibm.sysdummy1}; + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + + // print the result a DB2 string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2String()); + } + + // close the cursor + custIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // NumOfCustInToronto +} // XPath diff --git a/xml/xquery/java/sqlj/XQuery.sqlj b/xml/xquery/java/sqlj/XQuery.sqlj new file mode 100644 index 0000000..27a74a3 --- /dev/null +++ b/xml/xquery/java/sqlj/XQuery.sqlj @@ -0,0 +1,435 @@ +//*************************************************************************** +// (c) Copyright IBM Corp. 2007 All rights reserved. +// +// The following sample of source code ("Sample") is owned by International +// Business Machines Corporation or one of its subsidiaries ("IBM") and is +// copyrighted and licensed, not sold. You may use, copy, modify, and +// distribute the Sample in any form without payment to IBM, for the purpose of +// assisting you in the development of your applications. +// +// The Sample code is provided to you on an "AS IS" basis, without warranty of +// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +// not allow for the exclusion or limitation of implied warranties, so the above +// limitations or exclusions may not apply to you. IBM shall not be liable for +// any damages you suffer as a result of using, copying, modifying or +// distributing the Sample, even if IBM has been advised of the possibility of +// such damages. +//*************************************************************************** +// +// SOURCE FILE NAME: XQuery.sqlj +// +// SAMPLE: How to run a nested XQuery and shows how to pass parameters to +// sqlquery function. +// +// SQL/XML FUNCTIONS USED: +// sqlquery +// xmlcolumn +// +// XQUERY EXPRESSION USED +// FLWOR Expression +// +// OUTPUT FILE: XQuery.out (available in the online documentation) +//*************************************************************************** +// +// For more information on the sample programs, see the README file. +// +// For information on developing JDBC applications, see the Application +// Development Guide. +// +// For information on using XQUERY statements, see the XQUERY Reference. +// +// For the latest information on programming, compiling, and running DB2 +// applications, visit the DB2 application development website at +// http://www.software.ibm.com/data/db2/udb/ad +//**************************************************************************/ + +import java.lang.*; +import java.sql.*; +import java.io.*; +import java.util.*; +import com.ibm.db2.jcc.DB2Xml; +import sqlj.runtime.*; +import sqlj.runtime.ref.*; + +// Define the iterator to use in the functions +#sql iterator Positioned_Iterator1(Object); +#sql iterator Positioned_Iterator2(Object); + +class XQuery +{ + + public static void main(String argv[]) + { + int rc=0; + String url = "jdbc:db2:sample"; + Connection con=null; + DefaultContext ctx=null; + + try + { + Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); + + // connect to the 'sample' database + con = DriverManager.getConnection( url ); + + // select the default context + ctx= new DefaultContext(con); + + // set the default context for the sample + DefaultContext.setDefaultContext(ctx); + System.out.println(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + System.out.println("-------------------------------------------------------------"); + System.out.println("RESTRUCTURE THE PURCHASEORDERS ACCORDING TO THE CITY...."); + System.out.println(); + PO_OrderByCity(); + + System.out.println("-------------------------------------------------------------"); + System.out.println("RESTRUCTURE THE PURCHASEORDER ACCORDING TO THE PRODUCT....."); + System.out.println(); + CustomerOrderByProduct(); + + System.out.println("-------------------------------------------------------------"); + System.out.println("RESTRUCTURE THE PURCHASEORDER DATA ACCORDING TO PROVIENCE, CITY AND STREET.."); + System.out.println(); + PO_OrderByProvCityStreet(); + + System.out.println("-------------------------------------------------------------"); + System.out.println("COMBINE THE DATA FROM PRODUCT AND CUSTOMER TABLE TO CREATE A PURCHASEORDER.."); + CustomerPO(); + + } // main + + static void PO_OrderByCity() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator1 custIter=null; + Positioned_Iterator2 custIter1=null; + + // Run the query with default context + #sql custIter = {select XMLQUERY('for $city in fn:distinct-values(db2-fn:xmlcolumn("CUSTOMER.INFO") + /customerinfo/addr/city) + order by $city + return + { + for $cust in db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo[addr/city=$city] + let $po:=db2-fn:sqlquery("SELECT XMLELEMENT( NAME ""pos"", + (XMLCONCAT( XMLELEMENT(NAME ""custid"", c.custid), + XMLELEMENT(NAME ""order"", c.porder)))) + FROM purchaseorder AS c") + let $id:=$cust/@Cid, + $order:=$po/pos[custid=$id]/order + order by $cust/@Cid + return {$cust/name} {$cust/addr} {$order} } ') FROM + sysibm.sysdummy1}; + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + // print the result as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + System.out.println("\n\nThe following query shows how to pass parameters to sqlquery function"); + System.out.println("-------------------------------------------------------------------------"); + + #sql custIter1 = {SELECT XMLQUERY(' + for $city in fn:distinct-values(db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo/addr/city) + order by $city + return + + { + for $cust in db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo[addr/city=$city] + let $po:=db2-fn:sqlquery("SELECT porder FROM PURCHASEORDER WHERE custid=parameter(1)",$cust/@Cid) + let $order:=$po/order + order by $cust/@Cid + return + + {$cust/name} + {$cust/Addr} + {$order} + } + ') FROM SYSIBM.SYSDUMMY1}; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter1 INTO :data}; + + if (custIter1.endFetch()) + { + break; + } + // print the result as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + // close the cursor + custIter.close(); + custIter1.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // PO_OrderByCity + + static void CustomerOrderByProduct() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator1 custIter=null; + + // Run the query with default context + #sql custIter = {select xmlquery ('let $po:=db2-fn:sqlquery("SELECT XMLELEMENT( NAME ""pos"", + ( XMLCONCAT( XMLELEMENT(NAME ""custid"", c.custid), + XMLELEMENT(NAME ""order"", c.porder) ) )) + FROM purchaseorder AS c" ) + for $partid in fn:distinct-values(db2-fn:xmlcolumn("PURCHASEORDER.PORDER")/PurchaseOrder/item/partid) + order by $partid + return + + { for $id in fn:distinct-values($po[order/PurchaseOrder/item/partid=$partid]/custid) + let $order:= + {fn:sum($po[custid=$id]/order/PurchaseOrder/item[partid=$partid]/quantity)} + , + $cust:=db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo[@Cid=$id] + order by $id + return {$order} {$cust} } + + ') FROM SYSIBM.SYSDUMMY1 + }; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + // print the result as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + // close the cursor + custIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } // CustomerOrderByProduct + + static void PO_OrderByProvCityStreet() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator1 custIter=null; + + // Run the query with default context + #sql custIter = {select xmlquery ('let $po:=db2-fn:sqlquery("SELECT XMLELEMENT( NAME ""pos"", + ( XMLCONCAT( XMLELEMENT(NAME ""custid"", c.custid), + XMLELEMENT(NAME ""order"", c.porder) + ) )) + FROM PURCHASEORDER as c ORDER BY poid"), + $addr:=db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo/addr + for $prov in distinct-values($addr/prov-state) + return + + { + for $city in fn:distinct-values($addr[prov-state=$prov]/city) + order by $city + return + + { + for $s in fn:distinct-values($addr/street) where $addr/city=$city + order by $s + return + + { + for $info in $addr[prov-state=$prov and city=$city and street=$s]/.. + order by $info/@Cid + return + + {$info/name} + { + let $id:=$info/@Cid, $order:=$po[custid=$id]/order + return $order + } + + } + + } + + } + ') FROM SYSIBM.SYSDUMMY1}; + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + // print the result as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + // close the cursor + custIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + } //PO_OrderByProvCityStreet + + + static void CustomerPO() + { + try + { + Object data=null; + + // declare an iterator + Positioned_Iterator1 custIter=null; + + // Run the query with default context + #sql custIter = {select xmlquery (' + { + for $ns1_customerinfo0 in db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo + where ($ns1_customerinfo0/@Cid=1001) + return + + {$ns1_customerinfo0/name} +
+ {$ns1_customerinfo0/addr/street} + {$ns1_customerinfo0/addr/city} + { + if($ns1_customerinfo0/addr/@country="US") + then + $ns1_customerinfo0/addr/prov-state + else() + } + { + fn:concat ($ns1_customerinfo0/addr/pcode-zip/text(),",",fn:upper-case($ns1_customerinfo0/addr/@country + ))} +
+
+ } + { + for $ns2_product0 in db2-fn:xmlcolumn("PRODUCT.DESCRIPTION")/product + where ($ns2_product0/@pid="100-100-01") + return + $ns2_product0 + } +
') FROM SYSIBM.SYSDUMMY1}; + + + while (true) + { + // fetch the cursor + #sql {FETCH :custIter INTO :data}; + + if (custIter.endFetch()) + { + break; + } + // print the result as an XML string + System.out.println(); + System.out.println(((com.ibm.db2.jcc.DB2Xml)data).getDB2XmlString()); + } + + // close the cursor + custIter.close(); + } + catch(SQLException sqle) + { + System.out.println("Error Msg: "+ sqle.getMessage()); + System.out.println("SQLState: "+sqle.getSQLState()); + System.out.println("SQLError: "+sqle.getErrorCode()); + System.out.println("Rollback the transaction and quit the program"); + System.out.println(); + try { DefaultContext.getDefaultContext().getConnection().rollback(); } + catch (Exception e) + { + } + System.exit(1); + } + catch(Exception e) + {} + }// CustomerPO +} // XQuery diff --git a/xml/xquery/java/sqlj/bldsqlj b/xml/xquery/java/sqlj/bldsqlj new file mode 100644 index 0000000..8006187 --- /dev/null +++ b/xml/xquery/java/sqlj/bldsqlj @@ -0,0 +1,90 @@ +#!/bin/ksh +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# SCRIPT: bldsqlj +# Builds Java embedded SQL (SQLJ) applications and applets on UNIX +# Usage: bldsqlj prog_name (requires hardcoding user ID and password) +# bldsqlj prog_name userid password +# bldsqlj prog_name userid password server_name +# bldsqlj prog_name userid password server_name port_number +# bldsqlj prog_name userid password server_name port_number db_name +# +# Defaults: +# userid = $USER variable requires updating if used +# password = $PSWD variable requires updating if used +# server_name = $SERVER variable set to local hostname +# port_number = $PORTNUM variable set to 50000 +# db_name = $DB variable set to "sample" + +# To hardcode user ID (USER) and password (PSWD) +# Replace "NULL" with the correct values in quotes +USER="NULL" +PSWD="NULL" +# You can replace the defaults for each of the following +# with a new value. Note that the PORTNUM number cannot +# be one already used by another process. +SERVER=`hostname` +PORTNUM=50000 +DB="sample" + + +# Translate and compile the SQLJ source file +# and bind the package to the database. + if ( [ $# -eq 1 ] && [ $USER != "NULL" ] && [ $PSWD != "NULL" ] ) || ( [ $# -ge 3 ] && [ $# -le 6 ] ) + then + # Remove .sqlj extension + progname=${1%.sqlj} + + sqlj "${progname}.sqlj" + + if [ $# -eq 1 ] + then + db2sqljcustomize -url jdbc:db2://$SERVER:$PORTNUM/$DB \ + -user $USER -password $PSWD -longpkgname "${progname}_SJProfile0" + elif [ $# -eq 3 ] + then + db2sqljcustomize -url jdbc:db2://$SERVER:$PORTNUM/$DB -user $2 -password $3 \ + -longpkgname "${progname}_SJProfile0" + elif [ $# -eq 4 ] + then + db2sqljcustomize -url jdbc:db2://$4:$PORTNUM/$DB -user $2 -password $3 \ + -longpkgname "${progname}_SJProfile0" + elif [ $# -eq 5 ] + then + db2sqljcustomize -url jdbc:db2://$4:$5/$DB -user $2 -password $3 \ + -longpkgname "${progname}_SJProfile0" + else + db2sqljcustomize -url jdbc:db2://$4:$5/$6 -user $2 -password $3 \ + -longpkgname "${progname}_SJProfile0" + fi + else + echo 'Usage: bldsqlj prog_name (requires hardcoding user ID and password)' + echo ' bldsqlj prog_name userid password' + echo ' bldsqlj prog_name userid password server_name' + echo ' bldsqlj prog_name userid password server_name port_number' + echo ' bldsqlj prog_name userid password server_name port_number db_name' + echo '' + echo ' Defaults:' + echo ' userid = '$USER + echo ' password = '$PSWD + echo ' server_name = '$SERVER + echo ' port_number = '$PORTNUM + echo ' db_name = '$DB + fi diff --git a/xml/xquery/java/sqlj/makefile b/xml/xquery/java/sqlj/makefile new file mode 100644 index 0000000..f23aa63 --- /dev/null +++ b/xml/xquery/java/sqlj/makefile @@ -0,0 +1,116 @@ +############################################################################# +# (c) Copyright IBM Corp. 2007 All rights reserved. +# +# The following sample of source code ("Sample") is owned by International +# Business Machines Corporation or one of its subsidiaries ("IBM") and is +# copyrighted and licensed, not sold. You may use, copy, modify, and +# distribute the Sample in any form without payment to IBM, for the purpose of +# assisting you in the development of your applications. +# +# The Sample code is provided to you on an "AS IS" basis, without warranty of +# any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +# not allow for the exclusion or limitation of implied warranties, so the above +# limitations or exclusions may not apply to you. IBM shall not be liable for +# any damages you suffer as a result of using, copying, modifying or +# distributing the Sample, even if IBM has been advised of the possibility of +# such damages. +############################################################################# +# +# MAKEFILE for SQLj samples on Unix +# +# Enter one of the following commands +# +# make - Builds the program designated by . +# +# make all - Builds all supplied sample programs. +# +# make clean - Erases all intermediate files produced in the +# build process. +# +# make cleanall - Erases all files produced in the build process +# (all files except the original source files). +# +# The makefile contains the following sections: +# 1 -- VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# +# +############################################################################ +# 1 -- VARIABLES +############################################################################ + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +# To connect to a remote SAMPLE database cataloged on the client machine +# with another name, update the DB variable. +DB=sample +# Set UID, PWD, SERVER_NAME and PORT_NUMBER +# You need to hardcode at least the password in the makefile +# Update the PORT_NUMBER in case the default value is not correct +UID=$(USER) +PWD= +SERVER_NAME=$(HOSTNAME) +PORT_NUMBER=50000 + +COPY=cp +ERASE=rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all +# 2b - make clean +# 2c - make cleanall +############################################################################# + +#**************************************************************************** +# 2a - make all +#**************************************************************************** + +all : XPath XQuery Flwor SqlXQuery + + +#**************************************************************************** +# 2b - make clean +#**************************************************************************** + +clean : + $(ERASE) XPath.java + $(ERASE) XQuery.java + $(ERASE) SqlXQuery.java + $(ERASE) Flwor.java + +#**************************************************************************** +# 2c - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) *.class *.ser + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - standalone applications +############################################################################# +#*************************************************************************** +# 3a - standalone applications +#*************************************************************************** + + +XPath : + bldsqlj XPath $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +XQuery : + bldsqlj XQuery $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +Flwor: + bldsqlj Flwor $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) + +SqlXQuery: + bldsqlj SqlXQuery $(UID) $(PWD) $(SERVER_NAME) $(PORT_NUMBER) $(DB) +

+ Entry #: +

BT(1gT?p~hZ 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 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/st_multilinestring.prj b/extenders/spatial/data/st_multilinestring.prj new file mode 100644 index 0000000..747df58 --- /dev/null +++ b/extenders/spatial/data/st_multilinestring.prj @@ -0,0 +1 @@ +GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] \ No newline at end of file diff --git a/extenders/spatial/data/st_multilinestring.shp b/extenders/spatial/data/st_multilinestring.shp new file mode 100644 index 0000000000000000000000000000000000000000..db22094c9e4dc3a92c5b1d47dbf8ffc90de271db GIT binary patch literal 100 gcmZQzQ0HR64vbzfGcW)V4)9?=L;^J8=Bgw{vsWI5_}?n1C28SIJbT@}LsMT%Zdea&Kp52Q00K zJCM`=$>}ac9}7$_@<5Q*>GHS(Z842cCPCy_VRA}qc3O7;6c3$rZ@$t7%?(sB!^ug8s1I|*VYFHDZ@)vIq=K)L*eIrm#2a(pnk6rC!~Pe8XgUzzf9 z1u))#;`}hV{wuE~_<(XNxTK5kL*xWta)!K$_r%KL4m_IngmV@|P7o%Co)&=OLNK{1 zmXqoZKtIUKo%g*1@q;i-F4QZxbu%z-6Xv*BJcG!Iz~pA`RT5SOhV_p;V~!UPKZwHQ y_I~Nzun_2$ldh zYex|^0`friI6!GXC>;Z(v!HYZlx~C4Q=s%BD7^tn?}O53p!6*${Q^pVgV2mDP+AB| UD?n*IC~X6!y`XdiluiTD0R8YCga7~l literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/st_multipolygon.dbf b/extenders/spatial/data/st_multipolygon.dbf new file mode 100644 index 0000000000000000000000000000000000000000..d8a08d89a8db9f372b52324ffe8c40fe4978a6bf GIT binary patch literal 192 rcmZQhV`AcCU|?`$-~^IrAe@20(*-W(2V!x+xex}g0u&ew2tx`0hEfv8 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/st_multipolygon.prj b/extenders/spatial/data/st_multipolygon.prj new file mode 100644 index 0000000..747df58 --- /dev/null +++ b/extenders/spatial/data/st_multipolygon.prj @@ -0,0 +1 @@ +GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] \ No newline at end of file diff --git a/extenders/spatial/data/st_multipolygon.shp b/extenders/spatial/data/st_multipolygon.shp new file mode 100644 index 0000000000000000000000000000000000000000..09df9685c8fe1686a6ab53ad6d00185db5144acc GIT binary patch literal 7640 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 H$WH(O-T@g~ literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/st_point.dbf b/extenders/spatial/data/st_point.dbf new file mode 100644 index 0000000000000000000000000000000000000000..657c90e4199e35175ba377b8c1ea1f5eb50eea77 GIT binary patch literal 390 vcmZQhV`5TaU|?`$-~^IrAe@20(*-W(2V!x+xex}g0u&gGG87cZ3%q?Go7%r%hcDa)pSee_jS1*<(WvQf;)6#~Cm1Ox+ zk{gz$%i5M~EUho;O&Db*6;?`6iGeh-m?o8<>}(GQ6uhwe;ruxF`Jd-`#^J>Ia+ZBO z62E(LI9#x+xtZnJ=NR^deej65i>9*dk}COGhE)yab;doUsb$-j7G0n5b-k+2&%b$G z$*|>`gp@fGO+m>6es0szO!!T(6Ri<#eP*{o0%D!E{30n>vS)%hhOFs@_K*KXxe@X$ z%HxgZn_qC3b{Q+Y{hX}FL&LcO4zq=WY7w*fr+T% z5n?OQ2L6oOxEh8{^vO(Dk(~Z$+bR^FQ_2~3t}N(KF6j$EYkL|Kya8-c&Xs6dXUpjl zFg#PJ2cp@hwtCIL`R3m0mBe<_6x3ItZ7+?wbPW1^Tk18;b^g4X_FaXv$eKoLUKPN(D46KlV_5hBz=)+wtDNMPtdnX zAXw0mEKz8@DYetMbiQ?H2Uum|E7yFZ>FrLkpV4S<)n=Xs?qCqL-;zW2Y(3iWQI0Jh z>_;=dc$j2~L7TKlv#)_MCY?T&m*Ro4 zJBp|gkO#8I0ZRKp=@=-T1*I#XbQ_eO0;Ly0=?zeNACx`=rEfv$7f|{egl1%c(n3&L z0ZQvZX&Wf*1*IdPbQ+W{fznM-dIFT52c_3Q>0MCz1eCr8rJq3QPY{|3NP)tEi4RK4 GfM@`HAR~hS literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/st_polygon.dbf b/extenders/spatial/data/st_polygon.dbf new file mode 100644 index 0000000000000000000000000000000000000000..b67a227396e48aa0a6a8272bb5bb9848afd0a353 GIT binary patch literal 120 rcmZQhV`5@sU|?`$-~^IrAe@20(*-W(2V!x+xex}g0u&gK#E=32i;f9D literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/st_polygon.prj b/extenders/spatial/data/st_polygon.prj new file mode 100644 index 0000000..747df58 --- /dev/null +++ b/extenders/spatial/data/st_polygon.prj @@ -0,0 +1 @@ +GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] \ No newline at end of file diff --git a/extenders/spatial/data/st_polygon.shp b/extenders/spatial/data/st_polygon.shp new file mode 100644 index 0000000000000000000000000000000000000000..64bb0bd7d39fe57b39c023dc28f25ca9056a2cdd GIT binary patch literal 6680 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 literal 0 HcmV?d00001 diff --git a/extenders/spatial/data/st_polygon.shx b/extenders/spatial/data/st_polygon.shx new file mode 100644 index 0000000000000000000000000000000000000000..98bdcebba2fa9296ce1a55a978017231769bf37b GIT binary patch literal 148 zcmZQzQ0HR64!mA4Gcd3M<&M2^y2n)$cR-Ej>8$J}P7d8SPi422#T}SwzU9)JwN4J$ jwWEj{0eK*GWl(w-0|R#g0|Sp7ke>vkTOi^*CqOg+Y{(Y{ literal 0 HcmV?d00001 diff --git a/extenders/spatial/makefile b/extenders/spatial/makefile new file mode 100644 index 0000000..da0d1aa --- /dev/null +++ b/extenders/spatial/makefile @@ -0,0 +1,127 @@ +###------------------------------------------------------------------------ +### THIS IS AN OBSOLETE MAKEFILE FOR THE AIX PLATFORM +### +### ==> To build the "runGseDemo" program for all Unix platforms you now +### run the shell script: bldDemo.sh +### +###------------------------------------------------------------------------ + +# (C) COPYRIGHT International Business Machines Corp. 1996, 2002 +# All Rights Reserved. +# +# US Government Users Restricted Rights - Use, duplication or +# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + + +# Makefile for DB2 Universal Database Version 81 +# SQL procedure sample programs -- AIX operating system + + +# Enter one of the following commands +# +# make - Builds the program designated by +# +# make all - Builds the all the supplied sample programs +# +# make clean - Erases intermediate files +# make cleanall - Erases all files produced in the build process, +# except the original source files + +# The makefile contains the following sections: +# 1 -- COMPILERS + VARIABLES +# 2 -- MAKE CATEGORIES +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES + + +################################################################################## +# 1 -- COMPILERS + VARIABLES +################################################################################## + +# This file assumes the DB2 instance path is defined by the variable HOME. +# It also assumes DB2 is installed under the DB2 instance. +# If these statements are not correct, update the variable DB2PATH. +DB2PATH = $(HOME)/sqllib + +# Use the xlc compiler +CC= xlc +# Use xlc_r for multi-threaded programs +CM=xlc_r +# For multi-threaded programs on AIX 4.3 or later, use: +# CM=xlc_r7 + +DB2INSTANCEPATH = /home/$(DB2INSTANCE) +CFLAGS= -I$(DB2INSTANCEPATH)/sqllib/include -g -qcpluscmt +LIBES= -L$(DB2INSTANCEPATH)/sqllib/lib -ldb2 -lc + +# The required libraries +LIBS= -L$(DB2PATH)/lib -ldb2 +LIBS1= -L$(DB2PATH)/lib -ldb2 -ldb2apie + +# To connect to a remote SAMPLE database cataloged on the client machine +# with another name, update the DB variable. +DB=sample +# Set UID and PWD if neccesary +UID= +PWD= + +COPY=cp +ERASE=rm -f + +############################################################################# +# 2 -- MAKE CATEGORIES +# 2a - make all(= all samples) +# 2b - make clean +# 2a - make cleanall +############################################################################# + + +#**************************************************************************** +# 2a - make all +#**************************************************************************** + +all : \ + runGseDemo + +#**************************************************************************** +# 2b - make clean +#**************************************************************************** + + +clean : \ + cleangen + +cleangen : + $(ERASE) *.o *.map message.* + +#**************************************************************************** +# 2c - make cleanall +#**************************************************************************** + +cleanall : \ + clean + $(ERASE) runGseDemo + +############################################################################# +# 3 -- COMMANDS TO MAKE INDIVIDUAL SAMPLES +# 3a - Spatial extender sample +############################################################################# + +#**************************************************************************** +# 3a - Spatial extender samples +#**************************************************************************** + +###------------------------------------------------------------------------ +### THIS IS AN OBSOLETE MAKEFILE FOR AIX 32bit INSTANCES +### +### ==> To build the "runGseDemo" program for all Unix platforms you now +### run the shell script: bldDemo.sh +### +###------------------------------------------------------------------------ +# samputil contains common utility functions +samputil.o : samputil.c samputil.h + +runGseDemo : runGseDemo.o samputil.o ; + echo "==>" + echo "This makefile is obsolete. Please use bldDemo.sh instead." + echo "==>" + xlc -o runGseDemo runGseDemo.o samputil.o $(LIBES) -bloadmap:runGseDemo.map diff --git a/extenders/spatial/runGseDemo b/extenders/spatial/runGseDemo new file mode 100755 index 0000000000000000000000000000000000000000..0efa9630f7ae8b16db94edd2f1be8a2f55f46bf4 GIT binary patch literal 124504 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 CgZkS5 literal 0 HcmV?d00001 diff --git a/extenders/spatial/runGseDemo.c b/extenders/spatial/runGseDemo.c new file mode 100644 index 0000000..e0a9347 --- /dev/null +++ b/extenders/spatial/runGseDemo.c @@ -0,0 +1,3897 @@ +/***************************************************************************** +** +** Source File Name = runGseDemo.c +** +** Licensed Materials - Property of IBM +** +** (C) COPYRIGHT International Business Machines Corp. 2000, 2014 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +** +** +**P PURPOSE : +** Demonstrates the major GIS concepts and services supported by DB2 +** Spatial Extender +**E +*****************************************************************************/ + +#include +#include +#include +#include + +#include "sql.h" +#include "sqlcli.h" +#include "sqlcli1.h" +#include "sqlca.h" +#include "sqlutil.h" +#include "samputil.h" +#include "db2gse.h" +#include "sqlenv.h" +#include "db2ApiDf.h" + +#define MAX_COLUMNS 255 + +#define MIN_APPLHEAPSZ 2048 +#define MIN_LOGPRIMARY 10 +#define MIN_LOGFILSIZ 1000 + +#define LAT_LONG 54031 +#define KENT5 26980 +#define NORTH_AMERICAN 4269 +#define POINT_TYPE "ST_Point" +#define POLYGON_TYPE "ST_Polygon" + +#define MAX_STMT_LEN 255 +#define MAX_SP_PARAMS 22 + +#ifndef max +#define max(a,b) (a > b ? a : b) +#endif + + +/* Macro for Statement Handle Checking */ +#define STMT_HANDLE_CHECK( hstmt, SQLRC ) \ + if ( SQLRC != SQL_SUCCESS ) \ + { \ + rc = HandleInfoPrint( SQL_HANDLE_STMT, hstmt, \ + SQLRC, __LINE__, __FILE__ ) ; \ + if ( rc == 2 ) StmtResourcesFree( hstmt ); \ + if ( rc != 0 ) return rc; \ + } + +/* Macro for Connection Handle Checking */ +#define DBC_HANDLE_CHECK( hdbc, SQLRC ) \ + if ( SQLRC != SQL_SUCCESS ) \ + { \ + rc = HandleInfoPrint( SQL_HANDLE_DBC, hdbc, \ + SQLRC, __LINE__, __FILE__ ) ; \ + if ( rc != 0 ) return rc; \ + } + + +#undef _NOW32OS +#undef _W32OS + +#if ( defined(DB2AIX) || defined(DB2SUN) || \ + defined(DB2HP) || \ + defined(DB2LINUX)) +#define _NOW32OS +#else +#define _W32OS +#endif + +SQLHANDLE henv; +SQLHANDLE hdbc; +SQLHANDLE hstmt; + +SQLCHAR dbase[SQL_MAX_DSN_LENGTH + 1] = "sample"; +SQLCHAR uid[MAX_UID_LENGTH + 1]; +SQLCHAR pwd[MAX_PWD_LENGTH + 1]; +SQLCHAR AbChoice[4]="Y"; + +char path[255]; +char exceptionpath[255]; +char msgpath[255]; + +SQLINTEGER ind[MAX_SP_PARAMS]; + +/* Return code for all the services */ +SQLINTEGER retCode = 0; +SQLINTEGER NbCall = 0; +SQLINTEGER NbError = 0; +SQLINTEGER CheckRC = 0; +SQLINTEGER domenu = 0; +SQLRETURN rc; + +char reserved[SQL_MAX_MESSAGE_LENGTH+1] = ""; +char locatorFile[257]; +char parvalues[1000]; +char buffer[80]; + +struct sqlca sqlca; + +/* local functions for util.c */ +void HandleLocationPrint( SQLRETURN, int, char * ); +void HandleDiagnosticsPrint( SQLSMALLINT, SQLHANDLE ); + +/****************************************************************************** +** 1.1 - HandleInfoPrint - prints on the screen everything that +** goes unexpected with a SQL... function. +******************************************************************************/ +int HandleInfoPrint( SQLSMALLINT htype, /* handle type identifier */ + SQLHANDLE hndl, /* handle used by the SQL...func. */ + SQLRETURN sqlrc, /* ret. code of the SQL... func. */ + int line, + char * file ) +{ + int rc = 0; + + switch ( sqlrc ) + { + case SQL_SUCCESS: + rc = 0; + break ; + case SQL_INVALID_HANDLE: + printf( "\n-SQL INVALID HANDLE-----\n"); + HandleLocationPrint( sqlrc, line, file); + rc = 1; + break ; + case SQL_ERROR: + printf( "\n--SQL ERROR--------------\n"); + HandleLocationPrint( sqlrc, line, file); + HandleDiagnosticsPrint( htype, hndl); + rc = 2; + break ; + case SQL_SUCCESS_WITH_INFO: + rc = 0; + break ; + case SQL_STILL_EXECUTING : + rc = 0; + break ; + case SQL_NEED_DATA : + rc = 0; + break ; + case SQL_NO_DATA_FOUND: + rc = 0; + break ; + default: + printf( "\n--default----------------\n"); + HandleLocationPrint( sqlrc, line, file); + rc = 3; + break ; + } + + return ( rc ) ; +} + + +/****************************************************************************** +** 1.1.1 - HandleLocationPrint - used by HandleInfoPrint +******************************************************************************/ +void HandleLocationPrint( SQLRETURN sqlrc, + int line, + char * file) +{ + printf( " sqlrc = %d\n", sqlrc); + printf( " line = %d\n", line); + printf( " file = %s\n", file); +} + +/****************************************************************************** +** 1.1.2 - HandleDiagnosticsPrint - used by HandleInfoPrint +******************************************************************************/ +void HandleDiagnosticsPrint( SQLSMALLINT htype, /* handle type identifier */ + SQLHANDLE hndl /* handle */) +{ + SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1] ; + SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1] ; + SQLINTEGER sqlcode ; + SQLSMALLINT length, i ; + + i = 1 ; + + while ( SQLGetDiagRec( htype, hndl, i, sqlstate, &sqlcode, + message, SQL_MAX_MESSAGE_LENGTH + 1, + &length ) == SQL_SUCCESS ) + { + printf( "\n SQLSTATE = %s\n", sqlstate ) ; + printf( " Native Error Code = %d\n", sqlcode ) ; + printf( "%s\n", message ) ; + i++ ; + } + + printf( "-------------------------\n" ) ; +} +/*<-- */ + + +/****************************************************************************** +** 1.3 - StmtResourcesFree - no more comments +******************************************************************************/ +/* this function is used in STMT_HANDLE_CHECK, */ +/* it can not contain STMT_HANDLE_CHECK */ +int StmtResourcesFree( SQLHANDLE hstmt ) +{ + SQLRETURN sqlrc = SQL_SUCCESS; + int rc = 0; + + sqlrc = SQLFreeStmt( hstmt, SQL_UNBIND ) ; + rc = HandleInfoPrint( SQL_HANDLE_STMT, hstmt, + sqlrc, __LINE__, __FILE__); + if( rc != 0) return(1) ; + + sqlrc = SQLFreeStmt( hstmt, SQL_RESET_PARAMS ) ; + rc = HandleInfoPrint( SQL_HANDLE_STMT, hstmt, + sqlrc, __LINE__, __FILE__); + if( rc != 0) return(1) ; + + sqlrc = SQLFreeStmt( hstmt, SQL_CLOSE ) ; + rc = HandleInfoPrint( SQL_HANDLE_STMT, hstmt, + sqlrc, __LINE__, __FILE__); + if( rc != 0) return(1) ; + + return( 0 ); +} + +/*======================================================================*/ +/* */ +/* createDb - create a database in the local db directory */ +/* */ +/*======================================================================*/ +int createDb(char* dbase) +{ + struct sqledbdesc db_desc; + struct sqledbcountryinfo dbCountry; + struct sqledbdescext db_desc_ext; + + + printf("---------------> Creating the database '%s' ...\n", dbase); + + memset(&db_desc, 0, sizeof db_desc); + strcpy(db_desc.sqldbdid, SQLE_DBDESC_2); + db_desc.sqldbccp = 0; + db_desc.sqldbcss = 0; + db_desc.sqldbsgp = 0; + db_desc.sqldbnsg = 10; + db_desc.sqltsext = -1; + db_desc.sqlusrts = NULL; + db_desc.sqltmpts = NULL; + db_desc.sqlcatts = NULL; + strcpy(db_desc.sqldbcmt, "spatial extender test database"); + strcpy(dbCountry.sqldbcodeset, "IBM-850"); + strcpy(dbCountry.sqldblocale, "En_US"); + + memset(&db_desc_ext, 0, sizeof db_desc_ext); + db_desc_ext.sqlPageSize = SQL_PAGESIZE_8K; + + sqlecrea(dbase, dbase, "", &db_desc, &dbCountry, '\0', &db_desc_ext, &sqlca); + + if (sqlca.sqlcode != 0) + { + printf("<--------------- Failed to create local database '%s' with return \ +code %d.\n", dbase, sqlca.sqlcode); + return sqlca.sqlcode; + } + else + printf("<--------------- Database '%s' was successfully created.\n", + dbase); + + return sqlca.sqlcode; +} + +/*======================================================================*/ +/* */ +/* getNumPartitions - Get the number of entries from db2nodes.cfg */ +/* */ +/* returns: numPartitions */ +/* - if numPartitions = 1 we run in a single partition env */ +/* - if numPartitions > 1 we run in a multiple partition env */ +/* */ +/* Note: no longer used as of 04/09/07 */ +/* */ +/*======================================================================*/ +int getNumPartitions() +{ + FILE *db2nodes_fp; /* db2nodes.cfg file pointer */ + char cfg[256]; /* input configuration file name */ + char sqllibdir[255]; /* the concrete sqllib path */ + + int max_node_number, node_number = 0; + + strcpy(sqllibdir,getenv("DB2PATH")); +#ifdef _NOW32OS + sprintf(cfg,"%s/%s",sqllibdir,"db2nodes.cfg"); +#else + sprintf(cfg,"%s\\db2\\%s",sqllibdir,"db2nodes.cfg"); +#endif + + db2nodes_fp = fopen (cfg,"r"); + + if ( db2nodes_fp != NULL ) + { + /*================================================================*/ + /* Read the input cfg file for node num and keep the maximum */ + /*================================================================*/ + while(!feof(db2nodes_fp)) + { + fscanf(db2nodes_fp,"%d", &node_number); + fscanf(db2nodes_fp,"%*[^\n]"); /* Skip to the End of the Line */ + fscanf(db2nodes_fp,"%*1[\n]"); /* Skip One Newline */ + + max_node_number = node_number + 1; /* the first number is 0 */ + } + + fclose (db2nodes_fp); + } + else + { + /*===============================================================*/ + /* If we can not read the file because it does not exist, we can */ + /* asume that we have single node environment only. */ + /*===============================================================*/ + + max_node_number = 1; + } + + return max_node_number; +} + +/*======================================================================*/ +/* */ +/* Wrap up the Demo session */ +/* */ +/*======================================================================*/ +int WrapUpDemo() +{ + SQLRETURN rc; + printf("==========> Wrapping up the DB2GSE demo program ...\n"); + rc = SQLTransact(henv, hdbc, SQL_COMMIT); + CHECK_DBC(hdbc, rc); + + if (rc != SQL_SUCCESS) + { + terminate(henv, rc); + exit(0); + } + + printf("Total errors: %i\n",NbError); + printf("<========== The DB2GSE demo program is wrapped up \ +successfully.\n\n"); + printf("Disconnecting .....\n"); + + rc = SQLDisconnect(hdbc); + CHECK_DBC(hdbc, rc); + if (rc != SQL_SUCCESS) + { + terminate(henv, rc); + exit(0); + } + + rc = SQLFreeHandle(SQL_HANDLE_DBC,hdbc); + CHECK_DBC(hdbc, rc); + if (rc != SQL_SUCCESS) + { + terminate(henv, rc); + exit(0); + } + rc = SQLFreeHandle(SQL_HANDLE_ENV,henv); + if (rc != SQL_SUCCESS) + terminate(henv, rc); + exit(0); +} + + +/*======================================================================*/ +/* */ +/* GseCheck() */ +/* - Just check SQLRETURN values and closes program in error case */ +/* - The CheckRC=1 variable may be used to avoid abborting in the */ +/* error situation for debugging pourposes */ +/* */ +/*======================================================================*/ +void GseCheck(SQLRETURN rc) +{ + NbCall++; + if (rc != 0) + { + NbError++; + if(CheckRC) /* CheckRC=1 - Abort on any error */ + WrapUpDemo(); + else /* CheckRC=0 - go on */ + { + printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + printf("==========> An error has occurred in the function call number \ +%00i\n",NbCall); + printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\ +\n\n"); + + } + } + else + { + printf("===========================================================\n"); + printf("==========> Successfully called function number %00i\n",NbCall); + printf("===========================================================\n\n\ +\n"); + } + fflush(stdout); +} + + +/*======================================================================*/ +/* */ +/* gseBuildSampleFolder() */ +/* */ +/* - build a full pathname for filename placing it in the demo */ +/* directory */ +/* */ +/*======================================================================*/ +void gseBuildSampleFolder(char *fullpath,char *filename) +{ + char homedir[255]; + + strcpy(homedir,getenv("DB2PATH")); +#ifdef _NOW32OS + sprintf(fullpath,"%s/samples/extenders/spatial/data/%s",homedir,filename); +#else + sprintf(fullpath,"%s\\samples\\extenders\\spatial\\data\\%s",homedir,filename); +#endif +} + + +/*======================================================================*/ +/* */ +/* gseBuildTempFolder() */ +/* */ +/* - build a full pathname for filename placing it in the demo temp */ +/* directory */ +/* */ +/*======================================================================*/ +void gseBuildTempFolder(char *fullpath,char *filename) +{ + char homedir[255]; + char *tempdir; + +#ifdef _NOW32OS + tempdir = (char *)getenv("DEMO_TMPDIR"); + if (tempdir == NULL) + tempdir = "/tmp"; + sprintf(fullpath,"%s/%s",tempdir, filename); +#else + strcpy(homedir,getenv("DB2PATH")); + sprintf(fullpath,"%s\\samples\\extenders\\spatial\\%s",homedir,filename); +#endif +} + + + +/*======================================================================*/ +/* */ +/* stEnableDB() */ +/* */ +/* - enable the database with an ST_enable_db stored procedure call */ +/* */ +/*======================================================================*/ +int stEnableDB() +{ + SQLRETURN rc; + SQLCHAR createEnableProc[] = + "CREATE PROCEDURE db2gse.my_enable_db ( " \ + "IN tableCreationParameters VARCHAR(32672 OCTETS), " \ + "OUT msgCode INTEGER, " \ + "OUT msgText VARCHAR(1024 OCTETS)) " \ + "SPECIFIC db2gse.my_EnableDB " \ + "MODIFIES SQL DATA " \ + "NOT DETERMINISTIC " \ + "CALLED ON NULL INPUT " \ + "LANGUAGE C " \ + "EXTERNAL NAME 'db2gsead!ST_enable_db_ext' " \ + "NOT FENCED " \ + "THREADSAFE " \ + "INHERIT SPECIAL REGISTERS " \ + "PARAMETER STYLE GENERAL WITH NULLS " \ + "PROGRAM TYPE SUB " \ + "NO DBINFO "; + SQLCHAR callEnableDB[] = "CALL db2gse.my_enable_db(?,?,?)"; + SQLCHAR dropEnableProc[] = "DROP SPECIFIC PROCEDURE db2gse.my_EnableDB"; + + char *tableCreateParameters = NULL; + + // 1. allocate the statement handle + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + // 2. drop the stored procedure - it should not exist + rc = SQLExecDirect(hstmt, dropEnableProc, SQL_NTS); + + // 3. create the stored procedure + rc = SQLExecDirect(hstmt, createEnableProc, SQL_NTS); + CHECK_STMT(hstmt, rc); + + // 4. prepare the call statement + rc = SQLPrepare(hstmt, callEnableDB, SQL_NTS); + CHECK_STMT(hstmt, rc); + + // 5. bind the following 3 parameters to ST_enable_db: + // - table parameters (e.g. tablespace) + // - return code + // - reserved parameter (not used) + ind[0] = (tableCreateParameters == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR,255, 0,tableCreateParameters, + 256, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = 0; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = 0; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[2]); + CHECK_STMT(hstmt, rc); + + printf("==========> Enabling the database '%s' with spatial capability ...\ +\n", dbase); + fflush(stdout); + + // 6. execute the statement + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to enable the database '%s' with return \ +code=%d text=%s\n\n", dbase, retCode, reserved); + else + printf("<========== Database '%s' is successfully enabled.\n\n", dbase); + + fflush(stdout); + + // 7. drop the stored procedure + rc = SQLExecDirect(hstmt, dropEnableProc, SQL_NTS); + CHECK_STMT(hstmt, rc); + + // 8. free the statement handle + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + + +/*======================================================================*/ +/* */ +/* stDisableDB() */ +/* */ +/* - disable the database with an ST_disable_db stored procedure call */ +/* */ +/*======================================================================*/ +int stDisableDB(short force) +{ + SQLRETURN rc; + SQLCHAR callDisableDB[] = "call db2gse.ST_disable_db (?,?,?)"; + + // 1. allocate the statement handle + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + // 2. prepare the statement + rc = SQLPrepare(hstmt, callDisableDB, SQL_NTS); + CHECK_STMT(hstmt, rc); + + // 3. bind the following 3 parameters to ST_disable_db: + // - force switch + // - return code + // - reserved parameter (not used) + ind[0] = (force == -1) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SHORT, + SQL_SMALLINT, 0, 0, &force, 2, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = 0; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = 0; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[2]); + CHECK_STMT(hstmt, rc); + + printf("==========> Disabling the spatial capability for database \ +'%s' ...\n", dbase); + fflush(stdout); + + // 4. execute the statement + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to disable the database '%s' with return \ +code=%d text=%s\n\n", dbase, retCode, reserved); + else + printf("<========== Database '%s' is successfully disabled.\n\n", + dbase); + + // 5. free the statement handle + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + +/*======================================================================*/ +/* */ +/* stCreateCS() */ +/* */ +/* - Creates a new Coordinate System */ +/* */ +/*======================================================================*/ +int stCreateCS (char *csName,char *definition,char *organization,int csID, + char *description) +{ + SQLRETURN rc; + + SQLCHAR callCreateCS[] + = "call db2gse.ST_create_coordsys (?,?,?,?,?,?,?)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + rc = SQLPrepare(hstmt, callCreateCS, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, csName, 128, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 2047, 0, definition, 2048, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = (organization == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, organization, 128, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = (csID == (int)NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &csID, 4, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = (description == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 253, 0, description, 254, &ind[4]); + CHECK_STMT(hstmt, rc); + + ind[5] = 0; + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[5]); + CHECK_STMT(hstmt, rc); + + ind[6] = 0; + rc = SQLBindParameter(hstmt, 7, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[6]); + CHECK_STMT(hstmt, rc); + + + printf("==========> Creating a new coordinate system %s with id=%d ...\n", + csName,csID); + fflush(stdout); + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to create the coordinate system %s - id=%d \ +with return code=%d text=%s\n\n",csName,csID, retCode, reserved); + else + printf("<========== The coordinate system %s - id=%d was created \ +successfully.\n\n", csName,csID); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + + +/*======================================================================*/ +/* */ +/* stAlterCS() */ +/* */ +/* - Alters a Coordinate System */ +/* */ +/*======================================================================*/ +int stAlterCS (char *csName,char *definition,char *organization,int csID, + char *description) +{ + SQLRETURN rc; + + SQLCHAR callAlterCS[] + = "call db2gse.ST_alter_coordsys (?,?,?,?,?,?,?)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callAlterCS, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, csName, 128, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = (definition == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 2047, 0, definition, 2048, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = (organization == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, organization, 128, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = (csID == (int)NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &csID, 4, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = (description == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 253, 0, description, 254, &ind[4]); + CHECK_STMT(hstmt, rc); + + ind[5] = 0; + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[5]); + CHECK_STMT(hstmt, rc); + + ind[6] = 0; + rc = SQLBindParameter(hstmt, 7, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[6]); + CHECK_STMT(hstmt, rc); + + + printf("==========> Altering a coordinate system %s with id=%d ...\n", + csName,csID); + fflush(stdout); + + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to alter the coordinate system %s - id=%d \ +with return code=%d text=%s\n\n",csName,csID, retCode, reserved); + else + printf("<========== The coordinate system %s - id=%d was successfully \ +altered.\n\n", csName,csID); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + + + +/*======================================================================*/ +/* */ +/* stDropCS() */ +/* */ +/* - Deletes a Coordinate System */ +/* */ +/*======================================================================*/ +int stDropCS (char *csName) +{ + SQLRETURN rc; + + SQLCHAR callDropCS[] + = "call db2gse.ST_drop_coordsys (?,?,?)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callDropCS, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, csName, 128, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = 0; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = 0; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[2]); + CHECK_STMT(hstmt, rc); + + printf("==========> Dropping coordinate system %s ...\n",csName); + fflush(stdout); + + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to drop the coordinate system %s with return \ +code=%d text=%s\n\n",csName, retCode, reserved); + else + printf("<========== The coordinate system %s was successfully dropped. \ +\n\n", csName); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + + + +/*======================================================================*/ +/* */ +/* stCreateSRS() */ +/* */ +/* - Creates a new Spatial Reference System */ +/* */ +/*======================================================================*/ +int stCreateSRS (char *srsName,int srsID, + double xOffset, double xScale, double yOffset, double yScale, + double zOffset, double zScale, + double mOffset, double mScale, + char *coordsysName,char *description) +{ + SQLRETURN rc; + + SQLCHAR callEnableSref[] + = "call db2gse.ST_create_srs (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callEnableSref, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, srsName, 128, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = 0; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &srsID, 4, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; // xOffset + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &xOffset, 4, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = 0;//xScale + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &xScale, 4, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = SQL_NTS; //yOffset + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &yOffset, 4, &ind[4]); + CHECK_STMT(hstmt, rc); + + ind[5] = SQL_NTS; //yScale + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &yScale, 4, &ind[5]); + CHECK_STMT(hstmt, rc); + + ind[6] = SQL_NTS; //zOffset + rc = SQLBindParameter(hstmt, 7, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &zOffset, 4, &ind[6]); + CHECK_STMT(hstmt, rc); + + ind[7] = SQL_NTS; //zScale + rc = SQLBindParameter(hstmt, 8, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &zScale, 4, &ind[7]); + CHECK_STMT(hstmt, rc); + + ind[8] = SQL_NTS; //mOffset + rc = SQLBindParameter(hstmt, 9, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &mOffset, 4, &ind[8]); + CHECK_STMT(hstmt, rc); + + ind[9] = SQL_NTS;//mScale + rc = SQLBindParameter(hstmt, 10, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &mScale, 4, &ind[9]); + CHECK_STMT(hstmt, rc); + + ind[10] = SQL_NTS; //coordsysName + rc = SQLBindParameter(hstmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, coordsysName, 128, &ind[10]); + CHECK_STMT(hstmt, rc); + + ind[11] = (description == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 253, 0, description, 254, &ind[11]); + CHECK_STMT(hstmt, rc); + + ind[12] = 0; + rc = SQLBindParameter(hstmt, 13, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[12]); + CHECK_STMT(hstmt, rc); + + ind[13] = 0; + rc = SQLBindParameter(hstmt, 14, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[13]); + CHECK_STMT(hstmt, rc); + + printf("==========> Creating a new spatial reference system with id=%d ...\ +\n",srsID); + fflush(stdout); + + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to create the spatial reference system id=%d \ +with return code=%d text=%s\n\n", srsID, retCode, reserved); + else + printf("<========== The spatial reference system id=%d was successfully \ +created.\n\n", srsID); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} +/*======================================================================*/ +/* */ +/* stAlterSRS() */ +/* */ +/* - Alters an existing Spatial Reference System */ +/* */ +/*======================================================================*/ +int stAlterSRS (char *srsName,int srsID, + double xOffset, double xScale, double yOffset, double yScale, + double zOffset, double zScale, + double mOffset, double mScale, + char *coordsysName,char *description) +{ + SQLRETURN rc; + + SQLCHAR callAlterSref[] + = "call db2gse.ST_alter_srs (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callAlterSref, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, srsName, 128, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = (srsID == -1) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &srsID, 4, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; // xOffset + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &xOffset, 4, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = 0; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &xScale, 4, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = SQL_NTS; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &yOffset, 4, &ind[4]); + CHECK_STMT(hstmt, rc); + + ind[5] = SQL_NTS; //yScale + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &yScale, 4, &ind[5]); + CHECK_STMT(hstmt, rc); + + ind[6] = SQL_NTS; //zOffset + rc = SQLBindParameter(hstmt, 7, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &zOffset, 4, &ind[6]); + CHECK_STMT(hstmt, rc); + + ind[7] = SQL_NTS; //zScale + rc = SQLBindParameter(hstmt, 8, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &zScale, 4, &ind[7]); + CHECK_STMT(hstmt, rc); + + ind[8] = SQL_NTS; //mOffset + rc = SQLBindParameter(hstmt, 9, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &mOffset, 4, &ind[8]); + CHECK_STMT(hstmt, rc); + + ind[9] = SQL_NTS;//mScale + rc = SQLBindParameter(hstmt, 10, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 0, 0, &mScale, 4, &ind[9]); + CHECK_STMT(hstmt, rc); + + ind[10] = (coordsysName == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, coordsysName, 128, &ind[10]); + CHECK_STMT(hstmt, rc); + + ind[11] = (description == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 253, 0, description, 254, &ind[11]); + CHECK_STMT(hstmt, rc); + + ind[12] = 0; + rc = SQLBindParameter(hstmt, 13, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[12]); + CHECK_STMT(hstmt, rc); + + ind[13] = 0; + rc = SQLBindParameter(hstmt, 14, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[13]); + CHECK_STMT(hstmt, rc); + + + printf("==========> Creating a new spatial reference system with id=%d ...\ +\n",srsID); + + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to create the spatial reference system id=%d \ +with return code=%d text=%s\n\n", srsID, retCode, reserved); + else + printf("<========== The spatial reference system id=%d was successfully \ +created.\n\n", srsID); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + + + +/*======================================================================*/ +/* */ +/* stDropSRS() */ +/* - Deletes an existing Spatial Reference System */ +/* */ +/*======================================================================*/ +int stDropSRS(char *srsName) +{ + SQLRETURN rc; + + SQLCHAR callDisableSref[] + = "call db2gse.ST_drop_srs (?,?,?)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callDisableSref, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, srsName, 128, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = 0; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = 0; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[2]); + CHECK_STMT(hstmt, rc); + + printf("==========> Dropping a spatial reference system with name %s ...\ +\n",srsName); + fflush(stdout); + + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to drop the spatial reference system %s with \ +return code=%d test=%s\n\n", srsName, retCode, reserved); + else + printf("<========== The spatial reference system %s was successfully \ +dropped.\n\n", srsName); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + +/*======================================================================*/ +/* */ +/* gseCreateLatLongGeocoder() */ +/* */ +/* (1) Create the UDF LatLongGeocoder. */ +/* */ +/*======================================================================*/ +int gseCreateLatLongGeocoder() +{ + SQLRETURN rc; + +SQLCHAR createGCUDF[] + = "CREATE OR REPLACE FUNCTION db2se.LatLongGC(latitude double, longitude double, srs_id int) \ + RETURNS db2gse.ST_Point \ + SPECIFIC db2se.LatLongGC \ + LANGUAGE SQL \ + DETERMINISTIC \ + EXTERNAL ACTION \ + READS SQL DATA \ + RETURN TREAT(db2gse.ST_Point(longitude, latitude, 1)..st_transform(srs_id) AS db2gse.ST_Point)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + printf("---------------> Creating the geocoder UDF...\n"); + fflush(stdout); + + rc = SQLExecDirect(hstmt, createGCUDF, SQL_NTS); + CHECK_STMT(hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + { + printf("<--------------- Failed to create the geocoder UDF.\n"); + } else { + printf("<--------------- The geocoder UDF was successfully created.\n"); + }; + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + +/*======================================================================*/ +/* */ +/* gseSetupTables() */ +/* */ +/* (1) Create the "customers" table. */ +/* (2) Populate the "customers" table. */ +/* (3) Alter the "customers" table by adding the "location" column. */ +/* (4) Create the "offices" table */ +/* */ +/*======================================================================*/ +int gseSetupTables() +{ + SQLRETURN rc; + char datafile[256]; + char msgfile[256]; + char tmpbuf[100]; + time_t xtime; + struct sqldcol dataDescriptor; + struct sqllob *pColumnString; + char impStatement[] = "INSERT INTO CUSTOMERS"; + char fileType[] = SQL_DEL; + db2ImportStruct importStruct; + db2ImportIn importInput; + db2ImportOut importOutput; + + + SQLCHAR createOffices[] + = "CREATE TABLE OFFICES ( \ + NAME CHAR(16) , \ + EMPLOYEES BIGINT , \ + ID BIGINT , \ + LOCATION DB2GSE.ST_POINT ) organize by row"; + + SQLCHAR createCustomers[] + = "CREATE TABLE CUSTOMERS \ + (ID INTEGER, \ + NAME VARCHAR(30), \ + ADDRESS VARCHAR(30), \ + CITY VARCHAR(28), \ + STATE VARCHAR(2), \ + ZIP VARCHAR(5), \ + INCOME FLOAT, \ + PREMIUM FLOAT, \ + CATEGORY SMALLINT, \ + LATITUDE DOUBLE, \ + LONGITUDE DOUBLE \ + ) organize by row"; + + + SQLCHAR alterCustomers[] + = "ALTER TABLE CUSTOMERS ADD COLUMN LOCATION DB2GSE.ST_POINT"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + printf("==========> Setting up tables ...\n"); + + printf("---------------> Creating the 'customers' table ...\n"); + fflush(stdout); + + rc = SQLExecDirect(hstmt, createCustomers, SQL_NTS); + CHECK_STMT(hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + { + printf("<--------------- Failed to create the 'customers' table.\n"); + goto exit; + } + + printf("<--------------- The 'customers' table was successfully created.\ + \n"); + + printf("---------------> Populating the 'customers' table ...\n"); + + /* setup the load-file information ('customers.data') */ + strcpy(datafile,getenv("DB2PATH")); +#ifdef _NOW32OS + strcat(datafile,"/samples/extenders/spatial/customers.data"); +#else + strcat(datafile,"\\samples\\extenders\\spatial\\customers.data"); +#endif + + time(&xtime); + /*---------------------------------------------------------------*/ + sprintf(tmpbuf,"loadCust.log_%i",xtime); + gseBuildTempFolder(msgfile,tmpbuf); + + printf(" Load from: %s\n", datafile); + printf(" Logfile: %s\n", msgfile); + + /* setup data descriptor */ + /* Map columns in load-file 1:1 to columns in table */ + dataDescriptor.dcolmeth = SQL_METH_D; + + /* need to allocate the proper amount of space for the impStatement */ + pColumnString = (struct sqllob *)malloc(MAX_STMT_LEN + + sizeof(struct sqllob)); + + pColumnString->length = strlen(impStatement); + strncpy (pColumnString->data, impStatement, strlen(impStatement)); + + memset(&importStruct,0,sizeof(importStruct)); + memset(&importInput,0,sizeof(importInput)); + memset(&importOutput,0,sizeof(importOutput)); + + importStruct.piDataFileName = datafile; + importStruct.piDataDescriptor = &dataDescriptor; + importStruct.piFileType = fileType; + importStruct.piMsgFileName = msgfile; + importStruct.iCallerAction = SQLU_INITIAL; + importStruct.piImportInfoIn = &importInput; + importStruct.poImportInfoOut = &importOutput; + importStruct.piLongActionString= pColumnString; + + /* / do the IMPORT */ + rc = db2Import(SQL_REL9702, + &importStruct, + &sqlca); + + + if (rc != SQL_ERROR && rc != SQL_INVALID_HANDLE) + { + printf(" %d rows read, %d rows committed.\n", + importOutput.oRowsRead, importOutput.oRowsCommitted); + if(importOutput.oRowsCommitted > 0 && + importOutput.oRowsCommitted == importOutput.oRowsRead) + printf("<--------------- The 'customers' table was successfully \ +populated.\n"); + else + { + printf(" **Check that the logfile directory exists and has write permissions.\n"); + rc = SQL_ERROR; + } + } + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + { + printf("<--------------- Failed to populate the 'customers' table.\n"); + goto exit; + } + + + printf("---------------> Adding the 'location' column to the 'customers' \ +table ...\n"); + + rc = SQLExecDirect(hstmt, alterCustomers, SQL_NTS); + CHECK_STMT(hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + { + printf("<--------------- Failed to add the 'location' column to the \ +'customers' table.\n"); + goto exit; + } + printf("<--------------- The 'location' column of the 'customers' table \ +was successfully added.\n"); + + printf("---------------> Creating the 'offices' table ...\n"); + + rc = SQLExecDirect(hstmt, createOffices, SQL_NTS); + CHECK_STMT(hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + { + printf("<--------------- Failed to create the 'offices' table.\n"); + goto exit; + } + printf("<--------------- The 'offices' table was successfully created.\n"); + + exit: + retCode = rc; + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + printf("<========== Failed to set up tables with return code=%d.\n\n", + rc); + else + printf("<========== Tables were successfully set up.\n\n"); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + + +/*======================================================================*/ +/* */ +/* stRegisterGc() */ +/* */ +/* - register the geocoder with an ST_register_geocoder stored */ +/* procedure call */ +/* */ +/* */ +/*======================================================================*/ +int stRegisterGc (char *gcName,char *functionSchema,char *functionName, + char *specificName,char *ParValues, + char *ParDescription, char *vendor, char *description) +{ + SQLRETURN rc; + char parameterValues[1000]; + char parameterDescription[1000]; + + SQLCHAR callRegisterGc[] + = "call db2gse.ST_register_geocoder (?,?,?,?,?,?,?,?,?,?)"; + + if(ParValues) + strcpy(parameterValues,ParValues); + + if(ParDescription) + strcpy(parameterDescription,ParDescription); + + // 1. allocate the statement handle + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + // 2. prepare the statement + rc = SQLPrepare(hstmt, callRegisterGc, SQL_NTS); + CHECK_STMT(hstmt, rc); + + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 129, 0, gcName, 130, &ind[0]); + CHECK_STMT(hstmt, rc); + + // 3. bind the following 10 parameters to ST_register_geocoder: + // - @param geocoder name + // - @param function schema + // - @param function name + // - @param specific name + // - @param default parameter values + // - @param parameter descriptions + // - @param vendor + // - @param description + // - @return message code + // - @return message text + ind[1] = (functionSchema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 129, 0, functionSchema, 130, &ind[1]); + CHECK_STMT(hstmt, rc); + + + ind[2] = (functionName == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 129, 0, functionName, 130, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = (specificName == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 129, 0, specificName, 130, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = (ParValues == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(parameterValues)-1), 0, + parameterValues, sizeof(parameterValues), &ind[4]); + + ind[5] = (ParDescription == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(parameterDescription)-1), 0, + parameterValues, sizeof(parameterValues), &ind[5]); + + ind[6] = (vendor == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 253, 0, vendor, 254, &ind[6]); + CHECK_STMT(hstmt, rc); + + ind[7] = (description == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 256, 0, description, 256, &ind[7]); + CHECK_STMT(hstmt, rc); + + ind[8] = 0; + rc = SQLBindParameter(hstmt, 9, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[8]); + CHECK_STMT(hstmt, rc); + + ind[9] = 0; + rc = SQLBindParameter(hstmt, 10, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[9]); + CHECK_STMT(hstmt, rc); + + printf("==========> Registering a new geocoder %s ...\n", gcName); + fflush(stdout); + + // 4. execute the statement + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to register the geocoder %s with return \ +code=%d text=%s\n\n", gcName, retCode, reserved); + else + printf("<========== The geocoder %s was successfully registered.\n\n", + gcName); + + // 5. free the statement handle + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + +/*======================================================================*/ +/* */ +/* stUnregisterGc() */ +/* */ +/*======================================================================*/ +int stUnregisterGc(char *gcName) +{ + SQLRETURN rc; + + SQLCHAR callUnregisterGc[] + = "call db2gse.ST_unregister_geocoder (?,?,?)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callUnregisterGc, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 129, 0, gcName, 130, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = 0; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = 0; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[9]); + CHECK_STMT(hstmt, rc); + + printf("==========> Unregistering a geocoder %s ...\n", gcName); + fflush(stdout); + + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to unregister the geocoder %s with return \ +code=%d text=%s\n\n", gcName, retCode, reserved); + else + printf("<========== The geocoder %s was successfully unregistered\n\n", + gcName); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + +/*======================================================================*/ +/* */ +/* stRegisterSpatialColumn() */ +/* */ +/* - register a spatial column with an ST_register_spatial_column */ +/* stored procedure call */ +/* */ +/*======================================================================*/ +int stRegisterSpatialColumn(char *sourceschema, char *sourcetable, + char *sourcecolumn, char *srsName) +{ + SQLRETURN rc; + SQLCHAR callRegisterSpatialColumn[] + = "call db2gse.ST_register_spatial_column(?,?,?,?,?,?)"; + + // 1. allocate the statement handle + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + // 2. prepare the statement + rc = SQLPrepare(hstmt, callRegisterSpatialColumn, SQL_NTS); + CHECK_STMT(hstmt, rc); + + // 3. bind the following 6 parameters to ST_resgister_spatial_column: + // - schema name + // - table name + // - column name + // - spatial reference system name + // - return code + // - reserved parameter (not used) + ind[0] = (sourceschema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourceschema, 128, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourcetable, 128, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourcecolumn, 128, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = SQL_NTS; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, srsName, 128, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = 0; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[4]); + CHECK_STMT(hstmt, rc); + + ind[5] = 0; + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[5]); + CHECK_STMT(hstmt, rc); + + printf("==========> Registering a new spatial column for \ +'%s.%s' ...\n", sourcetable, sourcecolumn); + fflush(stdout); + + // 4. execute the statement + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to register the spatial column with return \ +code=%d text=%s\n\n", retCode,reserved); + else + printf("<========== The spatial column for table.column '%s.%s' was \ +successfully registered.\n\n", sourcetable, sourcecolumn); + + // 5. free the statement handle + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + + +/*======================================================================*/ +/* */ +/* stSetupGeocoding() */ +/* */ +/* - Setup the geocoder for a column/table with an ST_setup_geocoding */ +/* stored procedure call */ +/* */ +/*======================================================================*/ +int stSetupGeocoding(char *sourceschema, + char *sourcetable, + char *sourcecolumn, + char *geocoderName, + char *ParValues, + char *AutoGCValue, + char *WhereClause, + int commitscope) +{ + SQLRETURN rc; + + SQLCHAR callSetupGeocoding[] + = "call db2gse.ST_setup_geocoding(?,?,?,?,?,?,?,?,?,?)"; + + char parameterValues[1000]={'\0'}; + char autoGCValue[1000]={'\0'}; + + if(ParValues) + strcpy(parameterValues,ParValues); + + if(AutoGCValue) + strcpy(autoGCValue,AutoGCValue); + + // 1. allocate the statement handle + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + // 2. prepare the statement + rc = SQLPrepare(hstmt, callSetupGeocoding, SQL_NTS); + CHECK_STMT(hstmt, rc); + + // 3. bind the following 10 parameters to ST_setup_geocoding: + // - schema name + // - table name + // - column name + // - geocoder name + // - geocoder parameters + // - autogeocoding switch + // - where clause + // - commit scope + // - return code + // - reserved parameter (not used) + ind[0] = (sourceschema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourceschema, 129, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourcetable, 129, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourcecolumn, 129, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = SQL_NTS; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, geocoderName, 129, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = (ParValues == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(parameterValues)-1), 0, + parameterValues, sizeof(parameterValues), &ind[4]); + + ind[5] = (AutoGCValue == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(autoGCValue)-1), 0, autoGCValue, + sizeof(autoGCValue), &ind[5]); + + ind[6] = (WhereClause == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 255, 0, WhereClause, 256, &ind[6]); + + ind[7] = (commitscope == -1) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 8, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &commitscope, 4, &ind[7]); + CHECK_STMT(hstmt, rc); + + ind[8] = 0; + rc = SQLBindParameter(hstmt, 9, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[8]); + CHECK_STMT(hstmt, rc); + + ind[9] = 0; + rc = SQLBindParameter(hstmt, 10, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[9]); + CHECK_STMT(hstmt, rc); + + + printf("==========> Associating geocoder with spatial column \ +table.column '%s.%s' ...\n", sourcetable, sourcecolumn); + fflush(stdout); + + // 4. execute the statement + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to Setup Geocoder for spatial column \ +with return code=%d text=%s\n\n", retCode,reserved); + else + printf("<========== Geocoder is sucessfully setup for spatial column \ +table.column '%s.%s'.\n\n", sourcetable, sourcecolumn); + + // 5. free the statement handle + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + +/*======================================================================*/ +/* */ +/* stRemoveGeocodingSetup */ +/* */ +/* - remove the geocoding setup with an ST_remove_geocoding_setup */ +/* stored procedure call */ +/* */ +/* */ +/*======================================================================*/ +int stRemoveGeocodingSetup(char *sourceschema, char *sourcetable, + char *sourcecolumn) +{ + SQLRETURN rc; + + SQLCHAR callRemoveGeocodingSetup[] + = "call db2gse.ST_remove_geocoding_setup(?,?,?,?,?)"; + + // 1. allocate the statement handle + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + // 2. prepare the statement + rc = SQLPrepare(hstmt, callRemoveGeocodingSetup, SQL_NTS); + CHECK_STMT(hstmt, rc); + + // 3. bind the following 5 parameters to ST_remove_geocoding_setup: + // - @param table schema + // - @param table name + // - @param column name + // - @return message code + // - @return message text + ind[0] = (sourceschema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourceschema, 129, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourcetable, 129, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourcecolumn, 129, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = 0; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[8]); + CHECK_STMT(hstmt, rc); + + ind[4] = 0; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[9]); + CHECK_STMT(hstmt, rc); + + + printf("==========> Removing Geocoding Setup from table.column '%s.%s' \ +...\n", sourcetable, sourcecolumn); + fflush(stdout); + + // 4. execute the statement + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to remove Geocoder setup in the spatial \ +column with return code=%d text=%s\n\n", retCode,reserved); + else + printf("<========== Geocoder setup was sucessfully removed from \ +column and table.column '%s.%s'.\n\n", sourcetable, sourcecolumn); + + // 5. free the statement handle + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + +/*======================================================================*/ +/* */ +/* stUnregisterSpatialColumn() */ +/* */ +/* - unregister a spatial column with an ST_unregister_spatial_column */ +/* stored procedure call */ +/* */ +/*======================================================================*/ +int stUnregisterSpatialColumn(char *sourceschema, char *sourcetable, + char *sourcecolumn) +{ + SQLRETURN rc; + SQLCHAR callUnregistSpatialColumn[] + = "call db2gse.ST_unregister_spatial_column (?,?,?,?,?)"; + + // 1. allocate the statement handle + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + // 2. prepare the statement + rc = SQLPrepare(hstmt, callUnregistSpatialColumn, SQL_NTS); + CHECK_STMT(hstmt, rc); + + // 3. bind the following 5 parameters to ST_unregister_spatial_column: + // - schema name + // - table name + // - column name + // - return code + // - reserved parameter (not used) + ind[0] = (sourceschema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 30, 0, sourceschema, 31, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourcetable, 129, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourcecolumn, 129, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = 0; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = 0; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[4]); + CHECK_STMT(hstmt, rc); + + printf("==========> Unregistering a spatial column for table.column '%s.%s'\ +...\n", sourcetable, sourcecolumn); + fflush(stdout); + + // 4. execute the statement + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to unregister the spatial column with return \ +code=%d text=%s\n\n", retCode,reserved); + else + printf("<========== The spatial column for table.column '%s.%s' was \ +successfully unregistered.\n\n", sourcetable, sourcecolumn); + + // 5. free the statement handle + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + +/*======================================================================*/ +/* */ +/* stRunGC() */ +/* */ +/*======================================================================*/ +int stRunGC(char *sourceschema, char *sourcetable, char *sourcecolumn, + char *geocoderName, + char *ParValues, + char *whereclause, + int commitscope) +{ + SQLRETURN rc; + + SQLCHAR callRunGC[] + = "call db2gse.ST_run_geocoding (?,?,?,?,?,?,?,?,?)"; + + char parameterValues[1000]; + + if(ParValues) + strcpy(parameterValues,ParValues); + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callRunGC, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = (sourceschema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 30, 0, sourceschema, 31, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourcetable, 129, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, sourcecolumn, 129, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = SQL_NTS; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, geocoderName, 129, &ind[3]); + CHECK_STMT(hstmt, rc); + + + ind[4] = (ParValues == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(parameterValues)-1), 0, + parameterValues, sizeof(parameterValues), &ind[4]); + + ind[5] = (whereclause == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 256, 0, whereclause, 256, &ind[5]); + CHECK_STMT(hstmt, rc); + + ind[6] = (commitscope == (int)NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 7, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &commitscope, 4, &ind[6]); + CHECK_STMT(hstmt, rc); + + ind[7] = 0; + rc = SQLBindParameter(hstmt, 8, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[7]); + CHECK_STMT(hstmt, rc); + + ind[8] = 0; + rc = SQLBindParameter(hstmt, 9, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[8]); + CHECK_STMT(hstmt, rc); + + printf("==========> Running the geocoder %s for spatial column: \ +'%s.%s' ...\n",geocoderName, sourcetable, sourcecolumn); + fflush(stdout); + + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to geocode the spatial column with return \ +code=%d text=%s\n\n", retCode,reserved); + else + printf("<========== The spatial column '%s.%s' is successfully geocoded.\ +\n\n", sourcetable, sourcecolumn); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} +/*======================================================================*/ +/* */ +/* stImportShape() */ +/* */ +/*======================================================================*/ +int stImportShape(char *path,char *InputAttColumns,char *srsName, + char *sourceschema,char *sourcetable, + char *TableAttColumns, int createTableFlag, + char *TableCreationParameters,char *sourcecolumn, + char *typeSchema,char *typeName,int inlineLength, + char *identityColumn,int idColumnIsIdentity, + int restartCount, int commitscope, + char *exceptionFile,char *messageFile) +{ + SQLRETURN rc; + char inputAttColumns[1000]; + char tableAttColumns[1000]; + char tableCreationParameters[1000]; + + SQLCHAR callImportShape[] + = "call db2gse.ST_import_shape(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + + if(InputAttColumns) + strcpy(inputAttColumns,InputAttColumns); + + if(TableAttColumns) + strcpy(tableAttColumns,TableAttColumns); + + if(TableCreationParameters) + strcpy(tableCreationParameters,TableCreationParameters); + + printf(" Logfile: %s\n", messageFile); + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callImportShape, SQL_NTS); + CHECK_STMT(hstmt, rc); + + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 128, 0, path, 129, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = (InputAttColumns == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, sizeof(inputAttColumns)-1, 0, + inputAttColumns, sizeof(inputAttColumns), &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, srsName, 128, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = (sourceschema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourceschema, 128, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = SQL_NTS; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourcetable, 128, &ind[4]); + CHECK_STMT(hstmt, rc); + + ind[5] = (TableAttColumns == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, sizeof(tableAttColumns)-1, 0, + tableAttColumns, sizeof(tableAttColumns), &ind[5]); + CHECK_STMT(hstmt, rc); + + ind[6] = (createTableFlag == -1) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 7, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &createTableFlag, 4, &ind[6]); + CHECK_STMT(hstmt, rc); + + ind[7] = (TableCreationParameters == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, sizeof(tableCreationParameters)-1, 0, + tableCreationParameters, + sizeof(tableCreationParameters), &ind[7]); + CHECK_STMT(hstmt, rc); + + ind[8] = SQL_NTS; + rc = SQLBindParameter(hstmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourcecolumn, 128, &ind[8]); + CHECK_STMT(hstmt, rc); + + ind[9] = (typeSchema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, typeSchema, 128, &ind[9]); + CHECK_STMT(hstmt, rc); + + ind[10] = (typeName == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, typeName, 128, &ind[10]); + CHECK_STMT(hstmt, rc); + + ind[11] = (inlineLength == -1) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 12, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &inlineLength, 4, &ind[11]); + CHECK_STMT(hstmt, rc); + + ind[12] = (identityColumn == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, identityColumn, 128, &ind[12]); + CHECK_STMT(hstmt, rc); + + ind[13] = (idColumnIsIdentity == -1) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 14, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &idColumnIsIdentity, 4, &ind[13]); + CHECK_STMT(hstmt, rc); + + ind[14] = (restartCount == -1) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 15, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &restartCount, 4, &ind[14]); + CHECK_STMT(hstmt, rc); + + ind[15] = (commitscope == -1) ? SQL_NULL_DATA : SQL_NTS;; + rc = SQLBindParameter(hstmt, 16, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &commitscope, 4, &ind[15]); + CHECK_STMT(hstmt, rc); + + ind[16] = (exceptionFile == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 17, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 255, 0, exceptionFile, 256, &ind[16]); + CHECK_STMT(hstmt, rc); + + ind[17] = (messageFile == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 18, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 255, 0, messageFile, 256, &ind[17]); + CHECK_STMT(hstmt, rc); + + ind[18] = 0; + rc = SQLBindParameter(hstmt, 19, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[18]); + CHECK_STMT(hstmt, rc); + + ind[19] = 0; + rc = SQLBindParameter(hstmt, 20, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[19]); + CHECK_STMT(hstmt, rc); + + printf("\n==========> Importing the shape file '%s' ...\n", path); + fflush(stdout); + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to import the shape file '%s' with return \ +code=%d text=%s\n\n", path, retCode, reserved); + else + printf("<========== The shape file '%s' was successfully imported\n\n", + path); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; + +} + + +/*======================================================================*/ +/* */ +/* gseCLICreateIndex() */ +/* */ +/* - Create INDEX on sourcetable.sourcecolumn */ +/* */ +/*======================================================================*/ +int gseCLICreateIndex(char *sourcetable, char *sourcecolumn, + char *indexname, + char *gridSizes) +{ + SQLRETURN rc=0; + char EnableIDXBuffer[255]; + + + SQLCHAR CreateIndex[] + = "CREATE INDEX ? ON ?(?) EXTEND USING DB2GSE.SPATIAL_INDEX (?,?,?)"; + + sprintf(EnableIDXBuffer,"CREATE INDEX %s ON %s(%s) EXTEND USING \ +db2gse.spatial_index(%s)", + indexname,sourcetable,sourcecolumn,gridSizes); + + printf("%s\n\n",EnableIDXBuffer); + + /* allocate a statement handle */ + rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) ; + DBC_HANDLE_CHECK(hdbc, rc); + + rc = SQLExecDirect( hstmt, (SQLCHAR *) EnableIDXBuffer, SQL_NTS ) ; + STMT_HANDLE_CHECK( hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + printf("<========== Failed to create spatial index \n"); + else + printf("<========== The spatial index was successfully created\n\n"); + + /* free the statement handle */ + rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ; + STMT_HANDLE_CHECK( hstmt, rc); + + return rc; +} + +/*======================================================================*/ +/* */ +/* gseCLIDropIndex() */ +/* */ +/* - Drop INDEX indexname */ +/* */ +/*======================================================================*/ +int gseCLIDropIndex(char *indexname) +{ + SQLRETURN rc=0; + char DropIDXBuffer[255]; + + sprintf(DropIDXBuffer,"DROP INDEX %s",indexname); + printf("%s\n\n",DropIDXBuffer); + + /* allocate a statement handle */ + rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) ; + DBC_HANDLE_CHECK(hdbc, rc); + + + rc = SQLExecDirect( hstmt, (SQLCHAR *) DropIDXBuffer, SQL_NTS ) ; + STMT_HANDLE_CHECK( hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + printf("<========== Failed to drop spatial index \n"); + else + printf("<========== The spatial index was successfully removed\n\n"); + + /* free the statement handle */ + rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ; + STMT_HANDLE_CHECK( hstmt, rc); + + return rc; +} + +/*======================================================================*/ +/* */ +/* stEnableAutoGC() */ +/* */ +/* */ +/*======================================================================*/ +int stEnableAutoGC(char *sourceschema, char *sourcetable, char *sourcecolumn) +{ + SQLRETURN rc; + + SQLCHAR callEnableAutoGc[] + = "call db2gse.ST_enable_autogeocoding (?,?,?,?,?)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callEnableAutoGc, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = (sourceschema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourceschema, 128, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourcetable, 128, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourcecolumn, 128, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = 0; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = 0; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[4]); + CHECK_STMT(hstmt, rc); + + printf("==========> Enabling automatic geocoder ...\n"); + fflush(stdout); + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to enable automatic geocoder with return \ +code=%d text=%s\n\n", retCode,reserved); + else + printf("<========== The automatic geocoder is successfully enabled\n\n"); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + + +/*======================================================================*/ +/* */ +/* gseInsDelUpd() */ +/* */ +/*======================================================================*/ +int gseInsDelUpd() +{ + SQLRETURN rc; + + SQLCHAR insertCustomers[] + = "INSERT INTO CUSTOMERS(ID, NAME, ADDRESS, CITY, STATE, ZIP, INCOME, PREMIUM, CATEGORY, LATITUDE, LONGITUDE) \ + VALUES(999999, 'NEW CUSTOMER', \ + '2000 AVON CIRCLE', \ + 'RADCLIFF', 'KY', '40160', \ + 72000, 1300, 6, \ + 37.82, -85.96)"; + + SQLCHAR deleteCustomers[] + = "DELETE FROM CUSTOMERS WHERE ID >= 81000 AND ID <= 140000"; + + SQLCHAR updateCustomers[] + = "UPDATE CUSTOMERS SET (LATITUDE, LONGITUDE) = (37.82, -85.96) WHERE ID >= 140000"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + printf("==========> Inserts, updates, and deletes on the 'customers' \ +table ...\n"); + fflush(stdout); + + printf("---------------> Inserting tuples into the 'customers' table ...\ +\n"); + + rc = SQLExecDirect(hstmt, insertCustomers, SQL_NTS); + CHECK_STMT(hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + { + printf("<--------------- Failed to insert into the 'customers' table.\n"); + goto exit; + } + + printf("<--------------- Inserts to 'customers' table successful.\n"); + + rc = SQLTransact(henv, hdbc, SQL_COMMIT); + + printf("---------------> Updating the 'customers' table ...\n"); + + rc = SQLExecDirect(hstmt, updateCustomers, SQL_NTS); + CHECK_STMT(hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + { + printf("<--------------- Failed to update the 'customers' table.\n"); + goto exit; + } + + printf("<--------------- Updates to 'customers' table successful.\n"); + + rc = SQLTransact(henv, hdbc, SQL_COMMIT); + + printf("---------------> Deleting from the 'customers' table ...\n"); + + rc = SQLExecDirect(hstmt, deleteCustomers, SQL_NTS); + CHECK_STMT(hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + { + printf("<--------------- Failed to delete from the 'customers' table.\n"); + goto exit; + } + + printf("<--------------- Deletes from 'customers' table successful.\ +\n"); + + rc = SQLTransact(henv, hdbc, SQL_COMMIT); + + exit: + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + printf("\n<========== Insert, update, or delete failed \ +with return code %d.\n\n", rc); + else + printf("<========== Inserts, updates and deletes on the 'customers' table \ +were successful.\n\n"); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return rc; +} +/*======================================================================*/ +/* */ +/* stDisableAutoGc() */ +/* */ +/*======================================================================*/ +int stDisableAutoGc(char *sourceschema, char *sourcetable, + char *sourcecolumn) +{ + SQLRETURN rc; + + SQLCHAR callDisableAutoGc[] + = "call db2gse.ST_disable_autogeocoding (?,?,?,?,?)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callDisableAutoGc, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = (sourceschema == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourceschema, 128, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = SQL_NTS; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourcetable, 128, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 127, 0, sourcecolumn, 128, &ind[2]); + CHECK_STMT(hstmt, rc); + + ind[3] = 0; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = 0; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[4]); + CHECK_STMT(hstmt, rc); + + printf("==========> Disabling automatic geocoder ...\n"); + fflush(stdout); + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to disable automatic geocoder with return \ +code=%d text=%s\n\n", retCode,reserved); + else + printf("<========== The automatic geocoder was successfully disabled \ +\n\n"); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} + +/*======================================================================*/ +/* */ +/* gseCreateView() */ +/* */ +/* Create a view HIGHRISKCUSTOMERS representing a spatial join with */ +/* a join predicate ST_WITHIN(GEOM1, GEOM2). */ +/* */ +/*======================================================================*/ +int gseCreateView() +{ + SQLRETURN rc; + + SQLCHAR createView[] + = "CREATE VIEW HIGHRISKCUSTOMERS (ID, NAME, ADDRESS, CITY, STATE, ZIP, \ + INCOME, PREMIUM, CATEGORY, LOCATION) \ + AS (SELECT C.ID, C.NAME, C.ADDRESS, C.CITY, C.STATE, C.ZIP, \ + C.INCOME, C.PREMIUM, C.CATEGORY, C.LOCATION \ + FROM CUSTOMERS C, FLOODZONES F \ + WHERE DB2GSE.ST_WITHIN(C.LOCATION, F.LOCATION) = 1)"; + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + printf("==========> Creating the 'highRiskCustomers' view ...\n"); + fflush(stdout); + + rc = SQLExecDirect(hstmt, createView, SQL_NTS); + CHECK_STMT(hstmt, rc); + + if (rc == SQL_ERROR || rc == SQL_INVALID_HANDLE) + printf("<========== Failed to create the 'highRiskCustomers' view with \ +return code %d.\n\n", rc); + else + printf("<========== The 'highRiskCustomers' view was successfully \ +created.\n\n"); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return rc; +} + + +/*======================================================================*/ +/* */ +/* stExportShape() */ +/* */ +/*======================================================================*/ +int stExportShape(char *fileName,int appendFlag,char *OutputColumnNames, + char *SelectStatement,char *messagesFile) +{ + SQLRETURN rc; + char outputColumnNames[1000]; + char selectStatement[1000]; + + SQLCHAR callExportShape[] + = "call db2gse.ST_export_shape (?,?,?,?,?,?,?)"; + + if(OutputColumnNames) + strcpy(outputColumnNames,OutputColumnNames); + + if(SelectStatement) + strcpy(selectStatement,SelectStatement); + + rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); + CHECK_DBC(hdbc, rc); + + rc = SQLPrepare(hstmt, callExportShape, SQL_NTS); + CHECK_STMT(hstmt, rc); + + ind[0] = SQL_NTS; + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 255, 0, fileName, 256, &ind[0]); + CHECK_STMT(hstmt, rc); + + ind[1] = (appendFlag == -1) ? SQL_NULL_DATA : SQL_NTS;; + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &appendFlag, 4, &ind[1]); + CHECK_STMT(hstmt, rc); + + ind[2] = (OutputColumnNames == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, sizeof(outputColumnNames)-1, 0, + outputColumnNames, sizeof(outputColumnNames), + &ind[2]); + CHECK_STMT(hstmt, rc); + + + ind[3] = (SelectStatement == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, sizeof(selectStatement)-1, 0, + selectStatement, sizeof(selectStatement), &ind[3]); + CHECK_STMT(hstmt, rc); + + ind[4] = (messagesFile == NULL) ? SQL_NULL_DATA : SQL_NTS; + rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, + SQL_VARCHAR, 255, 0, messagesFile, 256, &ind[4]); + CHECK_STMT(hstmt, rc); + + ind[5] = 0; + rc = SQLBindParameter(hstmt, 6, SQL_PARAM_OUTPUT, SQL_C_LONG, + SQL_INTEGER, 0, 0, &retCode, 4, &ind[5]); + CHECK_STMT(hstmt, rc); + + ind[6] = 0; + rc = SQLBindParameter(hstmt, 7, SQL_PARAM_OUTPUT, SQL_C_CHAR, + SQL_VARCHAR, (sizeof(reserved)-1), 0, reserved, + sizeof(reserved), &ind[6]); + CHECK_STMT(hstmt, rc); + + printf("==========> Exporting spatial column and data ...\n"); + fflush(stdout); + rc = SQLExecute(hstmt); + CHECK_STMT(hstmt, rc); + + if (retCode != 0) + printf("<========== Failed to export spatial column with return \ +code=%d test=%s\n\n", retCode,reserved); + else + printf("<========== The spatial column was successfully exported\n\n"); + + rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); + CHECK_STMT(hstmt, rc); + + return retCode; +} +/*======================================================================*/ +/* */ +/* gseRunSpatialQueries() */ +/* */ +/*======================================================================*/ +int gseRunSpatialQueries(SQLHANDLE hdbc, char *queryStmt, char * queryTxt) +{ + SQLRETURN sqlrc = SQL_SUCCESS; + SQLINTEGER rc = 0; + SQLHANDLE hstmt ; + + SQLSMALLINT i; + SQLSMALLINT nResultCols; + + SQLCHAR colName[32]; + SQLSMALLINT colNameLen; + SQLSMALLINT colType; + SQLUINTEGER colSize; + SQLSMALLINT colScale; + + SQLINTEGER colDataDisplaySize; + SQLINTEGER colDisplaySize[MAX_COLUMNS]; + + struct + { + SQLCHAR *buff; + SQLINTEGER len; + SQLINTEGER buffLen; + } outData[MAX_COLUMNS]; /* var. to read the results */ + + int rows_found = 0; + + /* allocate a statement handle */ + sqlrc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) ; + DBC_HANDLE_CHECK(hdbc, sqlrc); + + printf("=============== RUNNING SPATIAL QUERY ================\n"); + /* execute directly the statement */ + printf("%s.\n", queryStmt); + printf("\n%s\n", queryTxt); + sqlrc = SQLExecDirect( hstmt, (SQLCHAR *) queryStmt, SQL_NTS ) ; + STMT_HANDLE_CHECK( hstmt, sqlrc); + + + /*" Identify the output columns, then \n"*/ + /*" fetch each row and display.\n"*/ + sqlrc = SQLNumResultCols( hstmt, &nResultCols ) ; + STMT_HANDLE_CHECK( hstmt, sqlrc); + + printf("\n "); + + for ( i = 0; i < nResultCols; i++ ) + { + sqlrc = SQLDescribeCol( hstmt, + ( SQLSMALLINT ) ( i + 1 ), + colName, + sizeof(colName), + &colNameLen, + &colType, + &colSize, + &colScale, + NULL ) ; + STMT_HANDLE_CHECK( hstmt, sqlrc); + + /* get display size for column */ + sqlrc = SQLColAttribute( hstmt, + ( SQLSMALLINT ) ( i + 1 ), + SQL_DESC_DISPLAY_SIZE, + NULL, + 0, + NULL, + &colDataDisplaySize ) ; + STMT_HANDLE_CHECK( hstmt, sqlrc); + + /* set "column display size" to max of "column data display size", + and "column name length". Plus at least one space between + columns. + */ + colDisplaySize[i] = max(colDataDisplaySize, colNameLen) + 1 ; + + /* print the column name */ + printf( "%-*.*s", + (int) colDisplaySize[i], + (int) colDisplaySize[i], + colName ) ; + + /* set "output data buffer length" to "column data display size". + Plus one byte for null terminator. + */ + outData[i].buffLen = colDataDisplaySize + 1; + + /* allocate memory to bind column */ + outData[i].buff = ( SQLCHAR * ) malloc( (int) outData[i].buffLen ) ; + + /* bind columns to program vars, converting all types to CHAR */ + sqlrc = SQLBindCol( hstmt, + ( SQLSMALLINT ) ( i + 1 ), + SQL_C_CHAR, + outData[i].buff, + outData[i].buffLen, + &outData[i].len ) ; + STMT_HANDLE_CHECK( hstmt, sqlrc); + } + + printf( "\n" ) ; + rows_found = 0; + + /* fetch each row and display */ + sqlrc = SQLFetch( hstmt ) ; + STMT_HANDLE_CHECK( hstmt, sqlrc); + + if (sqlrc == SQL_NO_DATA_FOUND) + printf("\n No rows found.\n"); + + while ( sqlrc != SQL_NO_DATA_FOUND ) + { + rows_found++; + printf(" "); + for ( i = 0; i < nResultCols; i++ ) + { + /* check for NULL data */ + if ( outData[i].len == SQL_NULL_DATA ) + printf( "%-*.*s", (int) colDisplaySize[i], (int) colDisplaySize[i], + "NULL" ) ; + else /* print outData for this column */ + printf("%-*.*s", (int) colDisplaySize[i], (int) colDisplaySize[i], + outData[i].buff); + } /* for all columns in this row */ + + printf("\n"); + sqlrc = SQLFetch( hstmt ) ; + STMT_HANDLE_CHECK( hstmt, sqlrc); + } /* while rows to fetch */ + printf("\n"); + /* free data buffers */ + for (i = 0; i < nResultCols; i++) + free( outData[i].buff ); + + /* free the statement handle */ + sqlrc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ; + STMT_HANDLE_CHECK( hstmt, sqlrc); + + if (rows_found > 0) + printf("<========== The spatial query was executed successfully\n"); + else + { + printf("<========== Spatial query failed to return any data\n"); + rc = SQL_ERROR; + } + + return(rc); +} + + +/*=================================================================*/ +/* Enable Spatial Database */ +/*=================================================================*/ +int EnableDB() +{ + rc = stEnableDB(); + GseCheck(rc); + return(rc); +} + +/*=================================================================*/ +/* Disable Spatial Database */ +/*=================================================================*/ +int DisableDB(void) +{ + rc = stDisableDB(-1); + GseCheck(rc); + return(rc); +} + + +/*=================================================================*/ +/* TEST OF Enable/disable Spatial Database */ +/*=================================================================*/ +/* */ +/* (1) Enable the spatial database */ +/* (2) Disable the spatial database */ +/* (3) Enable the spatial database again */ +/* */ +/*=================================================================*/ +int TestEnableDisable() +{ + printf("START: TestEnableDisable()\n"); + rc = stEnableDB(); + GseCheck(rc); + + rc = stDisableDB(-1); + GseCheck(rc); + + rc = stEnableDB(); + GseCheck(rc); + + return(rc); +} + +/*=================================================================*/ +/* Test of Creating/Dropping Coordinate systems */ +/*=================================================================*/ +/* */ +/* (1) Create Coordinate System "NORTH_AMERICAN" */ +/* (2) Drop Coordinate System "NORTH_AMERICAN" */ +/* (3) Create Coordinate System "KY_STATE_PLANE" */ +/* */ +/*=================================================================*/ +int TestCoordinateSystem(void) +{ + printf("START: TestCoordinateSystem()\n"); + /*====================Created and dropped ======================*/ + rc = stCreateCS ("NORTH_AMERICAN", + "GEOGCS[\"GCS_North_American_1983\",\ +DATUM[\"D_North_American_1983\",\ +SPHEROID[\"GRS_1980\",6378137,298.257222101]],\ +PRIMEM[\"Greenwich\",0],\ +UNIT[\"Degree\",0.0174532925199432955]]", + "EPSG", + 1001, + "Test Coordinate Systems"); + GseCheck(rc); + + rc = stDropCS ("NORTH_AMERICAN"); + GseCheck(rc); + + /*=====================Created and used ========================*/ + rc = stCreateCS ("KY_STATE_PLANE", + "\ +PROJCS[\"NAD_1983_StatePlane_Kentucky_South_FIPS_1602_Feet\",\ +GEOGCS[\"GCS_North_American_1983\",\ +DATUM[\"D_North_American_1983\",\ +SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],\ +PRIMEM[\"Greenwich\",0.0],\ +UNIT[\"Degree\",0.0174532925199433]],\ +PROJECTION[\"Lambert_Conformal_Conic\"],\ +PARAMETER[\"False_Easting\",1640416.666666667],\ +PARAMETER[\"False_Northing\",1640416.666666667],\ +PARAMETER[\"Central_Meridian\",-85.75],\ +PARAMETER[\"Standard_Parallel_1\",36.73333333333333],\ +PARAMETER[\"Standard_Parallel_2\",37.93333333333333],\ +PARAMETER[\"Latitude_Of_Origin\",36.33333333333334],\ +UNIT[\"Foot_US\",0.3048006096012192]]", + "ESRI", + 1002, + "Coordinate System used for Customers Table"); + + GseCheck(rc); + + return(rc); +} + +/*=================================================================*/ +/* Test the Creation/Drop of spatial reference systems */ +/*=================================================================*/ +/* */ +/* (1) Create the spatial reference system SRSDEMO1 */ +/* (2) Drop the spatial reference system SRSDEMO1 */ +/* (3) Create and use the spatial reference system KY_PROJ_SRS */ +/* */ +/* Note: */ +/* SRSDEMO1 is based on a geographic coordinate system whereas */ +/* KY_STATE_SRS uses a state plane system for Kentucky State. */ +/* */ +/* SRSDEMO1 has */ +/* cs: NORTH_AMERICAN */ +/* srsId : 100001 srsName: SRSDEMO1 */ +/* xOffset: -180 xScale : 5965232 */ +/* yOffset: -90 yScale : 5965232 */ +/* zOffset: 0 zScale : 1 */ +/* mOffset: 0 mScale : 1 */ +/* */ +/* KY_STATE_SRS has */ +/* cs: KY_PROJ_CS */ +/* srsId : 100002 srsName: KY_PROJ_SRS */ +/* xOffset: 0 xScale : 10 */ +/* yOffset: 0 yScale : 10 */ +/* zOffset: 0 zScale : 1 */ +/* mOffset: 0 mScale : 1 */ +/* */ +/*=================================================================*/ +int TestSRS(void) +{ + printf("START: TestSRS() for Spatial Reference System SRSDEMO1\n"); + /*====================Created and dropped ======================*/ + rc = stCreateSRS("SRSDEMO1",100001,-180,5965232,-90,5965232,0,1,0,1, + "GCS_NORTH_AMERICAN_1983", + "GSE Demo Program: test SRS"); + GseCheck(rc); + + rc = stDropSRS("SRSDEMO1"); + GseCheck(rc); + + /*======================Create KY_PROJ_SRS=======================*/ + /* The Spatial References System is based on a coordinate system */ + /* and defines additional offset values and scale factors to be */ + /* used by spatial extender routines to convert floating point */ + /* external representation to the internal integer representation*/ + /* */ + /* The x and y coordinate values in the Kentucky coordinate */ + /* will always be 0 so we just use x and y offsets of 0. */ + /* */ + /* The scale factor is set to 10 which will preserve precision */ + /* to at least a foot. */ + /*===============================================================*/ + + rc = stCreateSRS("KY_PROJ_SRS",100002,0,10,0,10,0,1,0,1, + "KY_STATE_PLANE", + "GSE Demo Program: customers table"); + GseCheck(rc); + + return(rc); + +} + +/*=================================================================*/ +/* Test creation of spatial tables */ +/*=================================================================*/ +int CreateSpatialTables(void) +{ + printf("START: CreateSpatialTables()\n"); + rc = gseSetupTables(); + GseCheck(rc); + + return(rc); +} + +/*=================================================================*/ +/* Test creation of geocoder */ +/*=================================================================*/ +int TestCreateLatLongGeocoder(void) +{ + printf("START: CreateLatLongGeocoder()\n"); + rc = gseCreateLatLongGeocoder(); + GseCheck(rc); + + return(rc); +} +/*=================================================================*/ +/* Test registration of spatial columns */ +/*=================================================================*/ +/* */ +/* (1) Register the customers/location column */ +/* (2) Unregister the customers/location column from step (1) */ +/* (3) Reregister the customers/location column from step (1) */ +/* (4) Register the offices/location column */ +/* */ +/*=================================================================*/ +int TestRegisterSpatialColumn(void) +{ + printf("START: TestRegisterSpatialColumn()\n"); + /*==============Register and unregister test ===================*/ + /* ---- Checking to see if the SRSDEMO1 was created indeed ---- */ + rc = stRegisterSpatialColumn(NULL,"CUSTOMERS", "LOCATION","NAD83_SRS_1"); + GseCheck(rc); + + rc = stUnregisterSpatialColumn(NULL, "CUSTOMERS", "LOCATION"); + GseCheck(rc); + + + /*======================Registered and used =======================*/ + rc = stRegisterSpatialColumn(NULL,"CUSTOMERS", "LOCATION","KY_PROJ_SRS"); + GseCheck(rc); + + rc = stRegisterSpatialColumn(NULL, "OFFICES", "LOCATION","KY_PROJ_SRS"); + GseCheck(rc); + /*=================================================================*/ + + return(rc); +} + +/*====================================================================*/ +/* Test registration of the geocoder */ +/*====================================================================*/ +/* */ +/* (1) Register a geocoder using DEFAULT geocoder UDF */ +/* (2) Unregister the geocoder registered in step (1) */ +/* (3) Register a geocoder using the projected coordinate system */ +/* for Kentucky data */ +/* */ +/*====================================================================*/ +int TestRegisterGeocoder(void) +{ + printf("START: TestRegisterGeocoder()\n"); + /*==============Register and unregister test =====================*/ + + /* In a first test we are going to register a geocoder SAMPLEGC */ + /* that uses a simple geocoder to convert latitude and */ + /* longitude into a spatial point value. */ + /* A set of parameters is used to adjust the geocoding function. */ + /* - column names that match LATITUDE and LONGITUDE */ + /* - the spatial reference system used for the result coordinates */ + /* is identified by the SRSID 1 */ + /* */ + /* The parameter description is left NULL and the vendor name is */ + /* DEFAULT. With the description 'Latitude & Longitude geocoder' */ + /* we have an additional field to distinguish between multiple */ + /* geocoder. */ + /* */ + /*================================================================*/ + + rc = stRegisterGc("SAMPLEGC","db2se","LATLONGGC","LATLONGGC", + "LATITUDE,LONGITUDE,1", + NULL,"DEFAULT","Latitude & Longitude geocoder"); + GseCheck(rc); + + rc = stUnregisterGc("SAMPLEGC"); + GseCheck(rc); + + /*=====================Registered and used ======================*/ + /* For the next geocoder setup we use the same values as above. */ + /* Only the SRSID 100002 points to a the KY_PROJ_SRS spatial */ + /* reference system created in TestSRS(). The KY_PROJ_SRS is */ + /* based on a projected coordinate system rather than a */ + /* geographic coordinate system. For some spatial analysis below */ + /* we need the customer data in a projected coordinate system */ + /* and avoid a transformation if we have the geocoder to produce */ + /* the required projection already. */ + /*===============================================================*/ + + rc = stRegisterGc("KY_STATE_GC","db2se","LATLONGGC","LATLONGGC", + "LATITUDE,LONGITUDE,1000002", + NULL,"DEFAULT","Geocoder for Kentucky State Coordinates"); + GseCheck(rc); + /*=================================================================*/ + + return(rc); +} + +/*=================================================================*/ +/* */ +/* Test setup of Geocoders for the spatial columns */ +/* */ +/*=================================================================*/ +int TestSetupGeocoder(void) +{ + printf("START: TestSetupGeocoder()\n"); + /** Checking to see if the geocoder(KY_STATE_GC) was registered correctly **/ + + rc = stSetupGeocoding(NULL, "CUSTOMERS", "LOCATION","KY_STATE_GC", + "LATITUDE,LONGITUDE,100002",NULL,NULL,-1); + GseCheck(rc); + + rc = stRemoveGeocodingSetup(NULL, "CUSTOMERS", "LOCATION"); + GseCheck(rc); + + /****************** Checking just the setup geocoding ********************/ + rc = stSetupGeocoding(NULL, "CUSTOMERS", "LOCATION","KY_STATE_GC", + "LATITUDE,LONGITUDE,100002",NULL,NULL,-1); + GseCheck(rc); + + /*-----------------------------------------------------------------------*/ + + return(rc); +} + + +/*=================================================================*/ +/* Test the geocoding of the spatial columns */ +/*=================================================================*/ +/* */ +/* Geocode the customers/location column using the KY_STATE_GC */ +/* geocoder from above. */ +/* */ +/*=================================================================*/ +int TestGeocoder(void) +{ + printf("START: TestGeocoder()\n"); +/*========== Testing Geocoding with registered Geocoder ===========*/ + rc = stRunGC(NULL, "CUSTOMERS", "LOCATION","KY_STATE_GC", + "LATITUDE,LONGITUDE,100002",NULL,0); + GseCheck(rc); + + return(rc); +} + +/*=================================================================*/ +/* */ +/* Test of InportShape procedure */ +/* Populating the spatial column... */ +/* */ +/*=================================================================*/ +int TestImportShape(void) +{ + char tmpbuf[100]; + char tmpbuf2[100]; + time_t xtime; + + printf("START: TestImportShape()\n"); + time(&xtime); + /*---------------------------------------------------------------*/ + gseBuildSampleFolder(path,"offices"); + sprintf(tmpbuf,"importOffices.log_%i",xtime); + sprintf(tmpbuf2,"importOffices.err_%i",xtime); + gseBuildTempFolder(msgpath,tmpbuf); + gseBuildTempFolder(exceptionpath,tmpbuf2); + rc=stImportShape(path,NULL,"KY_PROJ_SRS",NULL,"OFFICES",NULL, + 0,NULL,"LOCATION",NULL,NULL,-1, + NULL,-1,-1,-1,exceptionpath,msgpath); + GseCheck(rc); + /*---------------------------------------------------------------*/ + gseBuildSampleFolder(path,"floodzones"); + sprintf(tmpbuf,"importFloodzones.log_%i",xtime); + sprintf(tmpbuf2,"importFloodzones.err_%i",xtime); + gseBuildTempFolder(msgpath,tmpbuf); + gseBuildTempFolder(exceptionpath,tmpbuf2); + rc =stImportShape(path,NULL,"KY_PROJ_SRS",NULL,"FLOODZONES",NULL, + 1,NULL,"LOCATION",NULL,NULL,-1, + NULL,-1,-1,-1,exceptionpath,msgpath); + GseCheck(rc); + /*------------------------------------------------------------------*/ + gseBuildSampleFolder(path,"regions"); + sprintf(tmpbuf,"importRegions.log_%i",xtime); + sprintf(tmpbuf2,"importRegions.err_%i",xtime); + gseBuildTempFolder(msgpath,tmpbuf); + gseBuildTempFolder(exceptionpath,tmpbuf2); + rc =stImportShape(path,NULL,"KY_PROJ_SRS",NULL,"REGIONS",NULL, + 1,NULL,"LOCATION",NULL,NULL,-1, + NULL,-1,-1,-1,exceptionpath,msgpath); + GseCheck(rc); + /*------------------------------------------------------------------*/ + + return(rc); +} + +/*====================================================================*/ +/* Test Enable/Drop spatial indexes */ +/*====================================================================*/ +/* */ +/* (1) Create/Drop spatial index for the customers/location column */ +/* (2) Enable spatial index for all spatial tables */ +/* */ +/*====================================================================*/ +int TestIndexes(void) +{ + printf("START: TestIndexes()\n"); + + /* The following data have been generated in a test run on + CUSTOMERS.LOCATION: + +Number of Rows: 338 +Number of non-empty Geometries: 333 +Number of empty Geometries: 5 +Number of null values: 0 + + +Extent covered by data: + Minimum X: 1114636.300000 + Maximum X: 2435792.500000 + Minimum Y: 1762676.500000 + Maximum Y: 2651005.100000 + + Suggested Grid Sizes: + --------------------- + Size 0: 5000 + Size 1: 0 + Size 2: 0 */ + + rc = gseCLICreateIndex("CUSTOMERS","LOCATION","CUSTOMERSLOC", "5000.0, 0.0, 0.0"); + GseCheck(rc); + + rc = gseCLIDropIndex("CUSTOMERSLOC"); + GseCheck(rc); + + rc = gseCLICreateIndex("CUSTOMERS","LOCATION","CUSTOMERSLOC", "5000.0, 0.0, 0.0"); + GseCheck(rc); + + /* The following data have been generated in a test run on + OFFICES.LOCATION: + +Number of Rows: 31 +Number of non-empty Geometries: 31 +Number of empty Geometries: 0 +Number of null values: 0 + + +Extent covered by data: + Minimum X: 1260842.000000 + Maximum X: 2312300.500000 + Minimum Y: 1861630.200000 + Maximum Y: 2619517.400000 + + Suggested Grid Sizes: + --------------------- + Size 0: 5000 + Size 1: 0 + Size 2: 0 */ + + rc = gseCLICreateIndex("OFFICES", "LOCATION","OFFICESLOC", "5000.0, 0.0, 0.0"); + GseCheck(rc); + + /* The following data have been generated in a test run on + FLOODZONES.LOCATION: + +Number of Rows: 38 +Number of non-empty Geometries: 38 +Number of empty Geometries: 0 +Number of null values: 0 + + +Extent covered by data: + Minimum X: 1267927.700000 + Maximum X: 2443079.200000 + Minimum Y: 2014026.400000 + Maximum Y: 2644878.300000 + + Suggested Grid Sizes: + --------------------- + Size 0: 3900 + Size 1: 23000 + Size 2: 46000 */ + + rc = gseCLICreateIndex("FLOODZONES", "LOCATION","BOUNDARYLOC", "3900.0, 23000.0, 46000.0"); + GseCheck(rc); + + /* The following data have been generated in a test run on + REGIONS.LOCATION: + +Number of Rows: 3 +Number of non-empty Geometries: 3 +Number of empty Geometries: 0 +Number of null values: 0 + + +Extent covered by data: + Minimum X: 562573.500000 + Maximum X: 2739247.900000 + Minimum Y: 1708027.300000 + Maximum Y: 2664796.800000 + + Suggested Grid Sizes: + --------------------- + Size 0: 95000 + Size 1: 450000 + Size 2: 0 */ + + rc = gseCLICreateIndex("REGIONS", "LOCATION","REGIONLOC", "95000.0, 450000.0, 0.0"); + GseCheck(rc); + + return(rc); +} + +/*=================================================================*/ +/* */ +/* Automatic geocoder and indexes test */ +/* */ +/*=================================================================*/ +int TestAutoGC(void) +{ + printf("START: TestAutoGC() Automatic geocoder and indexes test\n"); + rc = stRemoveGeocodingSetup(NULL, "CUSTOMERS", "LOCATION"); + GseCheck(rc); + + /*====================================================================*/ + /* (1) Register the automatic geocoder for the customers/location */ + /* column */ + /*====================================================================*/ + rc = stSetupGeocoding(NULL, "CUSTOMERS", "LOCATION","KY_STATE_GC", + "LATITUDE,LONGITUDE,100002","LATITUDE, LONGITUDE",NULL,-1); + GseCheck(rc); + + rc = stEnableAutoGC(NULL, "CUSTOMERS", "LOCATION"); + GseCheck(rc); + /*=================================================================*/ + /* (1) Insert some tuples with different street number */ + /* (2) Update some tuples with new address */ + /* (3) Delete some tuples from the table */ + /*=================================================================*/ + rc = gseInsDelUpd(); + GseCheck(rc); + + return(rc); +} + +/*=================================================================*/ +/* */ +/* Create a view and register it as a spatial column */ +/* Perform spatial analysis */ +/* */ +/*=================================================================*/ +int TestViewsAndQueries(void) +{ + +/****************************************************************************/ + SQLCHAR query1txt[] = "Number of customers served by each region:"; + + SQLCHAR query1[] + = "SELECT R.NAME, COUNT(C.NAME) AS CUSTOMERS \n \ + FROM CUSTOMERS C, REGIONS R \n \ + WHERE DB2GSE.ST_WITHIN(C.LOCATION, R.LOCATION) = 1 \n \ + GROUP BY R.NAME ORDER BY R.NAME"; + +/****************************************************************************/ + SQLCHAR query2txt[] = "For offices and customers within each region, \ +the number of \n customers that are within 10 miles of each office:"; + + SQLCHAR query2[] = + "SELECT R.NAME AS REGION_NAME, O.NAME AS OFFICE_NAME, \n \ + COUNT(C.NAME) AS CUSTOMERS \n \ + FROM CUSTOMERS C, REGIONS R, OFFICES O \n \ + WHERE DB2GSE.ST_DISTANCE(C.LOCATION, O.LOCATION, 'STATUTE MILE') < 10.0 AND \n \ + DB2GSE.ST_WITHIN(O.LOCATION, R.LOCATION) = 1 \n \ + GROUP BY R.NAME, O.NAME ORDER BY R.NAME,O.NAME"; + +/****************************************************************************/ + SQLCHAR query3txt[] = "For each region the average income and premium of \ +its customers:"; + + SQLCHAR query3[] = + "SELECT R.NAME, DECIMAL(AVG(C.INCOME),8,2) AS INCOME, \n \ + DECIMAL(AVG(C.PREMIUM),8,2) AS PREMIUM \n \ + FROM CUSTOMERS C, REGIONS R \n \ + WHERE DB2GSE.ST_WITHIN(C.LOCATION, R.LOCATION) = 1 \n \ + GROUP BY R.NAME ORDER BY R.NAME"; + +/****************************************************************************/ + SQLCHAR query4txt[] = "List of flood zones that cross specific region \ +boundaries:"; + + SQLCHAR query4[] = + "SELECT FZ.NAME FROM FLOODZONES FZ, REGIONS R1, REGIONS R2 \n \ + WHERE (RTRIM(R1.NAME) = 'Kentucky Central' AND \n \ + DB2GSE.ST_OVERLAPS(FZ.LOCATION, R1.LOCATION) = 1) \n \ + AND \n \ + (RTRIM(R2.NAME) = 'Kentucky West' AND \n \ + DB2GSE.ST_OVERLAPS(FZ.LOCATION, R2.LOCATION) = 1) ORDER BY FZ.NAME"; + +/****************************************************************************/ + SQLCHAR query5txt[] = "Minimum distance from a specific customer to the \ +nearest office:"; + + SQLCHAR query5[] = + "WITH TEMP(CUSTOMER,ID,OFFICE, DISTANCE) AS \n \ + (SELECT C.NAME,C.ID,O.NAME,\n \ + DB2GSE.ST_DISTANCE(C.LOCATION, O.LOCATION, 'STATUTE MILE')\n \ + FROM CUSTOMERS C, OFFICES O \n \ + WHERE C.ID = 80708 ) \n \ + SELECT DISTINCT ID,CUSTOMER, OFFICE, \n \ + DECIMAL(DISTANCE,6,2) AS DISTANCE \n \ + FROM TEMP \n \ + WHERE DISTANCE = \n \ + (SELECT MIN(DISTANCE) \n \ + FROM TEMP)"; + +/****************************************************************************/ + SQLCHAR query6txt[] = "Customers located within half a mile of flood zone 'Boone':"; + + SQLCHAR query6[] = + "SELECT C.NAME FROM CUSTOMERS C, FLOODZONES FZ \n \ + WHERE RTRIM(FZ.NAME) = 'Boone' AND \n \ + DB2GSE.ST_DISTANCE(FZ.LOCATION, C.LOCATION, 'STATUTE MILE') < 0.5 \n \ + ORDER BY C.NAME"; + +/****************************************************************************/ + SQLCHAR query7txt[] = "High risk customers located within 2 miles of the \ +offices:"; + + SQLCHAR query7[] = + "SELECT HR.NAME FROM HIGHRISKCUSTOMERS HR, OFFICES O \n \ + WHERE DB2GSE.ST_WITHIN(HR.LOCATION, \n \ + DB2GSE.ST_BUFFER(O.LOCATION, 2, 'STATUTE MILE'))=1 ORDER BY HR.NAME"; + +/****************************************************************************/ + + printf("START: TestViewsAndQueries()\n"); + /*=================================================================*/ + /* (1) Create a view, highRiskCustomers, based on the spatial */ + /* join of the customers locations and the the hazardZones */ + /* using the spatial function ST_WITHIN as join predicate. */ + /* (2) Register this view as a spatial column */ + /*=================================================================*/ + rc = gseCreateView(); + GseCheck(rc); + + rc = stRegisterSpatialColumn(NULL, "HIGHRISKCUSTOMERS", "LOCATION", + "KY_PROJ_SRS"); + GseCheck(rc); + + /*=================================================================*/ + /* (1) Find the average customer distance from each office */ + /* (within, distance) */ + /* (2) Find the average customer income and premium for each */ + /* office (within) */ + /* (3) Find customers who is not covered by any existing office */ + /* (within) */ + /* (4) Find the number of hazard zones each office zone overlaps */ + /* with (overlap) */ + /* (5) Find the minimum distance from a particular customer */ + /* location to the surrounding offices. */ + /* (6) Find the customers whose location is close to the boundary */ + /* of a particular hazard zone (buffer, overlap) */ + /* (7) Find those high risk customers who is covered by a */ + /* particular office */ + /*=================================================================*/ + + /* Remove non-spatial query about Gene + rc = gseRunSpatialQueries(hdbc, "SELECT id, name \nFROM customers \n\ +WHERE name like 'Gene%' ORDER BY id", "Get all the customers with name GENE"); + GseCheck(rc); + */ + + rc = gseRunSpatialQueries(hdbc, (char *) query1, (char *) query1txt); + GseCheck(rc); + + rc = gseRunSpatialQueries(hdbc, (char *) query2, (char *) query2txt); + GseCheck(rc); + + rc = gseRunSpatialQueries(hdbc, (char *) query3, (char *) query3txt); + GseCheck(rc); + + rc = gseRunSpatialQueries(hdbc, (char *) query4, (char *) query4txt); + GseCheck(rc); + + rc = gseRunSpatialQueries(hdbc, (char *) query5, (char *) query5txt); + GseCheck(rc); + + rc = gseRunSpatialQueries(hdbc, (char *) query6, (char *) query6txt); + GseCheck(rc); + + rc = gseRunSpatialQueries(hdbc, (char *) query7, (char *) query7txt); + GseCheck(rc); + + return(rc); + +} + +/*=================================================================*/ +/* Test the ExportShape procedure */ +/*=================================================================*/ +/* */ +/* (1) Export the 'highRiskCustomers' view */ +/* */ +/*=================================================================*/ +int TestExportShape(void) +{ + char tbuffer[100]; + char tbuffer2[100]; + time_t xtime; + + printf("START: TestExportShape()\n"); + time(&xtime); + sprintf(tbuffer,"hiRiskCustShape_%i",xtime); + sprintf(tbuffer2,"hiRiskCustMsg_%i",xtime); + gseBuildTempFolder(path,tbuffer); + gseBuildTempFolder(msgpath,tbuffer2); + printf("==========> Export from HighRiskCustomers view to Shapefile...\n"); + printf(" Path: %s\n", path); + printf(" Logfile: %s\n", msgpath); + fflush(stdout); + rc = stExportShape(path,-1,NULL,"SELECT * FROM HIGHRISKCUSTOMERS", + msgpath); + GseCheck(rc); + + return(rc); + +} + +/*=================================================================*/ +/* An interactive system for maintenance purposes */ +/*=================================================================*/ +int menu() +{ + + int choice = -1; + + while(choice!=99) + { + printf(" CHOOSE FROM ONE OF THE OPTIONS AND 99 TO EXIT\n"); + printf(" 1 - TestEnableDisable();\n"); + printf(" 2 - TestCoordinateSystem();\n"); + printf(" 3 - TestSRS();\n"); + printf(" 4 - CreateSpatialTables();\n"); + printf(" 5 - TestRegisterSpatialColumn();\n"); + printf(" 6 - TestRegisterGeocoder();\n"); + printf(" 7 - TestSetupGeocoder();\n"); + printf(" 8 - TestGeocoder();\n"); + printf(" 9 - TestImportShape();\n"); + printf(" 10 - TestIndexes();\n"); + printf(" 11 - TestAutoGC();\n"); + printf(" 12 - TestViewsAndQueries();\n"); + printf(" 13 - TestExportShape();\n"); + printf(" 14 - TestCreateLatLongGeocoder();\n"); + printf(" 15 - EnableDB();\n"); + printf(" 16 - DisableDB();\n"); + printf(" 99 - WrapUpDemo() - EXIT;\n"); + + scanf("%i",&choice); + switch(choice) + { + case 1: TestEnableDisable(); break; + case 2: TestCoordinateSystem(); break; + case 3: TestSRS(); break; + case 4: CreateSpatialTables(); break; + case 5: TestRegisterSpatialColumn(); break; + case 6: TestRegisterGeocoder(); break; + case 7: TestSetupGeocoder(); break; + case 8: TestGeocoder(); break; + case 9: TestImportShape(); break; + case 10:TestIndexes(); break; + case 11:TestAutoGC(); break; + case 12:TestViewsAndQueries(); break; + case 13:TestExportShape(); break; + case 14:TestCreateLatLongGeocoder(); break; + case 15:EnableDB(); break; + case 16:DisableDB(); break; + case 99:WrapUpDemo(); break; + } + } + return(0); +} + +/*======================================================================*/ +/* */ +/* The following scenario is used in this sample program to demonstrate */ +/* the typical usage of DB2 Spatial Extender: */ +/* */ +/* (1) Story: */ +/* (a) An insurance company having online "customers" data and */ +/* "offices" data for its daily operations would like to adopt */ +/* the spatial technology for enhancing the business. */ +/* (b) More precisely, they would like to use the spatial attribute */ +/* of the existing data to perform various kinds of spatial */ +/* analysis such as finding the average premium of customers in */ +/* a certain area, looking for those customers who need to be */ +/* evacuated if certain area gets flooded, etc. */ +/* (2) Data: */ +/* (a) Customers table consists of 1000 records. */ +/* (b) Offices table consists of 120 records. */ +/* (c) HazardZones table consists of 3551 records. */ +/* (3) Major steps: */ +/* (a) Enable the database with spatial capability. */ +/* (b) Register spatial reference systems for the spatial data: */ +/* * The "location" column of the "customers" table. */ +/* * The "location" column of the "offices" table. */ +/* * The "zone" column of the "offices" table. */ +/* * The "boundary" column of the "hazardZones" table. */ +/* (c) Register the spatial columns */ +/* * The "location" column of the "customers" table. */ +/* * The "location" column of the "offices" table. */ +/* * The "zone" column of the "offices" table. */ +/* * The "boundary" column of the "hazardZones" table will be */ +/* registered by the shape file loader. */ +/* (c) Populate the spatial data: */ +/* * Geocoding the customers.location column based on the */ +/* address columns of the same table. */ +/* */ +/*======================================================================*/ + +/*======================================================================*/ +/* */ +/* main(argc, argv) */ +/* */ +/*======================================================================*/ +int main(int argc, char * argv[]) +{ + SQLRETURN rc; + + struct sqlfupd l_sqlfupd; + short applheapsz = 0; + short logprimary = 0; + short logfilsz = 0; + char yn_reply[4]; + + int dbExists = 0; + + if (argc > 5 || (argc >=2 && + ((strncmp(argv[1],"-h",2)==0)||(strncmp(argv[1],"-?",2)==0)))) + { + printf( + "Syntax for runGseDemo - Spatial Extender demo program: \n" + " runGseDemo db_name [userid password [AbortOnError(y/n)?] ]\n"); + printf("\nFor interactive input, type runGseDemo with no arguments. \n"); + +#ifdef _NOW32OS + printf( + "\n==>To save the GSE Demo output, the tee program can be helpful.\n"); + printf( + "Examples: \n"); + printf( + " runGseDemo | tee OR \n"); + printf( + " runGseDemo | tee \n"); + printf( + "Be sure is in a directory where you have write permissions.\n"); + printf( + "\n==> It is recommended to create a directory for temp files that are\n"); + printf( + "generated when runGseDemo executes. Set the environment variable \n"); + printf( + "DEMO_TMPDIR to the full path to that directory.\n"); +#endif + return(0); + } + + if (argc == 5) + { + strcpy((char *)dbase, argv[1]); + strcpy((char *)uid, argv[2]); + strcpy((char *)pwd, argv[3]); + strcpy((char *)AbChoice, argv[4]); + } + else + if (argc == 4) + { + strcpy((char *)dbase, argv[1]); + strcpy((char *)uid , argv[2]); + strcpy((char *)pwd , argv[3]); + } + else + if (argc == 2) + strcpy((char *)dbase , argv[1]); + else + { + printf("Interactive Mode. [For more info, use -? or -h] \n"); + printf("Do you wish to continue in Interactive Mode? (y/n) \n"); + fgets(yn_reply, sizeof(yn_reply), stdin); + if ((yn_reply[0]!='y') && (yn_reply[0]!='Y')) + { + printf("Exiting runGseDemo program at user request. \n"); + exit(0); + } + printf("Enter database name:\n"); + fgets((char *) dbase, sizeof(dbase), stdin); + + /* discard the newline character in the dbase name */ + if (dbase[strlen((char *) dbase) - 1] == '\n') + dbase[strlen((char *) dbase) - 1] = 0; + + printf("Enter userid or hit ENTER to use your userid:\n"); + fgets((char *) uid, sizeof(uid), stdin); + + /* discard the newline character in the user id */ + if (uid[strlen((char *) uid) - 1] == '\n') + uid[strlen((char *) uid) - 1] = 0; + + printf("Enter password or hit ENTER to use your password:\n"); + fgets((char *) pwd, sizeof(pwd), stdin); + + /* discard the newline character in the password */ + if (pwd[strlen((char *) pwd) - 1] == '\n') + pwd[strlen((char *) pwd) - 1] = 0; + + printf("Want to abort if any error occurs?(y/n) DEFAULT = y: "); + fgets((char *) AbChoice, 4, stdin); + + /* discard the newline character for the y/n answer */ + if (AbChoice[strlen((char *) AbChoice) - 1] == '\n') + AbChoice[strlen((char *) AbChoice) - 1] = 0; + } + + // in case we have a valid y\n answer we are going to proceed + // if we got a @ we will show a debug menu for maintenance purposes + if((AbChoice[0]=='y')||(AbChoice[0]=='Y')|| + (strcmp((char *)AbChoice,"")==0)) + CheckRC=1; + else + { + CheckRC=0; + if(AbChoice[0]=='@') + domenu=1; + } + + /*=================================================================*/ + /* Initialize the Spatial Extender runGseDemo program */ + /*=================================================================*/ + /* */ + /* (1) Initialize the CLI environment (ENV and DB) */ + /* (2) Check if the database exists */ + /* (3) Update some database configuration parameters */ + /* (4) Connect to the database */ + /*=================================================================*/ + + printf("==========> Initializing the Spatial Extender runGseDemo program \ +...\n"); + fflush(stdout); + if (getenv("DB2PATH") == NULL) + { + printf( + "<========== Failed to find the DB2PATH environment variable. \n"); + printf( + " Please set DB2PATH to the full path to sqllib for this instance.\n"); + printf("\n runGseDemo exiting. \n"); + exit(0); + } + + /*====================================================================*/ + /* (1) We allocate the environment handle and a database handle. The */ + /* database does not necessarily have to exist in order to allocate a */ + /* database handle. But we can not connect to the database without an */ + /* handle. */ + /*====================================================================*/ + rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + if (rc != SQL_SUCCESS) + { + printf("<========== Fail to allocate (henv) environment handle\ +=============>.\n\n"); + + terminate(henv, rc); + return (1); + } + + rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); + if (rc != SQL_SUCCESS) + { + printf("<========== Fail to allocate hdbc(database) handle\ +=============>.\n\n"); + + terminate(henv, rc); + return (1); + } + + /*====================================================================*/ + /* (2) We try to retrieve some database configuration parameter. If */ + /* this is not successful and returns a SQL1013 the database does not */ + /* exist. We will then ask the user if we should create the database. */ + /*====================================================================*/ + + l_sqlfupd.token = SQLF_DBTN_APPLHEAPSZ; + l_sqlfupd.ptrvalue = (char*)&applheapsz; + + rc = sqlfxdb((_SQLOLDCHAR *)dbase, 1, &l_sqlfupd, &sqlca); + + /*====================================================================*/ + /* Check the return code to see if we were successful. */ + /* YES: => set dbExists =1 */ + /* SQL1013: database does not exist => set dbExists = 0 */ + /* SQL1032: instance is not started => return with error */ + /* DEFAULT: => return with error */ + /*====================================================================*/ + + switch ( sqlca.sqlcode ) + { + case SQL_RC_OK: + dbExists = 1; + break; + + case SQLE_RC_NODB: /* SQL1013 */ + dbExists = 0; + /* For UNIX, we require the database to already exist. */ +#ifdef _NOW32OS + printf("<========== Database [%s] does not exist.\n", dbase); + printf(" The database must be created before running the sample\n"); + return(1); +#endif + break; + + case SQLE_RC_NOSTARTG: /* SQL1032 */ + printf("<========== The database instance is not started.\ + Please execute the `db2start` command before you proceed.\n"); + return(1); + break; + + default: + printf("<========== Failed to retrieve db cfg with return \ +code %d.\n", sqlca.sqlcode); + return(1); + } + + // If the database does not exist we ask the user for permission to create. + if (dbExists == 0) + { + printf("The database does not seem to exist. Do you want the demo \ +program to create a database '%s' in your local database directory? \ +(y/n) DEFAULT = y: ", &dbase); + + fgets((char *) AbChoice, 4, stdin); + + /* discard the newline character for the y/n answer */ + if (AbChoice[strlen((char *) AbChoice) - 1] == '\n') + AbChoice[strlen((char *) AbChoice) - 1] = 0; + + // If the answer is yes we create the database now + if((AbChoice[0]=='y') || (AbChoice[0]=='Y') || + (strcmp((char *)AbChoice,"")==0)) + { + rc = createDb((char*) dbase); + + // If even the create database statement failed, we have to + // return with error + if (rc != 0) return(1); + } + } + + /*==================================================================*/ + /* (3) We now try to udpate the following database parameters: */ + /* - APPLHEAPSZ */ + /* - LOGPRIMARY */ + /* - LOGFILSIZ */ + /* as recommended in the users guide. */ + /*==================================================================*/ + + /*==================================================================*/ + /* APPLHEAPSZ */ + /*==================================================================*/ + + l_sqlfupd.token = SQLF_DBTN_APPLHEAPSZ; + l_sqlfupd.ptrvalue = (char*)&applheapsz; + + rc = sqlfxdb((_SQLOLDCHAR *)dbase, 1, &l_sqlfupd, &sqlca); + + if (sqlca.sqlcode != 0) + { + + printf("<========== Failed to retrieve db cfg APPLHEAPSZ with return \ +code %d.\n", sqlca.sqlcode); + return(1); + } + + if (applheapsz < MIN_APPLHEAPSZ) + { + applheapsz = MIN_APPLHEAPSZ; + + rc = sqlfudb((_SQLOLDCHAR *)dbase, 1, &l_sqlfupd, &sqlca); + + if (sqlca.sqlcode != 0) + { + printf("<========== Failed to update db cfg APPLHEAPSZ with return \ +code %d.\n", sqlca.sqlcode); + return(1); + } + } + + /*==================================================================*/ + /* LOGPRIMARY */ + /*==================================================================*/ + l_sqlfupd.token = SQLF_DBTN_LOGPRIMARY; + l_sqlfupd.ptrvalue = (char*)&logprimary; + + rc = sqlfxdb((_SQLOLDCHAR *)dbase, 1, &l_sqlfupd, &sqlca); + + if (sqlca.sqlcode != 0) + { + printf("<========== Failed to retrieve db cfg LOGPRIMARY with return \ +code %d.\n", sqlca.sqlcode); + return(1); + } + + if (logprimary < MIN_LOGPRIMARY) + { + logprimary = MIN_LOGPRIMARY; + + rc = sqlfudb((_SQLOLDCHAR *)dbase, 1, &l_sqlfupd, &sqlca); + + if (sqlca.sqlcode != 0) + { + printf("<========== Failed to update db cfg LOGPRIMARY with return \ +code %d.\n", sqlca.sqlcode); + return(1); + } + } + + /*==================================================================*/ + /* LOGFILSZ */ + /*==================================================================*/ + l_sqlfupd.token = SQLF_DBTN_LOGFILSIZ; + l_sqlfupd.ptrvalue = (char*)&logfilsz; + + rc = sqlfxdb((_SQLOLDCHAR *)dbase, 1, &l_sqlfupd, &sqlca); + + if (sqlca.sqlcode != 0) + { + printf("<========== Failed to retrieve db cfg LOGFILSZ with return \ +code %d.\n", sqlca.sqlcode); + return(1); + } + + if (logfilsz < MIN_LOGFILSIZ) + { + logfilsz = MIN_LOGFILSIZ; + + rc = sqlfudb((_SQLOLDCHAR *)dbase, 1, &l_sqlfupd, &sqlca); + + if (sqlca.sqlcode != 0) + { + printf("<========== Failed to update db cfg LOGFILSZ with return \ +code %d.\n", sqlca.sqlcode); + return(1); + } + } + + /*==================================================================*/ + /* (4) Finally we connect to the database and can start with the */ + /* spatial sample routines and functions. */ + /*==================================================================*/ + + rc = SQLConnect(hdbc, (SQLCHAR *)dbase, SQL_NTS, (SQLCHAR *)uid, SQL_NTS, + (SQLCHAR *)pwd, SQL_NTS); + CHECK_DBC(hdbc, rc); + if (rc != SQL_SUCCESS) + { + printf("<========== Fail to connect to the database =============>.\ +\n\n"); + terminate(henv, rc); + exit(0); + } + + printf("<========== The runGseDemo program was initialized successfully.\ +\n\n"); + + /*=================================================================*/ + /* */ + /* The following steps will run all the tests in the demo */ + /* */ + /*=================================================================*/ + if(domenu) + return(menu()); + else + { + TestEnableDisable(); + TestCoordinateSystem(); + TestSRS(); + CreateSpatialTables(); + TestRegisterSpatialColumn(); + TestCreateLatLongGeocoder(); + TestRegisterGeocoder(); + TestSetupGeocoder(); + TestGeocoder(); + TestImportShape(); + TestIndexes(); + TestAutoGC(); + TestViewsAndQueries(); + TestExportShape(); + WrapUpDemo(); + return(0); + } +} /* end main */ diff --git a/extenders/spatial/samputil.c b/extenders/spatial/samputil.c new file mode 100644 index 0000000..b704575 --- /dev/null +++ b/extenders/spatial/samputil.c @@ -0,0 +1,382 @@ +/******************************************************************************* +** +** Source File Name = samputil.c %I% +** +** Licensed Materials - Property of IBM +** +** (C) COPYRIGHT International Business Machines Corp. 1995 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +** +** +** PURPOSE : +** - contains various sample functions, used by most other samples: +** - connect +** - print_connect_info +** - terminate +** - check_error +** - print_error +** - print_results +** +** FUNCTIONS USED : +** SQLAllocConnect +** SQLBindCol +** SQLColAttributes +** SQLConnect +** SQLDescribeCol +** SQLDisconnect +** SQLError +** SQLFetch +** SQLFreeConnect +** SQLFreeEnv +** SQLGetInfo +** SQLNumResultCols +** SQLSetConnectOption +** +** +*******************************************************************************/ + +#include +#include +#include +#include "sqlcli1.h" +#include "samputil.h" + +#define MAXCOLS 255 + +#ifndef max +#define max(a,b) (a > b ? a : b) +#endif + +/*--> SQLL1X12.SCRIPT */ +/* Global Variables for user id and password, defined in main module. + To keep samples simple, not a recommended practice. + The INIT_UID_PWD macro is used to initialize these variables. +*/ +extern SQLCHAR dbase[SQL_MAX_DSN_LENGTH + 1]; +extern SQLCHAR uid[MAX_UID_LENGTH + 1]; +extern SQLCHAR pwd[MAX_PWD_LENGTH + 1]; +/********************************************************************/ +SQLRETURN +DBconnect(SQLHENV henv, + SQLHDBC * hdbc) +{ + SQLRETURN rc; + SQLSMALLINT outlen; + + /* allocate a connection handle */ + if (SQLAllocConnect(henv, hdbc) != SQL_SUCCESS) { + printf(">---ERROR while allocating a connection handle-----\n"); + return (SQL_ERROR); + } + /* Set AUTOCOMMIT OFF */ + rc = SQLSetConnectOption(*hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); + if (rc != SQL_SUCCESS) { + printf(">---ERROR while setting AUTOCOMMIT OFF ------------\n"); + return (SQL_ERROR); + } + rc = SQLConnect(*hdbc, dbase, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS); + if (rc != SQL_SUCCESS) { + printf(">--- Error while connecting to database: %s -------\n", dbase); + SQLDisconnect(*hdbc); + SQLFreeConnect(*hdbc); + return (SQL_ERROR); + } else { /* Print Connection Information */ + printf(">Connected to %s\n", dbase); + } + return (SQL_SUCCESS); +} + +/********************************************************************/ +/* DBconnect2 - Connect with conect type and syncpoint type */ +/* Valid connect types SQL_CONCURRENT_TRANS, SQL_COORDINATED_TRANS */ +/* Valid syncpoint types, SQL_1_PHASE, SQL_2_PHASE */ +/********************************************************************/ +SQLRETURN +DBconnect2(SQLHENV henv, + SQLHDBC * hdbc, SQLINTEGER contype, SQLINTEGER conphase) +{ + SQLRETURN rc; + SQLSMALLINT outlen; + + /* allocate a connection handle */ + if (SQLAllocConnect(henv, hdbc) != SQL_SUCCESS) { + printf(">---ERROR while allocating a connection handle-----\n"); + return (SQL_ERROR); + } + /* Set AUTOCOMMIT OFF */ + rc = SQLSetConnectOption(*hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); + if (rc != SQL_SUCCESS) { + printf(">---ERROR while setting AUTOCOMMIT OFF ------------\n"); + return (SQL_ERROR); + } + rc = SQLSetConnectOption(hdbc[0], SQL_CONNECTTYPE, contype); + if (rc != SQL_SUCCESS) { + printf(">---ERROR while setting Connect Type -------------\n"); + return (SQL_ERROR); + } + if (contype == SQL_COORDINATED_TRANS ) { + rc = SQLSetConnectOption(hdbc[0], SQL_SYNC_POINT, conphase); + if (rc != SQL_SUCCESS) { + printf(">---ERROR while setting Syncpoint Phase --------\n"); + return (SQL_ERROR); + } + } + rc = SQLConnect(*hdbc, dbase, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS); + if (rc != SQL_SUCCESS) { + printf(">--- Error while connecting to database: %s -------\n", dbase); + SQLDisconnect(*hdbc); + SQLFreeConnect(*hdbc); + return (SQL_ERROR); + } else { /* Print Connection Information */ + printf(">Connected to %s\n", dbase); + } + return (SQL_SUCCESS); + +} +/*<-- */ + +/******************************************************************** +** Prompted_Connect - Prompt for connect options and connect ** +********************************************************************/ + +int +Prompted_Connect(SQLHENV henv, + SQLHDBC * hdbc) +{ + SQLRETURN rc; + SQLCHAR buffer[255]; + SQLSMALLINT outlen; + + /* Set AUTOCOMMIT OFF */ + rc = SQLSetConnectOption(*hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); + if (rc != SQL_SUCCESS) { + printf(">---ERROR while setting AUTOCOMMIT OFF ------------\n"); + return (SQL_ERROR); + } + + printf(">Enter Server Name:\n"); + fgets((char *) dbase, sizeof(dbase), stdin); + printf(">Enter User Name:\n"); + fgets((char *) uid, sizeof(uid), stdin); + printf(">Enter Password:\n"); + fgets((char *) pwd, sizeof(pwd), stdin); + + rc = SQLConnect(*hdbc, dbase, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS); + if (rc != SQL_SUCCESS) { + printf(">--- ERROR while connecting to %s -------------\n", dbase); + return (SQL_ERROR); + } else { + printf("Successful Connect to %s\n", dbase); + return (SQL_SUCCESS); + } +} /* end Prompted_Connect */ + +/********************************************************************/ +SQLRETURN +terminate(SQLHENV henv, + SQLRETURN rc) +{ + SQLCHAR buffer[255]; + SQLSMALLINT outlen; + + printf(">Terminating ....\n"); + print_error(henv, SQL_NULL_HDBC, SQL_NULL_HENV, rc, __LINE__, __FILE__); + + /* Free environment handle */ + if (SQLFreeEnv(henv) != SQL_SUCCESS) + print_error(henv, SQL_NULL_HDBC, SQL_NULL_HENV, rc, __LINE__, __FILE__); + + return (rc); +} + +/********************************************************************/ +/* Print Connection Information */ +SQLRETURN +print_connect_info(SQLHDBC hdbc) +{ + SQLCHAR buffer[255]; + SQLSMALLINT outlen; + SQLRETURN rc; + + printf("-------------------------------------------\n"); + rc = SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, buffer, 255, &outlen); + CHECK_DBC(hdbc, rc); + + printf("Connected to Server: %s\n", buffer); + rc = SQLGetInfo(hdbc, SQL_DATABASE_NAME, buffer, 255, &outlen); + CHECK_DBC(hdbc, rc); + + printf(" Database Name: %s\n", buffer); + rc = SQLGetInfo(hdbc, SQL_SERVER_NAME, buffer, 255, &outlen); + CHECK_DBC(hdbc, rc); + + printf(" Instance Name: %s\n", buffer); + rc = SQLGetInfo(hdbc, SQL_DBMS_NAME, buffer, 255, &outlen); + CHECK_DBC(hdbc, rc); + + printf(" DBMS Name: %s\n", buffer); + rc = SQLGetInfo(hdbc, SQL_DBMS_VER, buffer, 255, &outlen); + CHECK_DBC(hdbc, rc); + + printf(" DBMS Version: %s\n", buffer); + printf("-------------------------------------------\n"); + + return (rc); + +} + +/*--> SQLL1X32.SCRIPT */ +/******************************************************************* +** - print_error - call SQLError(), display SQLSTATE and message +** - called by check_error, see below +*******************************************************************/ + +SQLRETURN +print_error(SQLHENV henv, + SQLHDBC hdbc, + SQLHSTMT hstmt, + SQLRETURN frc, /* Return code to be included with error msg */ + int line, /* Used for output message, indcate where */ + char * file) /* the error was reported from */ +{ + SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]; + SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER sqlcode; + SQLSMALLINT length; + + + printf(">--- ERROR -- RC= %d Reported from %s, line %d ------------\n", + frc, file, line); + while (SQLError(henv, hdbc, hstmt, sqlstate, &sqlcode, buffer, + SQL_MAX_MESSAGE_LENGTH + 1, &length) == SQL_SUCCESS) { + printf(" SQLSTATE: %s\n", sqlstate); + printf("Native Error Code: %d\n", sqlcode); + printf("%s \n", buffer); + }; + printf(">--------------------------------------------------\n"); + return (SQL_ERROR); + +} +/********************************************************************* +* The following macros (defined in samputil.h) use check_error +* +* #define CHECK_ENV( henv, RC) if (RC != SQL_SUCCESS) \ +* {check_error(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT, RC, __LINE__, __FILE__);} +* +* #define CHECK_DBC( hdbc, RC) if (RC != SQL_SUCCESS) \ +* {check_error(SQL_NULL_HENV, hdbc, SQL_NULL_HSTMT, RC, __LINE__, __FILE__);} +* +* #define CHECK_STMT( hstmt, RC) if (RC != SQL_SUCCESS) \ +* {check_error(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, RC, __LINE__, __FILE__);} +* +***********************************************************************/ + +/******************************************************************* +** - check_error - call print_error(), checks severity of return code +*******************************************************************/ +SQLRETURN +check_error(SQLHENV henv, + SQLHDBC hdbc, + SQLHSTMT hstmt, + SQLRETURN frc, + int line, + char * file) +{ + SQLRETURN rc; + + switch (frc) { + case SQL_INVALID_HANDLE: + printf("\n>------ ERROR Invalid Handle --------------------------\n"); + print_error(henv, hdbc, hstmt, frc, line, file); + return (SQL_ERROR); + break; + case SQL_ERROR: + printf("\n>--- FATAL ERROR, Attempting to rollback transaction --\n"); + print_error(henv, hdbc, hstmt, frc, line, file); + return (SQL_ERROR); + break; + default: + break; + } + return (SQL_SUCCESS); + +} /* end check_error */ +/*<-- */ + +SQLRETURN +print_results(SQLHSTMT hstmt) +{ + SQLCHAR colname[32]; + SQLSMALLINT coltype; + SQLSMALLINT colnamelen; + SQLSMALLINT nullable; + SQLUINTEGER collen[MAXCOLS]; + SQLSMALLINT scale; + SQLINTEGER outlen[MAXCOLS]; + SQLCHAR *data[MAXCOLS]; + SQLCHAR errmsg[256]; + SQLRETURN rc; + SQLSMALLINT nresultcols; + int i; + SQLINTEGER displaysize; + + rc = SQLNumResultCols(hstmt, &nresultcols); + CHECK_STMT(hstmt, rc); + + for (i = 0; i < nresultcols; i++) { + SQLDescribeCol(hstmt, (SQLUSMALLINT)(i + 1), colname, sizeof(colname), + &colnamelen, &coltype, &collen[i], &scale, NULL); + + /* get display length for column */ + SQLColAttributes(hstmt, (SQLUSMALLINT)(i + 1), SQL_COLUMN_DISPLAY_SIZE, + NULL, 0, NULL, &displaysize); + + /* + * set column length to max of display length, and column name + * length. Plus one byte for null terminator + */ + collen[i] = max(displaysize, strlen((char *) colname)) + 1; + + printf("%-*.*s", (int)collen[i], (int)collen[i], colname); + + /* allocate memory to bind column */ + data[i] = (SQLCHAR *) malloc((int)collen[i]); + + /* bind columns to program vars, converting all types to CHAR */ + rc = SQLBindCol(hstmt, (SQLUSMALLINT)(i + 1), SQL_C_CHAR, data[i], + collen[i], &outlen[i]); + } + printf("\n"); + /* display result rows */ + while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA_FOUND) { + errmsg[0] = '\0'; + for (i = 0; i < nresultcols; i++) { + /* Check for NULL data */ + if (outlen[i] == SQL_NULL_DATA) + printf("%-*.*s", (int)collen[i], (int)collen[i], "NULL"); + else + { /* Build a truncation message for any columns truncated */ + if (outlen[i] >= collen[i]) { + sprintf((char *) errmsg + strlen((char *) errmsg), + "%d chars truncated, col %d\n", + (int)outlen[i] - collen[i] + 1, i + 1); + } + /* Print column */ + printf("%-*.*s", (int)collen[i], (int)collen[i], data[i]); + } + } /* for all columns in this row */ + + printf("\n%s", errmsg); /* print any truncation messages */ + } /* while rows to fetch */ + + /* free data buffers */ + for (i = 0; i < nresultcols; i++) { + free(data[i]); + } + + return(SQL_SUCCESS); + +} /* end print_results */ diff --git a/extenders/spatial/samputil.h b/extenders/spatial/samputil.h new file mode 100644 index 0000000..b4701ba --- /dev/null +++ b/extenders/spatial/samputil.h @@ -0,0 +1,67 @@ +/******************************************************* +** +** Licensed Materials - Property of IBM +** +** (C) COPYRIGHT International Business Machines Corp. 1995 +** All Rights Reserved. +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +** +** file = samputil.h +** Utility functions used in CLI examples +********************************************************/ + +SQLRETURN +DBconnect(SQLHENV henv, + SQLHDBC * hdbc); + +SQLRETURN +terminate(SQLHENV henv, + SQLRETURN rc); + +SQLRETURN +print_connect_info(SQLHDBC hdbc); + +SQLRETURN +print_error(SQLHENV henv, + SQLHDBC hdbc, + SQLHSTMT hstmt, + SQLRETURN frc, + int line, + char * file); + +SQLRETURN +check_error(SQLHENV henv, + SQLHDBC hdbc, + SQLHSTMT hstmt, + SQLRETURN frc, + int line, + char * file); + +/* Above line was SQLCHAR * file);, changed to just a CHAR */ + +#define MAX_UID_LENGTH 18 +#define MAX_PWD_LENGTH 30 + + +/** + Macros for common Error Checking using check_error from samputil.c +**/ +#define CHECK_ENV( henv, RC) if (RC != SQL_SUCCESS) \ + {check_error(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT, RC, __LINE__, __FILE__);} +#define CHECK_DBC( hdbc, RC) if (RC != SQL_SUCCESS) \ + {check_error(SQL_NULL_HENV, hdbc, SQL_NULL_HSTMT, RC, __LINE__, __FILE__);} +#define CHECK_STMT( hstmt, RC) if (RC != SQL_SUCCESS) \ + {check_error(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, RC, __LINE__, __FILE__);} + +#define INIT_UID_PWD if (argc == 4) \ + { strncpy((char *)dbase, (const char *)argv[1], SQL_MAX_DSN_LENGTH ); \ + strncpy((char *)uid, (const char *)argv[2], MAX_UID_LENGTH); \ + strncpy((char *)pwd, (const char *)argv[3], MAX_PWD_LENGTH); } \ + else { \ + printf(">Enter Database Name:\n"); gets((char *) dbase); \ + printf(">Enter User Name:\n"); gets((char *) uid); \ + printf(">Enter Password:\n"); gets((char *) pwd); } + + diff --git a/federated/drdalbacfun.clp b/federated/drdalbacfun.clp new file mode 100644 index 0000000..27a9efb --- /dev/null +++ b/federated/drdalbacfun.clp @@ -0,0 +1,20 @@ +-- SAMPLES for LBAC function templates for the DRDA wrapper accessing +--a DB2/LUW LBAC enabled server version 9.1 or later. + +--Replace with the actual server name + +--DB2 function template for LBAC function SECLABEL_TO_CHAR +drop function seclabel_2_char(varchar(50), varchar(50)); + +create function seclabel_2_char(varchar(50), varchar(50)) returns varchar(50) as template deterministic no external action; + +create function mapping l2cmap for seclabel_2_char(varchar(50), varchar(50)) server options (remote_name 'SECLABEL_TO_CHAR'); + + +--DB2 function template for LBAC function CHAR_TO_LABEL +drop function char_2_seclabel(varchar(50), varchar(50)); + +create function char_2_seclabel(varchar(50), varchar(50)) returns varchar(50) as template deterministic no external action; + +create function mapping c2lmap for char_2_seclabel(varchar(50), varchar(50)) server options (remote_name 'SECLABEL_BY_NAME'); + diff --git a/federated/net8olsfun.clp b/federated/net8olsfun.clp new file mode 100644 index 0000000..385d2ee --- /dev/null +++ b/federated/net8olsfun.clp @@ -0,0 +1,11 @@ +--Make sure to change the to the actual Net8 server you will apply these functions to + +--Net8 function template for Oracle OLS function LABEL_TO_CHAR +drop function label_2_char(decimal(10,0)); +create function label_2_char(decimal(10,0)) returns varchar(200) as template deterministic no external action; +create function mapping l2cmap1 for label_2_char(decimal(10,0)) server options (remote_name 'label_to_char'); + +--Net8 function template for Oracle OLS function CHAR_TO_LABEL +drop function char_2_label(varchar(200),varchar(200)); +create function char_2_label(varchar(200),varchar(200)) returns decimal(10,0) as template deterministic no external action; +create function mapping c2lmap1 for char_2_label(varchar(200),varchar(200)) server options (remote_name 'char_to_label'); \ No newline at end of file diff --git a/federated/selective_view/README b/federated/selective_view/README new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/federated/selective_view/README @@ -0,0 +1 @@ + diff --git a/federated/selective_view/selective_view.txt b/federated/selective_view/selective_view.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/federated/selective_view/selective_view.txt @@ -0,0 +1 @@ + diff --git a/federated/selective_view/selective_view_prep.db2 b/federated/selective_view/selective_view_prep.db2 new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/federated/selective_view/selective_view_prep.db2 @@ -0,0 +1 @@ + diff --git a/federated/selective_view/selective_view_procs.db2 b/federated/selective_view/selective_view_procs.db2 new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/federated/selective_view/selective_view_procs.db2 @@ -0,0 +1 @@ + diff --git a/federated/umplugin/file/README b/federated/umplugin/file/README new file mode 100644 index 0000000..fb49c26 --- /dev/null +++ b/federated/umplugin/file/README @@ -0,0 +1,59 @@ +***************************************************************************** +* +* README for user mapping plugin Samples (all platforms) +* +* Last Update: Jan 2007 +* +* The sample User Mapping plugin is designed to provide a simple +* implementation that you can customize to meet the specific requirements +* of your installation. User Mapping plugins can be used to retrieve +* user mappings stored in repository other than the database catalog +* of the federation server. +* +* For information on developing security plugins, see the Federation System +* Guide. +* +***************************************************************************** +* +* QUICKSTART +* +* - Copy sqllib/samples/federated/umplugin/file/* to a working directory. +* - Examine the "bldplugin" script and update any path information to reflect +* your specific installation. +* - Execute "bldplugin " (view bldplugin for more detail) to build +* the fsumpluginfile sample. +* +***************************************************************************** +* +* Sample files: +* +* bldplugin (bldplugin.bat on Windows) +* Build script used to handle plugin compilation and linking. +* +* fsumplugin_file.h +* The header file for the sample file based user mapping plugin. +* +* fsumplugin_file.c +* Implements a simple, file based user mapping lookup. This sample can be +* built with "bldplugin fsumplugin_file". +* +* fsumlookup (fsumlookup.exe on Windows) +* A standalone program to test the plugin outside of the DB2 environment +* Usage: +* fsumlookup +* where is the name of the plugin library with full path +* +* fsumsetup_file (fsumsetup_file.exe on Windows) +* A standalone program to setup the file name with full path of file holding +* the user mappings. +* +* fsumplugin_file.txt +* The sample file that stores the user mappings. User mapping entries are +* stored in the file as the following. Each user mapping entry occupies one +* line in the file. +* ;;;;REMOTE_AUTHID:;REMOTE_PASSWOD: +* Where is encrypted (reserved byte order). This is just +* use to show the encryption and decryption process. You should customize +* the encryption and decryption algorithm to meet your need. +* +***************************************************************************** diff --git a/federated/umplugin/file/fsumlookup b/federated/umplugin/file/fsumlookup new file mode 100755 index 0000000000000000000000000000000000000000..d7e770243becd11d33885ff6491bc84db1d97f3e GIT binary patch literal 36120 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 mv +#include +#include "fsumplugin.h" +#include "fsumplugin_file.h" + +/* Declare the utility functions. The FSUMPluginInit function +resolves the addresses of these functions. */ +FSUMlogErrorMsgFP *FSUMlogErrorMsg = NULL; +FSUMaddUMOptionFP *FSUMaddUMOption = NULL; +FSUMallocateFP *FSUMallocate = NULL; +FSUMdeallocateFP *FSUMdeallocate = NULL; + +#if defined ( _WIN32 ) +#define snprintf _snprintf +#endif + +/* The function that decrypts the password. */ +void decryptPassword(const char* a_encryptedPwd, + size_t a_encryptedPwdLen, + char** a_decryptedPwd, + size_t* a_decryptedPwdLen) +{ + sqlint32 i; + char* password; + void* buffer; + /* Encrypt all passwords in the external repository. + In this sample, passwords are encrypted by reversing + the bytes. This simple encryption is used only + to demonstrate the process of decryption. Customize + the encryption to match the security + that your environment uses. + */ + *a_decryptedPwdLen = a_encryptedPwdLen; + + /* Add 1 byte for '\0' */ + FSUMallocate (*a_decryptedPwdLen + 1, &buffer); + + password = (char*)buffer; + + /* Decrypt the password. In this sample, the decryption copies + the bytes in the reverse order. Customize the decryption to match + the security that your environment uses.*/ + for (i = 0; i < a_encryptedPwdLen; i++) + { + password[i] = a_encryptedPwd[a_encryptedPwdLen - 1 - i]; + } + + password[i] = '\0'; + + *a_decryptedPwd = password; + +} + +/* Implementation of the FSUMconnect API. The plug-in must implement this API. */ +SQL_API_RC SQL_API_FN myConnect(void** a_FSUMRepository, + const char* a_cfgFilePath) +{ + SQL_API_RC rc = FSUM_PLUGIN_OK; + char errMsgBuffer[FSUM_MAX_ERROR_MSG_SIZE]; + size_t errMsgLen; + FILE *configFile = NULL; + FILE *umFile = NULL; + char umFileName[FSUM_MAX_NAME_LEN +1]; /* leave room for '\0' */ + char configFileFullPathName[FSUM_MAX_PATH_LEN + FSUM_MAX_NAME_LEN + 1] = {'\0'}; + size_t fileSize; + + /* Add the path to the configuration file. */ + /* The configuration file and the plug-in must be in the + same directory. If the federated server calls the API, + a_cfgFilePath points to a string that represents the path + of the plug-in. */ + if(a_cfgFilePath != NULL) + { + strncat(configFileFullPathName, a_cfgFilePath, FSUM_MAX_PATH_LEN); + } + + /* Add the name of the configuration file. */ + strncat(configFileFullPathName, FSUM_CONFIG_FILE_NAME, FSUM_MAX_NAME_LEN); + + /* Get the file name and path from the fsumplugin_file.cfg file. */ + configFile = fopen(configFileFullPathName, "rb"); + if (configFile == NULL) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myConnect: cannot open file "FSUM_CONFIG_FILE_NAME"\n"); + + /* Log the error message */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code */ + rc = FSUM_CONNECTION_ERROR; + goto exit; + } + + /* Calculate the size of the file name, including + the full path. */ + fseek(configFile, 0L, SEEK_END); + fileSize = ftell(configFile); + + /* Go back to beginning of the file. */ + fseek(configFile, 0L, SEEK_SET); + + /* Read the entire file into memory. */ + fread (umFileName, fileSize, 1, configFile); + + /* Check if an error occurred while handling file. */ + rc = ferror(configFile); + if (rc != 0) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myConnect: failed to read from fsumplugin_file.cfg"); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_CONNECTION_ERROR; + goto exit; + } + + /* Close the configuration file. */ + fclose(configFile); + + /* Set the null terminator. */ + umFileName[fileSize] = '\0'; + + /* Open the user mapping file. */ + umFile = fopen ((char*)umFileName, "rb"); + if (umFile == NULL) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myConnect: failed to open um repository file %s", umFileName); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_CONNECTION_ERROR; + goto exit; + } + + /* Send the handle to the opened file to the caller. */ + *a_FSUMRepository = (void*)umFile; + +exit: + + return rc; +} + +/* Implementation of the FSUMfetchUM API. The plug-in must implement +this API. */ +SQL_API_RC SQL_API_FN myFetchUM (void* a_FSUMRepository, + FSUMEntry* a_entry) +{ + SQL_API_RC rc = FSUM_PLUGIN_OK; + SQL_API_RC utilRc = FSUM_PLUGIN_UTIL_OK; + char errMsgBuffer[FSUM_MAX_ERROR_MSG_SIZE]; + size_t errMsgLen; + char searchKey[FSUM_MAX_SEARCH_KEY_SIZE + 1]; + size_t searchKeySize = 0; + size_t fileSize; + size_t i; + size_t j; + + void* buffer = NULL; + char* startp; + char* entryStartp; + + size_t optionChainSize = 0; + char* optionChainStartp = NULL; + char* optionStartp = NULL; + size_t charCount = 0; + + char* optionName = NULL; + size_t optionNameSize; + char* optionValue = NULL; + size_t optionValueSize; + + char* remotePassword = NULL; + size_t remotePasswordSize = 0; + + int found = 0; + int done = 0; + int isRemotePasswordOption = 0; + + /* Get back the handle to the opened file. */ + FILE * fd = (FILE*) a_FSUMRepository; + + /* Calculate the file size. */ + fseek(fd, 0L, SEEK_END); + fileSize = ftell(fd); + + /* Check for an error after calculating the file size. */ + rc = ferror(fd); + if (rc != 0) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myFetchUM: failed to get the size of file"); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_LOOKUP_ERROR; + goto exit; + } + + /* Allocate the buffer to hold the user mapping information. */ + utilRc = FSUMallocate(fileSize, &buffer); + if (utilRc != FSUM_PLUGIN_UTIL_OK) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myFetchUM: failed to allocate memory for %d bytes", fileSize); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_LOOKUP_ERROR; + goto exit; + } + startp = (char*)buffer; + + /* Go back to the beginning of the file. */ + fseek(fd, 0L, SEEK_SET); + + /* Read the entire file into memory. */ + i = fread (startp, fileSize, 1, fd); + + /* Check for an error when handling the opened file. */ + rc = ferror(fd); + if (rc != 0) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myFetchUM: failed to read from file"); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_LOOKUP_ERROR; + goto exit; + } + + /* Construct the search key. */ + searchKeySize = a_entry->fsInstanceNameLen + sizeof (char) + + a_entry->fsDatabaseNameLen + sizeof (char) + + a_entry->fsServerNameLen + sizeof (char) + + a_entry->fsAuthIDLen + sizeof (char); + + /* SearchKeySize + 1 for the extra null terminator. */ + snprintf(searchKey, searchKeySize + 1, + "%s%c%s%c%s%c%s%c", + a_entry->fsInstanceName, + FSUM_IDENTIFIER_SEPARATOR, + a_entry->fsDatabaseName, + FSUM_IDENTIFIER_SEPARATOR, + a_entry->fsServerName, + FSUM_IDENTIFIER_SEPARATOR, + a_entry->fsAuthID, + FSUM_IDENTIFIER_SEPARATOR); + + /* Search the user mapping entries. */ + entryStartp = startp; + charCount = 0; + while (charCount < fileSize && !found) + { + /* Find the user mapping entry. */ + if(strncmp(entryStartp, searchKey, searchKeySize) == 0) + { + found = 1; + } + else + { + /* Move to the next entry. */ + for (i = charCount; + (i <= fileSize) && + (strncmp(&startp[i], FSUM_UM_ENTRY_SEPARATOR, ENTRY_SEPARATOR_SIZE) != 0); + i++); + /* Plus 1 to skip the FSUM_UM_ENTRY_SEPARATOR */ + charCount = i + ENTRY_SEPARATOR_SIZE; + if(charCount < fileSize) + { + entryStartp = &startp[charCount]; + } + } + } + if (found) + { + /* The option chain begins after the search key. */ + /*DB2INST1;GLOBALDB;ORA10G;NEWTON;REMOTE_AUTHID:J15USER1;REMOTE_PASSWORD:j15user1*/ + optionChainStartp = &entryStartp[searchKeySize]; + + /* Calculate the length of the option chain. */ + optionChainSize = 0; + for (optionChainSize = 0; + charCount < fileSize && + (strncmp(&optionChainStartp[optionChainSize], + FSUM_UM_ENTRY_SEPARATOR, + ENTRY_SEPARATOR_SIZE) != 0); + optionChainSize++, charCount++); + + /* Traverse the option chain. */ + optionNameSize = 0; + optionValueSize = 0; + j = 0; + + /* Start with the first option in the chain. */ + optionStartp = optionChainStartp; + charCount = 0; + + /* Perform a check. */ + done = (charCount >= fileSize)?1:0; + + while (!done) + { + /* Get the size of the option name. */ + optionNameSize = 0; + for (i = 0; + (charCount++ <= optionChainSize) && + optionStartp[i] != FSUM_OPTION_NAME_VALUE_SEPARATOR && + (strncmp(&optionStartp[i], FSUM_UM_ENTRY_SEPARATOR, ENTRY_SEPARATOR_SIZE) != 0) && + optionStartp[i] != FSUM_IDENTIFIER_SEPARATOR; i++) + { + optionNameSize++; + } + + /* Get the size of the option value. Do not include the FSUM_FSUM_OPTION_NAME_VALUE_SEPARATOR.*/ + optionValueSize = 0; + for (i = optionNameSize + 1; + (charCount++ <= optionChainSize) && + optionStartp[i] != FSUM_OPTION_NAME_VALUE_SEPARATOR && + (strncmp(&optionStartp[i], FSUM_UM_ENTRY_SEPARATOR, ENTRY_SEPARATOR_SIZE) != 0) && + optionStartp[i] != FSUM_IDENTIFIER_SEPARATOR; i++) + { + optionValueSize++; + } + + /* Get the option name. */ + if (optionNameSize > 0) + { + /* Allocate the buffer to hold the option name. */ + utilRc = FSUMallocate(optionNameSize, &buffer); + if (utilRc != FSUM_PLUGIN_UTIL_OK) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myFetchUM: failed to allocate memory of %d bytes for option name", optionNameSize); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_LOOKUP_ERROR; + goto exit; + } + optionName = (char*)buffer; + strncpy (optionName, optionStartp, optionNameSize); + /* Check if the option name is REMOTE_PASSWORD. */ + if(strncmp(optionName, FSUM_REMOTE_PASSWORD_OPTION, optionNameSize) == 0) + { + isRemotePasswordOption = 1; + } + else + { + isRemotePasswordOption = 0; + } + } + else + { + /* Option name is not valid. */ + optionName = NULL; + optionNameSize = 0; + } + + /* Get the option value. */ + if (optionValueSize > 0) + { + /* Allocate the buffer to hold the option value. */ + utilRc = FSUMallocate(optionValueSize, &buffer); + if (utilRc != FSUM_PLUGIN_UTIL_OK) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myFetchUM: failed to allocate memory of %d bytes for option value", optionValueSize); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_LOOKUP_ERROR; + goto exit; + } + optionValue = (char*)buffer; + /* Do not include the option name and the FSUM_FSUM_OPTION_NAME_VALUE_SEPARATOR. */ + strncpy (optionValue, &optionStartp[optionNameSize + 1], optionValueSize); + + /* If it is a password option, decrypt value of the option.*/ + if (isRemotePasswordOption) + { + remotePassword = NULL; + /* Decrypt the password. */ + decryptPassword (optionValue, optionValueSize, &remotePassword, &remotePasswordSize); + /* Free the password option value, and use the decrypted password.*/ + FSUMdeallocate(optionValue); + optionValue = remotePassword; + optionValueSize = remotePasswordSize; + if (remotePassword == NULL) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myFetchUM: decrypt password failed."); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_LOOKUP_ERROR; + goto exit; + } + } /* The option is REMOTE_PASSWORD. */ + } /* The option value is valid. */ + else + { + /* The option value is not valid. */ + optionValue = NULL; + optionValueSize = 0; + } /* If the option name is valid. */ + + /* Determine if the option chain has been traversed. */ + if (charCount >= optionChainSize) + { + done = 1; + } + else /* Move to the next option. */ + { /* Option chain looks like the following: */ + /* REMOTE_AUTHID:J15USER1;REMOTE_PASSWORD:1resu51j */ + optionStartp = &optionChainStartp[charCount]; + } + + /* Add the option to the user mapping entry. */ + if (optionName != NULL) + { + utilRc = FSUMaddUMOption(a_entry, optionName, optionNameSize, optionValue, optionValueSize); + if (utilRc != FSUM_PLUGIN_UTIL_OK) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myFetchUM: failed to add option %s", optionName); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_LOOKUP_ERROR; + goto exit; + } + /* Free the storage for the option name and option value. */ + FSUMdeallocate(optionName); + optionName = NULL; + optionNameSize = 0; + FSUMdeallocate(optionValue); + optionValue = NULL; + optionValueSize = 0; + } + } /* When not finished with the option chain. */ + } /* if found == 1 */ + else /* There is no matching entry. */ + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myFetchUM: UM entry not found"); + + /* Log the error message. */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code. */ + rc = FSUM_LOOKUP_ERROR; + goto exit; + } + +exit: + + if (optionName != NULL) + { + FSUMdeallocate(optionName); + } + + if (optionValue != NULL) + { + FSUMdeallocate(optionValue); + } + + return rc; +} + +/* Implementation of the FSUMdisconnect API. The plug-in must implement this + API. */ +SQL_API_RC SQL_API_FN myDisconnect (void* a_FSUMRepository) +{ + SQL_API_RC rc = FSUM_PLUGIN_OK; + char errMsgBuffer[FSUM_MAX_ERROR_MSG_SIZE]; + size_t errMsgLen; + + FILE *fd; + + /* Get back the handle to the repository (the opened file). */ + fd = (FILE *) a_FSUMRepository; + + /* Close the file */ + if (fclose (fd) != 0) + { + /* Construct the error message. */ + errMsgLen = snprintf(errMsgBuffer, sizeof(errMsgBuffer), + "UMPlugin myDisconnect: Failed to close file\n"); + + /* Log the error message */ + FSUMlogErrorMsg (FSUM_LOG_ERROR, errMsgBuffer, errMsgLen); + + /* Set the error return code */ + rc = FSUM_DISCONNECT_ERROR; + goto exit; + } + +exit: + + return rc; +} + +/* Implementation of the FSUMPluginTerm API. The plug-in must implement + this API. */ +SQL_API_RC SQL_API_FN myPluginTerm () +{ + SQL_API_RC rc = FSUM_PLUGIN_OK; + + /** + This function cleans up the global resources that the current thread + in the db2fmp process allocates. This sample plug-in does not allocate + any global resources; therefore, this sample does not use this function. + **/ + return rc; + +} + +/* The plug-in initialization API function. You must use this name for this API. + Do not rename it. */ +SQL_API_RC SQL_API_FN FSUMPluginInit(sqlint32 a_version, + FSUMPluginAPIs* a_pluginAPIs, + FSUMPluginUtilities* a_pluginUtils) +{ + SQL_API_RC rc = FSUM_PLUGIN_OK ; + + /* Pass the API function pointers to federated server */ + a_pluginAPIs->FSUMconnect = &myConnect; + a_pluginAPIs->FSUMfetchUM = &myFetchUM; + a_pluginAPIs->FSUMdisconnect = &myDisconnect; + a_pluginAPIs->FSUMPluginTerm = &myPluginTerm; + + /* Get the function pointers for the utility functions */ + FSUMallocate = a_pluginUtils->allocate; + FSUMdeallocate = a_pluginUtils->deallocate; + FSUMlogErrorMsg = a_pluginUtils->logErrorMsg; + FSUMaddUMOption = a_pluginUtils->addUMOption; + + /** + If an error occurs, the plug-in must return error code + rc = FSUM_INITIALIZE_ERROR. There are two additional optional ways + to handle errors: Call FSUMlogErrorMsg to log the error, or + use use a_errorMsg to send a message to federated server. + (Set up a_errorMsgLen based on the size of a_errorMsg.) + **/ + + return rc; +} diff --git a/federated/umplugin/file/fsumplugin_file.h b/federated/umplugin/file/fsumplugin_file.h new file mode 100644 index 0000000..50e6bdd --- /dev/null +++ b/federated/umplugin/file/fsumplugin_file.h @@ -0,0 +1,35 @@ +/****************************************************************************** +** +** Source File Name: fsumpluginfile.h +** +** (C) COPYRIGHT International Business Machines Corp. Y1, Y2 +** All Rights Reserved +** Licensed Materials - Property of IBM +** +** US Government Users Restricted Rights - Use, duplication or +** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +** +** Function = header file for sample file based user mapping plugin +** +** Operating System: All +** +*******************************************************************************/ +#ifndef FS_H_UM_PLUGIN_FILE_INCLUDED +#define FS_H_UM_PLUGIN_FILE_INCLUDED + +#define FSUM_CONFIG_FILE_NAME "fsumplugin_file.cfg" +#define FSUM_IDENTIFIER_SEPARATOR ';' +#define FSUM_OPTION_NAME_VALUE_SEPARATOR ':' +#if defined ( _WIN32 ) +#define FSUM_UM_ENTRY_SEPARATOR "\r\n" +#else +#define FSUM_UM_ENTRY_SEPARATOR "\n" +#endif +#define ENTRY_SEPARATOR_SIZE sizeof(FSUM_UM_ENTRY_SEPARATOR) - 1 + +/* search key include FS instance name, database name, remote server name, +and local user name. So the max key size is 4 * FSUM_MAX_IDENTIFIER_SIZE +and 4 separator between these identifiers */ +#define FSUM_MAX_SEARCH_KEY_SIZE (4 * FSUM_MAX_NAME_LEN + 4 * sizeof(char)) + +#endif /* FS_H_UM_PLUGIN_FILE_INCLUDED */ diff --git a/federated/umplugin/file/fsumplugin_file.txt b/federated/umplugin/file/fsumplugin_file.txt new file mode 100644 index 0000000..62b37ba --- /dev/null +++ b/federated/umplugin/file/fsumplugin_file.txt @@ -0,0 +1,3 @@ +DB2INST1;TESTDB;MSSQL2K;ALICE;REMOTE_AUTHID:TESTUSR1;REMOTE_PASSWORD:testuser1 +DB2INST1;GLOBALDB;ORA10G;NEWTON;REMOTE_AUTHID:J15USER1;REMOTE_PASSWORD:1resu51j +DB2INST2;REPLDB;ORA10G;RONLIU;REMOTE_AUTHID:REPLUSR1;REMOTE_PASSWORD:repluser1 diff --git a/federated/umplugin/file/fsumsetup_file b/federated/umplugin/file/fsumsetup_file new file mode 100755 index 0000000000000000000000000000000000000000..6d3e66972b3a3a657dcfb009dc6c6fa6db23879d GIT binary patch literal 30688 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 +#include "fsumplugin.h" + +/* read a line from the command line */ +sqlint32 fsum_getline(char line[], int max) +{ + sqlint32 nch = 0; + int c; + max = max - 1; /* leave room for '\0' */ + + while((c = getchar()) != '\n') + { + if(nch < max) + { + line[nch] = (char)c; + } + nch = nch + 1; + } + + if(nch >= max + 1) + { + printf("File name is too long\n"); + return EOF; + } + + if(c == EOF || nch == 0) + { + printf("File name is invalid.\n"); + return EOF; + } + + line[nch] = '\0'; + return nch; +} + + +/* read a line (path and file name info) from command line and store the + * information in the config file fsumpluginfile.cfg. + */ +int main() +{ + char pluginFileName[FSUM_MAX_PATH_LEN + FSUM_MAX_NAME_LEN +1]; /* leave room for '\0' */ + const char configFileName[] = "fsumplugin_file.cfg"; + sqlint32 pluginFileNameLen = 0; + FILE *fd = NULL; + + printf("Full path and name of file (UM repository): "); + + pluginFileNameLen = fsum_getline(pluginFileName, FSUM_MAX_PATH_LEN + FSUM_MAX_NAME_LEN +1); + + if (pluginFileNameLen == EOF) + { + /* invalid file name early exit */ + return 0; + } + + /* open the config file for write */ + fd = fopen (configFileName, "wb"); + + /* write the plugin full path information to the config file */ + fwrite(pluginFileName, sizeof(pluginFileName[0]), pluginFileNameLen, fd); + + /* close the file */ + fclose(fd); + + return 0; +} diff --git a/federated/umplugin/ldap/README.txt b/federated/umplugin/ldap/README.txt new file mode 100644 index 0000000..8b2a0d4 --- /dev/null +++ b/federated/umplugin/ldap/README.txt @@ -0,0 +1,151 @@ +******************************************************************************* + README for II Federated User Mapping LDAP Sample Plugin on UNIX Platforms +******************************************************************************* + +I) Note: +-------- + + In this README file, the /samples and /function directories are relative + paths to the DB2 instance directory. We assume that your DB2 instance is + installed at $DB2PATH. For example, if $DB2PATH is /home/db2inst1/sqllib, + then the full paths of the /samples and /function directories should be + /home/db2inst1/sqllib/samples and /home/db2inst1/sqllib/function. + + This Java sample plugin demonstrates the process to build a Java plugin for + the federated server to get user mapping information from an external + repository such as a LDAP server. + + The string enclosed by < and > represents that you need to customize to + your own string. For example should be replaced by your real + userid to logon to the federated server. + + Prerequisite: This LDAP plugin sample requires you have Java Development Kit + JDK 1.4.1 or higher installed. + +II) What is each file about? +---------------------------- + + This README and the sample codes are under the /samples/federated/umplugin/ldap + directory. To access this directory to deploy the sample plugin, you must + install the DB2 Application Development Client. + + schema.ldif + LDAP schema extension for user mapping assumed by this sample plugin. + It should be loaded to the LDAP server. + + entry.ldif + A few LDAP user mapping entries used for testing this sample plugin. + It should be loaded to the LDAP server. + + UserMappingRepositoryLDAP + The derived java class that contains the actual connect, fetchUM + and disconnect implementations. + + UserMappingCryptoLDAP.java + The derived java class that contains the actual encode, decode, + encrypt, decrypt implementations. + + UserMappingSetupLDAP.java + The java class that sets up the sample plugin's configuration + parameters in a file with the matching name, i.e., + UserMappingRepositoryLDAP.cfg. + + UserMappingLookupLDAP.java + The java class that calls the lookupUM method of UserMappingRepository + class to perform the standalone lookup test before integrating into + the federated server. + Note UserMappingRepositoryLDAP class inherited lookupUM method + from its parent, i.e., UserMappingRepository class. + +III) How to deploy this sample plugin? +-------------------------------------- + +1) Copy /samples/federated/umplugin/ldap/* to an empty working directory. + +2) Compile and archive the java codes with the following commands: + javac -classpath $DB2PATH/java/db2umplugin.jar:$CLASSPATH \ + -d . \ + ./UserMappingRepositoryLDAP.java \ + ./UserMappingCryptoLDAP.java \ + ./UserMappingSetupLDAP.java \ + ./UserMappingLookupLDAP.java + + jar -cfM0 UserMappingRepositoryLDAP.jar . + + You must add your JDK path into UNIX $PATH environment variable + in order to use the right javac, jar and java commands. + +Before you proceed further, you need to ensure the following: +A) know your LDAP server's configuration information such as + host name or IP address, port number, userid/password, + SSL setting as well as related certificates etc. +B) load /samples/federated/umplugin/ldap/schema.ldif and + /samples/federated/umplugin/ldap/entry.ldif to your LDAP server + in order to try out the sample plugin. + +3) Setup the config file UserMappingRepositoryLDAP.cfg with the commond: + java -classpath $DB2PATH/java/db2umplugin.jar:./UserMappingRepositoryLDAP.jar:$CLASSPATH UserMappingSetupLDAP + + You must follow the prompt of the setup program to enter the + required parameters very carefully, There is no default provided. + +4) Run the lookup test with the commamd: + java -classpath $DB2PATH/java/db2umplugin.jar:./UserMappingRepositoryLDAP.jar:$CLASSPATH \ + UserMappingLookupLDAP -server -authid -instance -database + + You must specify the server, authid, instance and database in the command line + in order for the plugin to find the right user mapping entry. + +5) Integrate the sample plugin with the federated server. + Ensure you have write permission to /function directory and copy your + UserMappingRepositoryLDAP.jar and UserMappingRepositoryLDAP.cfg over. + +6) Test if the sample plugin is used by the federated server. + + 6.1) Set the database manager configuration parameter FEDERATED to YES. + db2 update dbm cfg using FEDERATED YES + + 6.2) Set the database manager configuration parameter JDK_PATH correctly. + db2 update dbm cfg using JDK_PATH + You can use an empty string, '', if you have used JDK installed + under $DB2PATH/java directory. + + 6.3) After you have updated the database manager configuration, you have + to restart DB2 and create a few things: + db2 terminate + db2stop + db2start + db2 "create database " + db2 "connect to user newton using " + db2 "create table newton.t1(c1 int)" + db2 "connect reset" + + 6.4) Connect to your database, create wrapper and/or server with DB2_UM_PLUGIN + option specified. + db2 "connect to user using " + db2 "create wrapper drda" + db2 "create server type DB2/CS version 8 wrapper drda authorization password options (dbname , DB2_UM_PLUGIN 'UserMappingRepositoryLDAP'); + db2 "create nickname .nick1 for .newton.t1" + + Note: This last create nickname statement internally will invoke + the sample plugin to read user mapping (iiAuthid->newton) information + back from the LDAP server in order to create the nickname successfully. + +IV. How to deploy your own LDAP plugin starting from this sample codes? + +Starting from the sample codes, + +1) schema.ldif and entry.ldif contains schema extension for user mapping + and some user mapping entries that this sample plugin assumed. + In your case, you need to customize your UserMappingRepositoryLDAP.java, + UserMappingCryptoLDAP.java implementation to fit your own LDAP schema + extension and user mapping entry layout. +2) Use UserMappingRepositorySetup.java to set up the configuration file. +3) Use UserMappingRepositoryLookup.java to test the lookup. +4) Be careful that if you decide to rename UserMappingRepositoryLDAP to +something else, ensure all the relevant files are renamed consistently +that include UserMappingRepositoryLDAP.java, UserMappingRepositoryLDAP.jar +and UserMappingRepositoryLDAP.cfg. + +For more information on developing Java user mapping plugin, please +see the Federated System Guide. diff --git a/federated/umplugin/ldap/UserMappingCryptoLDAP.java b/federated/umplugin/ldap/UserMappingCryptoLDAP.java new file mode 100644 index 0000000..c67dd6a --- /dev/null +++ b/federated/umplugin/ldap/UserMappingCryptoLDAP.java @@ -0,0 +1,99 @@ +/********************************************************************** + * + * Source File Name = UserMappingCryptoLDAP.java + * + * (C) COPYRIGHT International Business Machines Corp. 2003, 2004, 2005 + * All Rights Reserved + * Licensed Materials - Property of IBM + * + * US Government Users Restricted Rights - Use, duplication or + * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + * + * Operating System = all + * + ***********************************************************************/ +import javax.crypto.*; +import javax.crypto.spec.*; + +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; + +import com.ibm.ii.um.UserMappingCrypto; +import com.ibm.ii.um.UserMappingException; + +/** + * This class implements encryption and decryption of bytes + * and is used by the user mapping plugin Java sample. + * It is stronly recommended that you customize this class + * to fit your security needs. + */ +public class UserMappingCryptoLDAP extends UserMappingCrypto { + + public UserMappingCryptoLDAP() throws UserMappingException { + try { + // algorithm used to encrypt user mappings on the LDAP server + cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); + // key used to encrypt user mappings on the LDAP server + key = getKey(); + } + catch (Exception e) { + throw new UserMappingException(UserMappingException.DECRYPTION_ERROR); + } + } + + /** + * Encrypt the plainValue parameter. + */ + public byte[] encrypt(byte[] plainValue) throws Exception { + byte[] result = null; + cipher.init(Cipher.ENCRYPT_MODE, key); + result = cipher.doFinal(plainValue); + return result; + } + + /** + * Decrypt the encryptedValue parameter. + */ + public byte[] decrypt(byte[] encryptedValue) throws Exception { + byte[] result = null; + cipher.init(Cipher.DECRYPT_MODE, key); + result = cipher.doFinal(encryptedValue); + return result; + } + + /** + * Return the key used for encryption/decryption + */ + private SecretKey getKey() throws Exception { + SecretKey result = null; + // raw key material, 24 byte = 192 bit + byte[] rawKey = { + (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c, + (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99, + (byte)0xa7, (byte)0xf3, (byte)0x48, (byte)0x1e, + (byte)0x62, (byte)0xc1, (byte)0xd7, (byte)0xaa, + (byte)0xba, (byte)0x22, (byte)0xf5, (byte)0x74, + (byte)0xcf, (byte)0x98, (byte)0xac, (byte)0xe2 + }; + DESedeKeySpec myKeySpec = new DESedeKeySpec(rawKey); + SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede"); + result = factory.generateSecret(myKeySpec); + return result; + } + + /** + * Uses the Base64Decoder to decode String to bytes. + */ + public byte[] decode(String string) throws Exception { + byte[] result = new BASE64Decoder().decodeBuffer(string); + return result; + } + + /** + * Uses the Base64Encoder to encode byte array into Sring. + */ + public String encode(byte[] bytes) throws Exception { + String result = new BASE64Encoder().encode(bytes); + return result; + } +} diff --git a/federated/umplugin/ldap/UserMappingLookupLDAP.java b/federated/umplugin/ldap/UserMappingLookupLDAP.java new file mode 100644 index 0000000..aec010d --- /dev/null +++ b/federated/umplugin/ldap/UserMappingLookupLDAP.java @@ -0,0 +1,180 @@ +/********************************************************************** + * + * Source File Name = UserMappingLookupLDAP.java + * + * (C) COPYRIGHT International Business Machines Corp. 2003, 2004, 2005 + * All Rights Reserved + * Licensed Materials - Property of IBM + * + * US Government Users Restricted Rights - Use, duplication or + * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + * + * Operating System = all + * + ***********************************************************************/ +import java.io.*; + +import com.ibm.ii.um.*; + +/** + * This simple UserMappingLookupLDAP class is used to test if the + * UserMappingRepositoryLDAP is implemented correctly. + */ +public class UserMappingLookupLDAP { + + private static String configFilePath = System.getProperty("user.dir"); + + private static String iiInstanceName = null; + private static String iiDatabaseName = null; + private static String iiRemoteServerName = null; + private static String iiAuthID = null; + + /** + * The main function gets input parameters, + * looks up the user mapping entry, and print them out. + */ + public static void main(String[] args) { + // Lookup + if (args.length == 0) { + printUsage(); + System.exit(-1); + } + + // Lookup -h + if (args[0].equalsIgnoreCase("-h")) { + printUsage(); + System.exit(-1); + } + + // Lookup -server -authid + // Mandatory parameter -server + if (!args[0].equalsIgnoreCase("-server")) { + System.out.println("Error: Parameter -server is missing"); + printUsage(); + System.exit(-1); + } + else + if (args.length > 1 && + args[1] != null) { + iiRemoteServerName = args[1]; + } + else { + System.out.println("Error: Parameter is missing"); + printUsage(); + System.exit(-1); + } + + // Mandatory parameter -authid + if (!(args.length > 2 && + args[2].equalsIgnoreCase("-authid"))) { + System.out.println("Error: Parameter -authid is missing"); + printUsage(); + System.exit(-1); + } + else + if (args.length > 3 && + args[3] != null) { + iiAuthID = (String) args[3]; + } + else { + System.out.println("Error: Parameter is missing"); + printUsage(); + System.exit(-1); + } + + // Optional paramter -instance + if (args.length > 4 ) { + if (!args[4].equalsIgnoreCase("-instance")) { + System.out.println("Error: Invalid parameter" + args[4]); + printUsage(); + System.exit(-1); + } + else + if (args.length > 5 && + args[5] != null) { + iiInstanceName = (String) args[5]; + } + else { + System.out.println("Error: Parameter is missing."); + printUsage(); + System.exit(-1); + } + + if (args.length > 6) { + if (!args[6].equalsIgnoreCase("-database")) { + System.out.println("Error: Invalid parameter" + args[6]); + printUsage(); + System.exit(-1); + } + else + if (args.length > 7 && + args[7] != null) { + iiDatabaseName = (String) args[7]; + } + else { + System.out.println("Error: Parameter is missing."); + printUsage(); + System.exit(-1); + } + } + } + + System.out.println("IIInstance=" + iiInstanceName); + System.out.println("IIDatabase=" + iiDatabaseName); + System.out.println("IIRemoteServerName=" + iiRemoteServerName); + System.out.println("IIAuthID=" + iiAuthID); + + UserMappingRepository myLDAP = null; + UserMappingEntry myUM = null; + + try { + // initialize UserMappingRepository subclass + myLDAP = new UserMappingRepositoryLDAP(configFilePath); + } + catch (UserMappingException e) { + System.out.println("ErrorNumber: " + e.getErrorNumber()); + System.out.println("ErrorMessage: " + e.getErrorMessage()); + System.exit(-1); + } + + try { + // call the same lookupUM that II is going to call + myUM = myLDAP.lookupUM(myLDAP, + iiInstanceName, + iiDatabaseName, + iiRemoteServerName, + iiAuthID); + } + catch (UserMappingException e) { + System.out.println("ErrorNumber: " + e.getErrorNumber()); + System.out.println("ErrorMessage: " + e.getErrorMessage()); + System.exit(-1); + } + + // extract the options that II is going to extract + UserMappingOption option = myUM.getFirstOption(); + while (option != null) { + System.out.println(option.getName() + "=" + option.getValue()); + option = option.getNextOption(); + } + } + + /** + * Print command usage of UserMappingLookupLDAP + */ + private static void printUsage() { + System.out.println("================================================"); + System.out.println(" UserMappingLookupLDAP Usage "); + System.out.println("================================================"); + System.out.println("UserMappingLookupLDAP -h"); + System.out.println(">> Display help information."); + System.out.println(""); + + System.out.println("UserMappingLookupLDAP -server "); + System.out.println(" -authID "); + System.out.println(" [-instance ]"); + System.out.println(" [-database ]"); + System.out.println(">> Displays a specific user mapping, "); + System.out.println(">> -server and -authid are mandatory paramters."); + } +} diff --git a/federated/umplugin/ldap/UserMappingRepositoryLDAP.java b/federated/umplugin/ldap/UserMappingRepositoryLDAP.java new file mode 100644 index 0000000..e7ba86f --- /dev/null +++ b/federated/umplugin/ldap/UserMappingRepositoryLDAP.java @@ -0,0 +1,291 @@ +/********************************************************************** +* +* Source File Name = UserMappingRepositoryLDAP.java +* +* (C) COPYRIGHT International Business Machines Corp. 2003, 2004 +* All Rights Reserved +* Licensed Materials - Property of IBM +* +* US Government Users Restricted Rights - Use, duplication or +* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +* +* Operating System = all +* +***********************************************************************/ +import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.lang.Exception; +import java.util.Hashtable; +import java.util.Properties; +import javax.naming.*; +import javax.naming.directory.*; +import com.ibm.ii.um.*; + +/* + * Sample subclass of UserMappingRepository that uses an LDAP directory + * as the repository for storing and retrieving user mapping entries. + */ + +public class UserMappingRepositoryLDAP extends UserMappingRepository { + + // ================== + // CONFIGURATION FILE + // ================== + // configuration file name default to this class name with suffix .cfg + private String configFileName = UserMappingRepositoryLDAP.class.getName() + ".cfg"; + + // ======================== + // CONFIGURATION PARAMETERS + // ======================== + private String hostname = null; + private String portnumber = null; + private String baseDN = null; + private String userid = null; + private String password = null; + + private String serverSSLEnabled = null; + private String serverCAcertStore = null; + private String serverCAcertStorePassword = null; + + private String mutualAuthRequired = null; + private String clientKeystore = null; + private String clientKeystorePassword = null; + + // ============================ + // LDAP CONTEXT AND ENVIRONMENT + // ============================ + private DirContext ctx = null; + private Hashtable env = null; + + // ======================= + // LDAP OBJECT CLASS NAMES + // ======================= + // LDAP object class name that represents a user entry. + private String UserObjectClassName = "inetOrgPerson"; + + // LDAP object class name that represents a user mapping entry. + private String UserMappingObjectClassName = "IIUserMapping"; + + // ========================= + // LDAP ATTRIBUTE TYPE NAMES + // ========================= + // LDAP attribute name that represents the II Authorization ID. + private String UserAuthIDAttrName = "uid"; + + // LDAP attribute type names that represent II user mapping properties. + private String IIRemoteServerAttrName = "IIRemoteServerName"; + private String IIInstanceAttrName = "IIInstanceName"; + private String IIDatabaseAttrName = "IIDatabaseName"; + private String IIRemoteAuthIDAttrName = "uid"; + private String IIRemotePasswordAttrName = "IIRemotePassword"; + + /* + * Instantiates the repository: + * Instantiate the crypto, and read the configuration parameters. + * @throws UserMappingException If anything failed. + */ + public UserMappingRepositoryLDAP(String configFilePath) throws UserMappingException { + try { + // Instantiate the crypto + crypto = new UserMappingCryptoLDAP(); + + // Read properties file. + Properties properties = new Properties(); + properties.load(new FileInputStream(configFilePath + + File.separatorChar + + configFileName)); + + // Get configuration parameter values + hostname = properties.getProperty("hostname"); + portnumber = properties.getProperty("portnumber"); + baseDN = properties.getProperty("baseDN"); + userid = properties.getProperty("userid"); + password = properties.getProperty("password"); + serverSSLEnabled = properties.getProperty("serverSSLEnabled"); + if (serverSSLEnabled.matches("[yY]")) { + serverCAcertStore = properties.getProperty("serverCAcertStore"); + serverCAcertStorePassword = properties.getProperty("serverCAcertStorePassword"); + mutualAuthRequired = properties.getProperty("mutualAuthRequired"); + if (mutualAuthRequired.matches("[yY]")) { + clientKeystore = properties.getProperty("clientKeystore"); + clientKeystorePassword = properties.getProperty("clientKeystorePassword"); + } + } + } + catch (Exception e) { + throw new UserMappingException(UserMappingException.INITIALIZE_ERROR); + } + } + + /* + * Connects to the repository + * @throws UserMappingException If the connection or authentication failed. + */ + public void connect() throws UserMappingException { + + String LDAPURL = new String("ldap://" + + hostname + ":" + + portnumber + "/" + + baseDN); + try { + // retrieve required connection parameters + env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, + LDAPURL); + env.put(Context.SECURITY_AUTHENTICATION, + "simple"); + env.put(Context.SECURITY_PRINCIPAL, + userid); + env.put(Context.SECURITY_CREDENTIALS, + new String(crypto.getChars(crypto.decrypt(crypto.decode(password))))); + + if (serverSSLEnabled.matches("[yY]")) { + env.put(Context.SECURITY_PROTOCOL, + "ssl"); + System.setProperty("javax.net.ssl.trustStore", + serverCAcertStore); + System.setProperty("javax.net.ssl.trustStorePassword", + new String(crypto.getChars(crypto.decrypt(crypto.decode(serverCAcertStorePassword))))); + + if (mutualAuthRequired.matches("[yY]")) { + env.put(Context.SECURITY_AUTHENTICATION, + "EXTERNAL"); + System.setProperty("javax.net.ssl.keyStore", + clientKeystore); + System.setProperty("javax.net.ssl.keyStorePassword", + new String(crypto.getChars(crypto.decrypt(crypto.decode(clientKeystorePassword))))); + } + } + + // connect and authenticate to LDAP server + ctx = new InitialDirContext(env); + } + catch (AuthenticationException e) { + throw new UserMappingException(UserMappingException.AUTHENTICATION_ERROR); + } + catch (Exception e) { + throw new UserMappingException(UserMappingException.CONNECTION_ERROR); + } + } + + /* + * Disonnects from the repository. + */ + public void disconnect() { + try { + ctx.close(); + } + catch (NamingException e){} + } + + /* + * Fetches a user mapping from the repository. + * The um parameter contains detailed query information to determine + * which user mapping should be fetched. + * UserMappingOption will be created/added to contain the fetch result. + * @throws UserMappingException If no match found. + */ + public void fetchUM(UserMappingEntry um) throws UserMappingException { + + String filter = null; + SearchControls ctls = new SearchControls(); + + NamingEnumeration userEntry = null; + NamingEnumeration userMappingEntry = null; + + try { + // FIRST SEARCH: user entry + String iiAuthID = um.getIIAuthID(); + + // filter for correct user + if (iiAuthID != null) { + filter = ("(&("+ UserAuthIDAttrName + "=" + iiAuthID + ")(objectclass=" + UserObjectClassName + "))"); + } + else { + throw new UserMappingException(UserMappingException.INVALID_PARAMETER_ERROR); + } + + // set search controls + ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); + String [] returnAttr1 = {UserAuthIDAttrName}; + ctls.setReturningAttributes(returnAttr1); + + // search + try { + userEntry = ctx.search("", filter, ctls); + } + catch (SizeLimitExceededException e) { + } + + String userEntryDN = ((SearchResult)userEntry.next()).getName(); + + // SECOND SEARCH: find user mapping entry + String iiRemoteServerName = um.getIIRemoteServerName(); + String iiInstanceName = um.getIIInstanceName(); + String iiDatabaseName = um.getIIDatabaseName(); + + // filter for correct user mapping + filter = null; + if (iiRemoteServerName != null) { + filter = ("(&("+ IIRemoteServerAttrName + "=" + iiRemoteServerName+")"); + } + else { + throw new UserMappingException(UserMappingException.INVALID_PARAMETER_ERROR); + } + if (iiInstanceName != null) { + filter = (filter + + "(" + IIInstanceAttrName + "=" + iiInstanceName+ ")"); + } + if (iiDatabaseName != null) { + filter = (filter + + "(" + IIDatabaseAttrName + "=" + iiDatabaseName+ ")"); + } + filter = (filter + + "(objectclass=" + UserMappingObjectClassName + "))"); + + // set search controls + ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE); + String [] returnAttr2 = {IIRemoteAuthIDAttrName, IIRemotePasswordAttrName}; + ctls.setReturningAttributes(returnAttr2); + + try { + userMappingEntry = ctx.search(userEntryDN, filter, ctls); + } + catch (SizeLimitExceededException e) { + } + + // parse the result + Attributes userMappingAttrs = ((SearchResult)userMappingEntry.next()).getAttributes(); + String iiRemoteAuthID = (String)userMappingAttrs.get(IIRemoteAuthIDAttrName).get(0); + String iiRemotePassword = (String)userMappingAttrs.get(IIRemotePasswordAttrName).get(0); + + if (iiRemoteAuthID != null) { + StringOption authIDOption = new StringOption(um); + authIDOption.setName(StringOption.REMOTE_AUTHID_OPTION); + authIDOption.setValue(iiRemoteAuthID); + um.addOption(authIDOption); + } + else { + throw new UserMappingException(UserMappingException.LOOKUP_ERROR); + } + + if (iiRemotePassword != null) { + StringOption pwdOption = new StringOption(um); + pwdOption.setName(StringOption.REMOTE_PASSWORD_OPTION); + pwdOption.setValue(new String(crypto.getChars(crypto.decrypt(crypto.decode(iiRemotePassword))))); + um.addOption(pwdOption); + } + else { + throw new UserMappingException(UserMappingException.LOOKUP_ERROR); + } + } + catch (Exception e) { + throw new UserMappingException(UserMappingException.LOOKUP_ERROR); + } + } +} diff --git a/federated/umplugin/ldap/UserMappingSetupLDAP.java b/federated/umplugin/ldap/UserMappingSetupLDAP.java new file mode 100644 index 0000000..6ebe4e1 --- /dev/null +++ b/federated/umplugin/ldap/UserMappingSetupLDAP.java @@ -0,0 +1,463 @@ +/********************************************************************** + * + * Source File Name = UserMappingSetupLDAP.java + * + * (C) COPYRIGHT International Business Machines Corp. 2003, 2004, 2005 + * All Rights Reserved + * Licensed Materials - Property of IBM + * + * US Government Users Restricted Rights - Use, duplication or + * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + * + * Operating System = all + * + ***********************************************************************/ +import java.io.*; +import java.util.Properties; +import com.ibm.ii.um.*; + +/** + * One time configuration setup for the LDAP plugin sample. + * It is a standalone Java program that can be invoked from command line. + */ + +public class UserMappingSetupLDAP +{ + // set up the input stream + BufferedReader bin; + + // set up the ouput stream + private OutputStream configFile; + + // configuration file path default to current directory + private String configFilePath = System.getProperty("user.dir"); + // configuration file name must match the plugin name with .cfg suffix + private String configFileName = UserMappingRepositoryLDAP.class.getName() + ".cfg"; + + // hostname of LDAP server + private String hostname = null; + // portnumber of LDAP server + private String portnumber = null; + // base DN in LDAP server's directory to start search + private String baseDN = null; + // userid and password to bind with LDAP server + private String userid = null; + private String password = null; + + // Is LDAP server SSL enabled? + private String serverSSLEnabled = null; + // keystore and password for LDAP server's CA certificate + private String serverCAcertStore = null; + private String serverCAcertStorePassword = null; + + // Is LDAP client/server mutual authentication required? + private String mutualAuthRequired = null; + // keystore and password for LDAP client's public/private keys and certificate + private String clientKeystore = null; + private String clientKeystorePassword = null; + + public UserMappingSetupLDAP() throws IOException { + bin = new BufferedReader(new InputStreamReader(System.in)); + try { + configFile = new FileOutputStream(configFilePath + + File.separatorChar + + configFileName); + } + catch (IOException ioe){ + System.out.println("Exception while creating the config file"); + ioe.printStackTrace(); + } + } + + public static void main(String args[]) throws Exception { + UserMappingSetupLDAP mySetup = new UserMappingSetupLDAP(); + try { + mySetup.printWelcome(); + mySetup.askHostname(); + mySetup.askPortnumber(); + mySetup.askBaseDN(); + mySetup.askUseridPassword(); + mySetup.askServerSSLEnabled(); + mySetup.askMutualAuthRequired(); + mySetup.writeToFile(); + mySetup.printBye(); + } + catch (Exception e) + { + System.out.println(e.getMessage()); + e.printStackTrace(); + } + } + + private void printWelcome() + { + System.out.println(""); + System.out.println(""); + System.out.println("===================================================="); + System.out.println(" WELCOME TO THE SETUP PROGRAM OF "); + System.out.println(" WS II USER MAPPING PLUG-IN LDAP SAMPLE "); + System.out.println("===================================================="); + System.out.println(""); + System.out.println("PURPOSE: Set up the required configuration parameters."); + System.out.println(""); + System.out.println("USAGE: java UserMappingSetupLDAP"); + System.out.println(" Enter the value of the requested parameter"); + System.out.println(" To proceed to the next parameter, press ENTER."); + System.out.println(" To quit at anytime, press Ctrl/C."); + System.out.println(""); + System.out.println(" The config file path defaults to the current directory."); + System.out.println(" The config file name matches the plugin name with suffix .cfg"); + System.out.println(" The config parameter values are written into the config file."); + System.out.println(" Passwords are encrypted in the config file."); + System.out.println(" To change config parameter values, run this setup program again."); + System.out.println(""); + System.out.println("===================================================="); + System.out.println(" PLEASE INPUT THE SETUP PARAMETERS: "); + System.out.println("===================================================="); + System.out.println(""); + } + + private void printBye() + { + System.out.println("===================================================="); + System.out.println(" CONFIGURATION SETUP FINISHED SUCCESSFULLY! "); + System.out.println("===================================================="); + } + + /** + * Requests the user to input the hostname and does syntax check on it. + * @throws IOException If there is a problem with reading the user's + * input from the command line + */ + private void askHostname() throws IOException { + boolean ready = false; + String tempString = null; + try { + while (!ready) { + System.out.print("HOST NAME of LDAP server, e.g., daytona.svl.ibm.com --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0 && + tempString.matches("[^\\s,<>\\?]+?\\.?[^\\s,<>\\?]+")) { + hostname = tempString; + ready = true; + } + else { + System.out.println("-- Wrong host name syntax (DNS or IPv4 formats), try again --"); + } + } // end of while + } + catch (IOException ioe) { + System.out.println("Exception while reading hostname."); + throw(ioe); + } + } + + /** + * Requests the user to input the port number and does syntax check on it. + * @throws IOException If there is a problem with reading the user's + * input from the command line + */ + private void askPortnumber() throws IOException { + boolean ready = false; + String tempString = null; + try { + while (!ready) { + System.out.print("PORT NUMBER of LDAP server, e.g., 389 --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0 && + tempString.matches("[0-9]+")) { + portnumber = tempString; + ready = true; + } + else { + System.out.print("-- Wrong port number syntax (from 0 to 65535), try again -- "); + } + } // end of while + } + catch (IOException ioe) { + System.out.println("Exception while reading port number."); + throw(ioe); + } + } + + /** + * Requests the user to input the baseDN. + * The baseDN represents the root of the LDAP subtree to start the search + * @throws IOException If there is a problem with reading the user's + * input from the command line + */ + private void askBaseDN() throws IOException { + boolean ready = false; + String tempString = null; + try { + while (!ready) { + System.out.print("BASE DN of LDAP subtree, e.g., ou=ii,o=ibm,c=us --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0) { + baseDN = tempString; + ready = true; + } + else { + System.out.println(" -- No BASE DN provided, try again! -- "); + } + } // end of while + } + catch (IOException ioe) { + System.out.println("Exception while reading base DN."); + throw(ioe); + } + } + + /** + * Requests the user to input the userid and password to bind to LDAP server + * @throws IOException If there is a problem with reading the user's + * input from the command line + */ + private void askUseridPassword() throws Exception { + boolean ready = false; + String tempString = null; + UserMappingCryptoLDAP myCrypto = null; + + try { + while (!ready) { + System.out.print("USERID to bind to LDAP Server, e.g., cn=root --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0) { + userid = tempString; + ready = true; + } + else { + System.out.println(" -- No userid provided, try again -- "); + } + } // end of while + } + catch (IOException ioe) { + System.out.println("Exception while reading userid."); + throw(ioe); + } + + try { + myCrypto = new UserMappingCryptoLDAP(); + } + catch (Exception e) { + System.out.println("Exception while getting crypto."); + throw(e); + } + + try { + ready = false; + tempString = null; + while (!ready) { + System.out.print("PASSWORD for the userid --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0) { + password = myCrypto.encode(myCrypto.encrypt(myCrypto.getBytes(tempString.toCharArray()))); + ready = true; + } + else { + System.out.print("-- No password provided, try again -- "); + } + } // end of while + } + catch (Exception e) { + System.out.println("Exception while reading password."); + throw(e); + } + } + + /** + * Requests the user to input if SSL is enabled for the LDAP Server. + * If SSL is enabled, all communication will be encrypted and the + * authentication during SSL handshake requires at least the server + * to present its CA certificate. + * @throws IOException If there is a problem with reading the user's + * input from the command line + */ + private void askServerSSLEnabled() throws Exception { + boolean ready = false; + String tempString = null; + UserMappingCryptoLDAP myCrypto = null; + + try { + while (!ready) { + System.out.print("Is LDAP server SSL enabled? y or n --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0 && + tempString.matches("[yYnN]")) { + serverSSLEnabled = tempString; + ready = true; + } + else { + System.out.print(" -- No LDAP server SSL info provided, try again -- "); + } + } // end of while + } + catch (IOException ioe) { + System.out.println("Exception while reading LDAP server SSL info."); + throw(ioe); + } + + if (serverSSLEnabled.matches("[yY]")) { + try { + ready = false; + tempString = null; + while (!ready) { + System.out.print("KEYSTORE with LDAP server's CA certificate, e.g., /myhome/myjdk/jre/lib/security/cacerts --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0) { + serverCAcertStore = tempString; + ready = true; + } + else { + System.out.println(" -- No LDAP server CA certificate keystore provided, try again -- "); + } + } // end of while + } + catch (IOException ioe) { + System.out.println("Exception while reading LDAP server CA certificate keystore."); + throw(ioe); + } + + try { + myCrypto = new UserMappingCryptoLDAP(); + } + catch (Exception e) { + System.out.println("Exception while getting crypto."); + throw(e); + } + + try { + ready = false; + tempString = null; + while (!ready) { + System.out.print("PASSWORD for the LDAP server CA certificate keystore --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0) { + serverCAcertStorePassword = myCrypto.encode(myCrypto.encrypt(myCrypto.getBytes(tempString.toCharArray()))); + ready = true; + } + else { + System.out.print("-- No LDAP server CA certificate keystore password provided, try again -- "); + } + } // end of while + } + catch (Exception e) { + System.out.println("Exception while reading LDAP server CA certificate keystore password."); + throw(e); + } + } // end of if + } + + /** + * Requests the user to input if mutual authentication is required + * between LDAP client and LDAP server. This mutual authentication + * is valid only if the LDAP server is SSL enabled plus client + * authentication is required as well. It requires the LDAP client + * to present its keystore with public/private key pair and certificate. + * @throws IOException If there is a problem with reading the user's + * input from the command line + */ + private void askMutualAuthRequired() throws Exception { + boolean ready = false; + String tempString = null; + UserMappingCryptoLDAP myCrypto = null; + + if (serverSSLEnabled.matches("[yY]")) { + try { + while (!ready) { + System.out.print("LDAP client/server mutual authentication required? y or n --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0 && + tempString.matches("[yYnN]")) { + mutualAuthRequired = tempString; + ready = true; + } + else { + System.out.print(" -- No LDAP client/server mutual authentication info provided, try again -- "); + } + } // end of while + } + catch (IOException ioe) { + System.out.println("Exception while reading LDAP client/server mutual authentication info."); + throw(ioe); + } + + if (mutualAuthRequired.matches("[yY]")) { + try { + ready = false; + tempString = null; + while (!ready) { + System.out.print("KEYSTORE with LDAP client's public/private keys and certificate, e.g., /myhome/clientkey.jks --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0) { + clientKeystore = tempString; + ready = true; + } + else { + System.out.println(" -- No LDAP client keystore provided, try again -- "); + } + } // end of while + } + catch (IOException ioe) { + System.out.println("Exception while reading LDAP client keystore."); + throw(ioe); + } + + try { + myCrypto = new UserMappingCryptoLDAP(); + } + catch (Exception e) { + System.out.println("Exception while getting crypto."); + throw(e); + } + + try { + ready = false; + tempString = null; + while (!ready) { + System.out.print("PASSWORD for LDAP client keystore --> "); + if ((tempString = bin.readLine()) != null && + tempString.length() != 0) { + clientKeystorePassword = myCrypto.encode(myCrypto.encrypt(myCrypto.getBytes(tempString.toCharArray()))); + ready = true; + } + else { + System.out.print("-- No LDAP client keystore password provided, try again -- "); + } + } // end of while + } + catch (Exception e) { + System.out.println("Exception while reading LDAP client keystore password."); + throw(e); + } + } // end of if mutualAuthRequired + } // end of if serverSSLEnabled + } + + private void writeToFile() throws Exception { + try { + Properties properties = new Properties(); + properties.setProperty("hostname", hostname); + properties.setProperty("portnumber", portnumber); + properties.setProperty("baseDN", baseDN); + properties.setProperty("userid", userid); + properties.setProperty("password", password); + properties.setProperty("serverSSLEnabled", serverSSLEnabled); + if (serverSSLEnabled.matches("[yY]")) { + properties.setProperty("serverCAcertStore", serverCAcertStore); + properties.setProperty("serverCAcertStorePassword", serverCAcertStorePassword); + properties.setProperty("mutualAuthRequired", mutualAuthRequired); + if (mutualAuthRequired.matches("[yY]")) { + properties.setProperty("clientKeystore", clientKeystore); + properties.setProperty("clientKeystorePassword", clientKeystorePassword); + } + } + properties.store(configFile,null); + configFile.close(); + } + catch (Exception e) { + System.out.println("Exception while writing into the config file."); + throw(e); + } + } +} diff --git a/federated/umplugin/ldap/entry.ldif b/federated/umplugin/ldap/entry.ldif new file mode 100644 index 0000000..1c25d75 --- /dev/null +++ b/federated/umplugin/ldap/entry.ldif @@ -0,0 +1,41 @@ +# ================================================================ +# NEW ENTRIES: assume o=IBM,c=US suffix created +# ================================================================ + +dn: o=IBM,c=US +objectclass: organization +o: IBM + +dn: ou=II,o=IBM,c=US +objectclass: organizationalUnit +ou: II + +dn: uid=,ou=II,o=IBM,c=US +objectclass: inetOrgPerson +cn: Tian Zhang +sn: Zhang +uid: +mail: @us.ibm.com + +dn: uid=newton,ou=II,o=IBM,c=US +objectclass: inetOrgPerson +cn: Famous Newton +sn: Newton +uid: newton +mail: newton@us.ibm.com + +dn: IIRemoteServerName=,uid=,ou=II,o=IBM,c=US +objectclass: IIUserMapping +IIRemoteServerName: +IIInstanceName: +IIDatabaseName: +uid: newton +IIRemotePassword: <74BTjiRTSVcUHISN/Uhsjw==> + +dn: IIRemoteServerName=,uid=newton,ou=II,o=IBM,c=US +objectclass: IIUserMapping +IIRemoteServerName: +IIInstanceName: +IIDatabaseName: +uid: +IIRemotePassword: diff --git a/federated/umplugin/ldap/schema.ldif b/federated/umplugin/ldap/schema.ldif new file mode 100644 index 0000000..54b1a01 --- /dev/null +++ b/federated/umplugin/ldap/schema.ldif @@ -0,0 +1,52 @@ +# =================== +# NEW ATTRIBUTE TYPES +# =================== +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 1.3.18.0.2.6.9001 NAME 'IIInstanceName' + DESC 'Name of DB2 instance, as set by II' + EQUALITY 2.5.13.2 ORDERING 2.5.13.3 SUBSTR 2.5.13.4 + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE + USAGE userApplications ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 1.3.18.0.2.6.9002 NAME 'IIDatabaseName' + DESC 'Name of DB2 database, as set by II' + EQUALITY 2.5.13.2 ORDERING 2.5.13.3 SUBSTR 2.5.13.4 + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE + USAGE userApplications ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 1.3.18.0.2.6.9003 NAME 'IIRemoteServerName' + DESC 'Name of the remote data source as set by II' + EQUALITY 2.5.13.2 ORDERING 2.5.13.3 SUBSTR 2.5.13.4 + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE + USAGE userApplications ) + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 1.3.18.0.2.6.9004 NAME 'IIRemotePassword' + DESC 'Password (encrypted and encoded) for the remote server' + EQUALITY 2.5.13.2 ORDERING 2.5.13.3 SUBSTR 2.5.13.4 + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE + USAGE userApplications ) + +# =================== +# NEW OBJECT CLASSES +# =================== + +dn: cn=schema +changetype: modify +add: objectclasses +objectclasses: ( 1.3.18.0.2.6.9010 NAME 'IIUserMapping' + DESC 'II user mapping' + SUP 'top' + STRUCTURAL MUST (IIRemoteServerName) + MAY (IIInstanceName $ IIDatabaseName $ uid $ IIRemotePassword)) + diff --git a/ha/xml/db2ha.xsd b/ha/xml/db2ha.xsd new file mode 100644 index 0000000..8817fca --- /dev/null +++ b/ha/xml/db2ha.xsd @@ -0,0 +1,341 @@ + + + + + DB2 High Availability configuration schema. + This schema describes the elements of DB2 High Availability that are used in the configuration of a HA cluster. + + + + + + + + + + Each DB2 HA configuration document begins with the DB2Cluster element. + This element encapsulates the cluster configuration specification for the instance + + + + + + + + + + + + + + + + + + + + The DB2ClusterTemplate type encapsulates parameterization information about the DB2 cluster. + It can be used to deploy complex DB2 DPF configurations or roll out a number of similar DB2 HA configurations + + + + + + + + + + + + + The DB2ClusterTemplateParameter type is used to define the parameters for the cluster template + + + + + + + + + + + + + + + The DB2ClusterTemplateParameterException type is used to define the exception element for parameterization + + + + + + + + + + + + The DB2ClusterTemplateParameterValue type is used to define the value for parameterization + + + + + + + + + + + The DB2Instance element encapsulates the cluster confiuguration specification for the instance + + + + + + + + + + + + + + + + + Each cluster domain can have a number of physical systems (nodes). + TSA currently supports a maximum of 32 nodes per cluster domain. + DB2 single partition instances will typically only have a single cluster domain. + In DB2 DPF implementations, it is not uncommon to have database partition groups setup for mutual failover + in pairs of nodes where both nodes are in a single cluster domain. + + + + + + + + + + + + + + + + The failover policy specifies the failover order of the cluster nodes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The HADRDB element lists the HADRDB Sets + + + + + + + + + + + + + + + The HADRDB element defines the HADR databases to be automated for takeover + + + + + + + + + + + + + + + + The HADB element lists the Databases to be made HA + + + + + + + + + + + + + + The HADB element defines the HADR database to be made HA + + + + + + + + + + + The quorum specifies the quorum configuration for the cluster domain + + + + + + + + + + + + This element type is an enumeration of the quorum types supported. + + + + + + + + + + + + + + + + + The physical network specifies the network type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The cluster node specifies the physical machine/node in the cluster domain + + + + + + + + + + + + The DB2 partition type specifies a DB2 Partition + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ha/xml/db2ha_sample_DPF_NPlusM.xml b/ha/xml/db2ha_sample_DPF_NPlusM.xml new file mode 100644 index 0000000..81a45ce --- /dev/null +++ b/ha/xml/db2ha_sample_DPF_NPlusM.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ha/xml/db2ha_sample_DPF_mutual.xml b/ha/xml/db2ha_sample_DPF_mutual.xml new file mode 100644 index 0000000..fa9863c --- /dev/null +++ b/ha/xml/db2ha_sample_DPF_mutual.xml @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ha/xml/db2ha_sample_HADR.xml b/ha/xml/db2ha_sample_HADR.xml new file mode 100644 index 0000000..42c7b70 --- /dev/null +++ b/ha/xml/db2ha_sample_HADR.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ha/xml/db2ha_sample_sharedstorage_mutual.xml b/ha/xml/db2ha_sample_sharedstorage_mutual.xml new file mode 100644 index 0000000..cd8b392 --- /dev/null +++ b/ha/xml/db2ha_sample_sharedstorage_mutual.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/Websphere/AIRLINE.war b/java/Websphere/AIRLINE.war new file mode 100644 index 0000000000000000000000000000000000000000..f10e98f4754e7475c912d98644b7d6a134fc9467 GIT binary patch literal 988058 zcmb5UbFe5u^WS}J-(%ahZQHi3du-dbZQHhO+djF^FI9Pyyp>dCW_xODyQXJr|JnZb zr{$%9L689;{>^&J2o8Y%X(0c*ml07GpplRjrIQhml@JwCQl^y=eUzD+l$N5Qorjg8 zp`4kTZB(RRV%j@)oROfWU4a#+9F``viwxGv)8Wss$o&Iket zhHsMD)FR)qf}ALcm424*N?bfV9<(YC%|TKn(nPt_-(_u1Gyq`WY(ENpcXg41$Xb1$ zcC??v7azL#Vn1`(&|$|e=by1225j8M#OH(^hZloJa@^im2xhd)ucjVTCW||{U6mLf zMQ@p@=(^ZtNSugJIQYRr<#RX+73Ng5hpF2n40Grm`#~`*VB>Jjfzz%$OaZI#Dnio` zRl+eO&-;dOgL{7mc5!1`2vJJ{2+hnSGU}Yt-azJZgzbk8Ee800{CYRYy$ksZP1SdF z=tUqS77cxmzh+vYHOmeJw|`J&oYFPD!HyWXH4|vo`0;@uCf>wBBE6@ZvY6zN*$z60%X3eCKB(H1~qS&?X%{%UOo2(?LK+O%xn6f%OFm7!S!+@dh#aI!h!Jo zdvA!Naq&} z!zji$pC|SQ0E?YBBMAlrH*#=ILprMHr@G2IzWZ^D}46iBq7>4QH;25nH z?b+*F8Nv|hOvC5NazF16#H3o*w{C0{FF7$-@4#z3JYQkYj|K-g{Tb8fR=wKyXCGR8 zj{QLirdQhbu*_^zky>C>%}lvunkMLAH5RRx-9Zo$kQx>?dZLU%Vfn zJLE~d>dN%ZfJUA{L(TeLw+wZMMS2{CJ|bTNqGGYFw$P+kQWW9%kh+9GOC8mI+ZAV) zMau}QMvUbd4rP*fh+V`-JVzi1?;@f@AAOK%;7?gok}xtzzP!y~C;}3^{$|B{;-cas zoxr{3DHf1m!-#=|%MyMT3xVKTZw%Ifb8^IbDR8K_N z-QJb`Opaa)GdHsm9-~9ZAK6S(U#F~vIq`q8G6PndiGSg_h_Z>$=YFbjI?bKl2&IA< zWn!p)BeqZB{;JY024kXT@;`Gw(CK5rOcDFT-CGPkT+XC*$V=Wy)Tj^Uiw|0S_#})vDAg`k!+muH zmIO$!?Co(;g207`&0J@Nc^Q--?v6}^C{3I&Q=y}E%#ffc3=ZH1s5UUiPu08^@o7+N zWFwN`P6_p|A+&{-C0fu5s-7OEKtb^!F0dt{I6(jDm&`f4u>se&875_3^F>3KK7U39 zvUX=uh|?Lvvl5LOQ!a|^fNn<}@!6K<&2yQj|0xvJI+Xo@eOwwke^jx?7+Ht2W^eVE zNnW$}fW?}1-P4@2hl_pzW98C4I9liQMUUKcI9LJ`#J*Cd9?+@>NMHZ~V1|%)&HHJ` zc$v9dn8PQ@nUGCIT7(Zhkw?uBcId{{;cPz`^H3JtvXT-4%KI}WVRiD91MjiQ+^;EJ z5Dq_$L;;TZAfJr=OtsM`IvPt_7G`Pl_|@JTfvL3GJ);A>=UAqbBdj>;=#Qf3PrL+_ zDu-&z%;Crvln=c= zbVF6Q9nimX5(zm52lkCB4QwSmoi5ZKrk3?&MGpm+aDZBQf1q{O$IE71n+IsY{@wU` z3vQ8SR7u$E37a0E&763<3rrhKrQ@O(89Wh+!w>pnWc4e8E=b&M#2D?AJvNt~9pj{) zl6G)PflV|RTVU4&D~7V+!q{h^M=u`F=~tpHt^&>C=KWVAVO22TEsqB#!m=wOPvzn+ z5Mk^M)EV4+8;YfbIVD*N^<1>32n)ms?p}$m%9-1^zGh4Qq>nPLG0F$-QbZ(^W+C80 z5?eqb>KwQTtPF%R8{#av&^f&-!@djv3>Ln7Nbo)5S>CED%Oc6EwB3R_DEY9MHE=8i+CIFLp zgB4{PSx!jB%B#wO9TeMlmlFVZ949A57m`QzAMeP0-wX^>g+a$)ey)#~&#dPW+VA@S+yP;RltdJF=>q~iaWyM;}Y3!8CYtDB38ut-kA=T$&n1eoGaLz4WN1SCoiPYZDuxbf`oh6bGtq-`PD}Ep zb@CObJ>Rj8=f-Vfxw1odUM7B|v>x-(+>CHH!}{Ver?oq^nA;H!_TdE1hj2{96!ZhC zhquKsc(CwfQ9u;iRd-Ym>h3@aP__r4Px8J2tl?ESO|Lcnz6*!n{ms4u7U)~D0RH1S zIC*nFA7|#{S_Vz4a5)>qPARZT5=F-jsp`)*s2&v_>0t&?1zj|O6j8?*9j>)Se+#Ok z4Blf)Z%|P-?KZQK#9`lw%T?}gNGd>aBn~!i6v4ABd`5rBLga>8HUKXz{Ski>8p@~l z(U)cU%d1NVn~JyZu6nhxoiE?(vQdB?xqdNoZAp|I%k7>PPhmjJpG1eJZovph?t8gQ zu5P1Cw#8>cBj%14y-KHgmEIRp11CMR^cFn=TqHKyTOm_UB2yD`;xhRZPZ!{FzFg2{ z3YFE!x9pzUGSP`mi@r$sK+#>feHHAtq3rfN##i{43?R|>DQsBq z+}_g4ZTx);D27vak3`>WN!h`J5ZgQyDfzzG%cz{a&c(& z8dJ3rm5gRX*HJ^ySMbIrQu3WFt`pfV*EBqYF$Kcthli*pZd53|F)mamR!|wG$5^-{ zg({&ll(M~ZbdS_IeY%jkUMNtu8-qE5iVJ(QXA81$A6jF|5Pd6Lr{_Lc6sCw)R?{@* zkHHgK%GiC@SL^SCjB0*9X0zdM8Z?J!pWg6QCX7E92Fb?TtO@=$g{2v#ZIDYP4BUJ2 zUB`}fyJ7{wy=rFNo$-21{%qwWrr)~wL@b9_qW4U~lV58m*$3v~A$Wn5pm}W{z1}ku zRgEYI)!i&aC-&5oYKwWKQxV2;f1IY3qN+^kw0^bSvRVG{jthS8(_R%XM?`MXH1$lG zc3Lc7waK1YsNzhEWXztlwqINo7^Ld=2P631WJ_&l*N!XrmUo(d+Z?yMGyewr{RY)# zH067sux)(g_WywYN6V}inj$8{007|p6EpvxmLdM%w9J2Glc9@+wK1Ksoy~uY#>T?- zpRSqKw6Qy6Mf&OK9YBN<&}5R_0*(mOVYSaPcH6W@l4{8Ab3u!cA?u(_AQ&I-X!-q| zjzba|cVzYK2ELIpR2WP*(`9EOc6s{Iq0_7~{M~1;L04+LKfJ%^lQ^95j4B8mDYds` z=@6LPyG<0GLPF(hOb1OgtwMZLLM63cQ4e84Wm^ziVRxCqOf_u#zG09-yDlum@H7=@ z(ywn8Y*8IsC|q9Pn<&vbUwztUiu}U|wHb|9om+M2b{o5c@o2&>V=zU(I;*?IUhK9V zySlo<_zdhA&jX_S#!ow5d&JhUlK}sA8qxE%Pwi1}I`8~GG|)sOuJLB=eQ%~$GS4Wj zA#EkbmU##VbxBd1niIUo^U%)yHgNO%q_jX2%UgGzi}I>h}D?(Kc;A?CX!*0_Aa;0@*DcYm2lCp+8I(-nj^BC!b%%x9dr)Cs?4 zfZd(O-*{|YTh6SqtNrP8xVMGmSd~OV0h4i=Ry@gW{lul^{=3=67ccZSw@!$c`NBmP z>(d9rk?U=uG#K*E+FYGR17tS=lgX3itE0}>6!v98GWkgy9i3uPJg*OUa`6|ENxHF7 zcva8G+Y)zLdbz0^%nG?Bcin{rk1Z!cwL)Joc^by?<#6 zZU$&?Q&8y0!DM=EOAG9L&Wx@@*8>EvxckhaUV42>LJg2ssI@JN@mqShGS6yL%VRbw*R~9eYY7h`ywjWQk>8`}5V__rAlV59e zG@Dts8a%Im3m*R`vEJ47^L*S>-}WkaoI4`7YW9aYCc!*Mb6fxZ%;FD~(c-!+4>G_@ zg*^jvY+?pW(WdrtKjOq`Tad#h+;ZDXx(gFiixW{LRBjU9=uFXcH;Fq|I|dGYA*?_e zR)aBNr#dPI#}JYSeE;0oex7-Ydi74|V!d4Vy(iy$jUkm1UGc1xT+B z)DPpIdi0qWboJFwRS1?r9UAmv8XYz`YkSxe(lkwD*Gm{>jllv7DPADa7d1xzV}o}J z&jdp3oDD^Hlxc%&MP=;oe2EAu?Wpw&4ju0dKsjD9X!W-^UQ1ZKwy@^gh5I7ldAqPR zE>iCc^?)j)->qBb%)Cr4*T#BC9+ADVUHd-V67AWVuj4U2ZuwS_uy(P{W0gyJ?K&I+ z^&ZD!)YK3u1os?;;3LnTt~sl(^rHI&Ktzd)ApMX^G$y|~Hn1!p;;tFYyWO4Ud`JALFiV&9VhHX3G10Qos58`y(!4uSxS~LQOl=cx7xMdi@GVQA1<# zNm4vS8$=S`gfL2$Bj|CdZwhK++03PRBpOpdd7i*fP9aV1@Fsh*VLwKqnK!ts86K5q ztcBeL1`wG6-r(|jV0wKganT|d>x6G%izWo-uHw5ys@sV+P(A_P5#J;#RefF#+t`M< zE|3>)x}!u*L&eKx3EQSUC+$6N{DO7u*oLntKZ+iXu0TGSq}?S{y=H4sD>tyb(l;Q| zCVN4tbo)3Cr#dSom9852H(M>24|93WSqy3-0UJ6itCdmIiPsA&y}ax&3#VBOmPz-{NR? zVYH>;zPtp;ngUIM8X|gOD;DO}+%BD({Bd1FKw4IOrJaFUF5=&}-W-@y>q^8pK^SoiWXRzs!OI^s)df$Q+3bI)gkX1xNTiu0psMh$~YYHo>)s^!O$a&L#(MRM+3>q+QY-$9Zm`2 zR~l|s>wqJCC1IPpcM0lU7NqbLi!sjYD|_WaUXIx9Uauldt|iRx(EO;c?_ZlX5QNUN zzGw(@h6ZVG9GO5rm#gv>@i8}tolatikiXa${8jVEYAiiV_s-2WPT$Ax?=J*G+yy!R zsIEy(#zNe3pbUCaz2Px!zb;$9fI56|CnkR$2RxQ0RqQoFg{&*D6;}|kQEsCed`~&^AS#_ zJ0rzWN8ppDluGG?3xLiW%;6dPwcDFVAZp{FKM`Ms4Jtjx?B2!oDx^vs zt)(F604R9cjxup;oes{Wb+YeH-c0A-7n9yd!AQc%1RuUVA}a33zL%fk6Qa+Xr#b7O z$-@hf{f=U{QDuxNCJ^Va#v`btXGV3}n98dux1&a+Rqhga~8(RTFyE-zA;ohaEXFpaD_ zx-_VzsB*-T7cAmx;Fz=vO5fTOAO}&_H~A+%!{jYS6gvmY+gu}3CS1JUEK86lbe9K~ z@@>WWpzA|Tk&pJ~AWDXQ!v=7Pqvi% zPIZlq!SkiiAT&9g%kD`-M6}%N8Kv=Q`pdL%sGwpL&X|bKM(xV# zgH&W7;I3Mdyz93Hh$Ic^D;ST=0$zS*V(qvdd7$Ye0ZKQG?848ZZPzckTTVA!OvQcJ z`q$s1f>5zj$}ZQ@g&HLoxVEa+Yp2py#w)2!8KC=Qy23I7RgvijCR|!&iuPvoVmbgs zBiT{*&JgS)fak|CtRr94sy#Crx)<=ejgBk0pmruB)zV_pp@+c3OQTP$6ZXwD#SBVXt)si~v-kjkr+0fxh zm8WV;1CL9WRod{@GkPBIR;Q!3-U{eqJN2*AhVz4aKi1QiUqUX^Q+OM+h;wckQ0t2i zhI{S+ts9u@_;OasFsmR(D2gX!sSlW1a;R<8?ZcEjui-R)tj*wY>GAZc^&*=;2|~%d zAs$W!`WWd0m^a-;eIfSepHlXjTw`yOcWRD6JFgWN3Qb%xG&Zt1M~_ztWNM|7eVGMTk7s#hd;V?CJtYT#L`jvnZ-9dL-p2zKRql2U0dpVw`) z1b8b4)&4HYVLOqzpkdC59{T#omfO9p2|j;BvGNBUA5MZq4BRww3g*D_7?ZRl4nZkU zzlMG=@A_=!{a8m(8dd3fUXP@dNT2DHOocF5>(BtsY9KQZWdv-3#e$iaC|_3WO*v}|aCGwo$D zZ%h1LFG3>p2zS2$MOp-iasH&Oes6VE)L;t0kl?YEm7mbp=O62IPfcZPaT;#U2@Z;~ z90jc1wt*(l7T7dH0 zS(`S@^a3uwvE^a5>m8tqT74gmrhw7>_5%J#!Mz3%toy+N08~=`-xM6eKLsaa;%H_f zVe9N@C#3WrC{?Xt|j?j&B(Gg{Va`b<|n-=7qy0x=dN*` z43g&hu^_5MGJR{1SL$lxi+B1*xtnXX3 ze`KE6M>d_~Y*d3bj{(Guk)j6)QS(9`@ba`8T|)mQBl;*rJMkpg^I};d7m6NBi=qVP3s< z_4)a)&X|S~GkrssovOhMNQD6St@p+k$sXpF#8LB*+ING>bs~h zi&-8VFxU1!Jax2GsvvxlAoJ}xarh5U?Tqk+9H!M=@I|6}Y|avhrebFKP3ZqPojsRd zNp-}eNuLu8heNO#6E=mA7dVa>^-2)3F0V(TO1w-7`A!o;u!~-`avV0choF3RoaE(!3 z_m&TFP0ub709Kd7RNh>r8&e|I8`{DPL)QB`{0gM^n`!NwcLt25Pr)bJQO^lCeHn=< zh2!HInko^|zAb+ZQp~k68n$(}<=ZM5u@J>EDtt=ML^<0Yx;^H4^MX}=!&JQ(s9y`! zZE)3Xbk=Rqg)aXvsCV}>wRr>%_TAZYFtRtpR1Wxw@@^iJ_z#ldUPvq}!z;%2Qa%%f>@DH9hqkDdFB;FIT9)d@YxK)p| zPK~_kt4O=nAd8g2_-k+z$zykA_79>tzP_Kl=-pwqbX9u6FI)S=1};Efa~&k~uUeP) zfwC>H|A7V=TqO>IRlz--9E=Viaxn+IguGi(xJqDy%>R^9PXqqR8R#e0>-L6HH=Ju+ zQ~E~zLUO}7VB)pf`Acj{XasUAmWKS7xk(xiM)LC?m8^HP(c`-D{_mz55C^8D~IaxWTu`j4W^$MZrBAAj{ z(e=`PYW$?xtLq-~x1#B^*>q%glbzVmlG`=mFZGHGdbeQD0N9ojQCvFAbpEaZr<9v3 z($_w99JGeA^+!$x>dth!G$q0k7)r%rN3B`i?l2KL(};vHaAGr0YpwRE6Vb{VEX;L) zM`#8KR0&MPL!1c^#Y>dDUynY!h(3>hkrX7cFK0efNskPIK|*SAM(mYCG6Bd9UeIuhl`a$R*ceg@d@(^ zW$Pe8VpB%@qhBZ<)7S)O8=J@5L9(9{R^k-%8LO%0Q}zJu_`3+x-wr~<;Ui|GOQ|g8 z+ARn-30iv_C|OmdFTSgUrj5IP4uY^?DiF1=SDl4)=f=wPxN?5S#15`#NOCAQSFS%6 zKQ`IcW<8nb7qp}vGb*l&PGGfD+duj^g0FtZAi}6fA==cF*rE)OBJu(72895$M8g|t zckNV!K*M4B6kGMocL?$A(15?%^<}biH4>N_s|@+t8JTEd;C_LI3IReC=i!j~0szA^ zVKr^6t0?KnE{p-Qo1;VwN-LXW%7C|}u$S}S8NCC^*&G{eM?xLy?U2zr@L~qposi;WokLcsk zG@yPFHKBw>nvRffsdiHOEZbiJxKRhiMJ0;VFBIr-=s$h^<^aPbh|b~rrfOFXk`oW4 zJYWk0l#wnbU0j+jvTsv+EP>Kq0^`pa<0eZPkJ z;~^#ob$3&Bu=w?ZlKm<%2SiJ@oEOvj97XSnrL4_l{T+$LP)a;oSQ%2q2Gu8qIPyzi z+{js38ui3&;o2Gp6HW8RJZ1=_pu2P+718o&HCp%9RX)C4Z|<2RpX-}!A;`!>rw9ZT zbySLgiQH&kf8`Scpb%VAru=lrkZ{c}@57czoI)@bl>@jNZI0hn>s2Hk+ajUxYtwmv zw)w?oJ6Wl~2$2@_X8QpZnH8 zdpc3=hObU@Rq7>*%a1XnDZL2wp*Xlt6};Im{QWHP04Bjrw&58f$4W4e@DPXO5~G*} zp=joQn0s0YDkhVi%*Uk{Gk;d)C~AALD!)c5dx8odEuVz!A`3<_j2(K1ACq4%pw|aH zq%x8oC_;WHuG+;LU6E^aEI&2Qi3`01EG%ZN?3yqi7L7*cV%a21FDVD?PPohzzjs=Z z>sYPAnWRXNlwBkNy|CSzx2hckjr|nr(!Y5j!sQmE3n7t;Ljkur6CAi^E<;?IFzg`4 zHWimvW0lxUnQ`&COP-Y`eCn8$;|#{#D*MbCk!P6RhKb_H0y~dV+A#AqH<7XITz9TE zHIc&3lJR3>zOeXhZ;s-(#CPoJXs!}bWIErHk*kx0=D$zH%Tcl1@9F9M<`R;(;G^O0 z4}no1T2E3hHq7ReWRdwbx-y}8Zg^RVuWZ8#{W{0r?g?58uK3LF>s0~*hn==FplgIt@Hk+SMRWf&qoW+O zX1hl1>w;O2xu@yk8~u~4jpBRbG1#J_YYLZXI8kOs%1OU>lTnV45|O|1Fy@ub0w3vY zyw~y~o4Dst8GE8gZT3hfwaqy+ZX=OWLL!czlbo&?nHSj>k(~F|@|-1M=E%IWWqoRa z9%2GJrV(ekx{p-t)DVAxBb>9xkU%>g+lJEvll1t#Ozx*(=1W4#nE+V6HNMI=%EBf?I}hFc!TnL(qWZRZi-2S&Bq#nM!1FHi z@o0oXkwSqFfk1!#f2@6bt$Vl4TyHtMBYh%nytgt_#GS%j>UWLgAPd&s*0DPstbd2U zKPz5>Q$xYgKt8jc?hXI`CH3qeX=}%IEFMwNG1SH`#Ks}Sz7o71^EbZSUJ-^jtfF_F zZRY{J^1}glTLarnI3s3KV*-v4aCTu1oV1U2bJ@AIZeE;N8+T{2VA{c!i_X{d(6D9P zK;FgneS6ps90;7!G!?fU+fNycH;Fd@H4xK`CDxXmW1fq$i;C?;PhHDs>oxqHZz&9= z!-*k}+LL*R(cws0OG5V~V67mgq$i>;<{@b&Vrgf2m%q+msw_9)FtEtBsA5$$6f)ds zZu)~m7Q=$Wwf;AuB{yX!ea6zjG5ZZ>WpgamnqjN+o|R7N_AtUpueEN zzhK~J;A!M(>0&9NKjFatAYdneTLHHXX7;2L_EXSlhrnI$2^(!pi;|RD}Ewt0Yz?Sw`kaCT)y%m*cDCW_HWU_zJ3q)aUj~OnJ=8z3M*AesnvQ z&TD7J@N_|Fft6cLv&5!{sYl0+iwob`P3C3i``O9dz+B&<|IYbNKADhrqj%tAAg~kg zcjI?!?hdX7I>ui{MsB_>wrw(<1j!u9p~!^_P-gLb;tNocouGt+P&%3MsrGur( zSh~}cQ(m9u| zYtnpUN2!yCaImBJ2a}@Yy6DyVKEgXC^8x5l<-3?_*h2=PMPqI@PaMUWu@g7Cysl@lD&so&P z$4ZmEMd)GU*cifEQ-Fo`Tz|b>bgsESArC$!pP`#nrk?;`LOO^V5h>YeV~r99T<(ww zR+x4+2B}GR8yzzOxiR`r^UVjDXTLRL)sfgqWYj8zXTE2STZQ^Ixncp`o+UsBE!h2W$DJzd&6HQEK@b#9ES6vt{n6*ZZKtTXTr-RRle* zB`mgRS_6X+2;^28I>&Wa86x4{A~u(X_pAIo?HpinZI%hAl&?#rP~UdcE5wZ|!I#Aw zKH^9iTGYpJw~+Wo_HQ%EE)Lj0Gl0IXZeWi3=d^C@Q@^(RHrs-*U)^zjDA|a*!7e$Y z)cujBJZSu-_4$F14fe$+Pto)BnHff}uahavF$9?Y5yOZKIg&2%{go51SgY)a9p(H+ zC9C}_WP_z&#k1BhL*57Shd)r4U?CQshCi|WqCKccM!np@IIbJxOS@xxqM7m`1`t!XHt9eBVt^?Fo&3FalnT3?OQ7gUHJNl@&J<>pvW!Qz z%Z04y?lHBS#{@MId}$j1ZdY))k2o%xkhHq~BDqWl#%h~AAr{Ba8!JKOq5h>@$b@D4 z1_mko7BNs0O?_7l1{?t6qcvc|M*8ZARu6@-sL0`yDOpX7IpZv=r_6g?F2kKsv*FBs zsHSLVf@Bv>SQv^cA|+tZVyNe=ggQMtTE%|UtKxj%Q4LjE9>sRpH>(}-M=?rt{_y9d z%TI--=tHVrMpX|D{-T#u zxwf?cFn_2ACn1R!Of$YY7PhYcs#RDta6nsrBHeN;BZs{f*sM*0d>iq$CsnuW(N(Pu zrD{skj}Mrf(Ktd2EVQMZ_v~qULQ*2?T$wzts zkVg&nAIiA*Wh65`+b?%#QTn|aYse!@vT+7fNQA0G=GC|idsQhnWxZMIDLO*H{E95I zv>r>L3JOQ|Xf&;o)|9VmuKM@JxzLV2g=lx0`YqsnOomKlS=q-yT@VTm-#F*2GKb!u z?IauZSw9N~0!_w_giCokMk9Z>%T{!Qf(2$g=){8>2FK_?BjqHhwh5ix$Fa$XFNH5E zcQizS31;P(w+F?+KNLhUGKF$9I1;2rJ0qZp1e3mu3KrK$Yk{R((;mysobomIyXw%% zD}@*Tx;ib~$KQ9BQZZ?q*)5)Ip9m`MPgeJNX(=_HoB^>=M-#~#Mcy|{IntDZx@<7Y zgP&Z^LIljLdAAC;kG4PF!RcF6Rx)!YYo(oFSQ!JH zeIyw+sZ!_KnNw=}vdx77(MhH=Kal?(B_yAQzE}X<2GeZpZCL$!z+X?g@15aQkei2x z&PX+cW1Xn&9e6!Fvz;5A=_MpwlL#vN`BgTDf~njf58N?_Z3yh);GBl10$`N)K1&H+ z^59Cm>8foh@7{XCW?$~35#zLE=rn0;?(Wus6#})BFF=j7BW8HCB&M0Yq4ck-qZ4_Z zSui5gUx&kJ9px+)@EG1iSnzI9`T>0npc`-nj7;U2I@W!mKO+Fy;E~hvG$OeAB$4}M zj0L=P)%5uM-UMlIQmtn71Z?PeOExM4Vpc=#{|JvAA3PMuk7lGh_|T3YS@$L+FsO2n z5c%(8Win(jwjN_Y$E@$tU?1GMXcDuy>QFW-j>!O(^kRzfn}PF z){R-u;PFycPYCoZCO{}U4n`-OV=w0<6EIbf@DCk47?IYYz#7}h8XEwX3T}&bm*L9% z>Lyzmg`~)mm~JT6xqE4L)TxOG{NR?E5k4o6<7Rwd_Iuk!vbPS4C)5qbGcD22Y#0Pc z*$Cn1$PMn<6M-*#3Ht$ACJo#XjO*iWcO$G*u4<{_CzaDuo1l+IT*ESZETg)p}>?dX*UI#&dm~%I+;zy_&4Qd<6=a9t6hQMi9 zD>qoNu*?s_57x^=_n7$Z8CJ*`6UT%u#t{Q#o(qq)-%Q`TAkv=3q|Gny6R@Vx7tDZ| z0Ji4&RA9lxu$&3VK;RFi;RcP|+BQn4f2`AUdgwrBT|0O<*P9D~F)<{9gt4EFLW`az zLqKqgLUf_w+O|MdyEXugrMYk@n>H@8HK9*#9!>%bS`hjgoyzrPjYSHuyPDbD^}h)3 z`isRqW|XE?Nu29(+D2y+S_^SP+#qoqGS}LVZBsrPP{oxWCJHr{z5)z-1_=5@H?~4f z{eh~X0tkS%@jCJ~mkjQ215Fkf92}TyPy>S?8`89_9Dig>Aee~^wiH$zXl6H&(T`#w z7!80-F5ICXPc=#qS*|4xa|XgVV>+M34e%*ZUXAT1dV=dhO!Uj*dN@9PV*~Z4E{|7D z02e-Wnt@m7Roi2_<&Rd$96uCR&Y<9FWV`G@wmT}ZFE&pMXpcVNhg4!BMC=62jUABk zIpvw0pJ#+VZxC|PpW89SG#;Zx*M{M7{4Lh_Q%vwybZ8IAJXI{gJ1zOb)Hc#6@wZj; z&LQ54L#0B&QzRLF{_If>s61LSc@wB&vfz9LfbNWNW)dt`X8#*tgyOM|#;gt|=wuAx zDP%wba03$vV6m1)4q!_dehMg%GJaP|MIaV#?jkd8KB8lUW<#(&nz9H|Gm554JemRT zv|_j!E$rPx%!%jn@Mz&kZ??yVZ=u(7Y|*Q!F6r7%ZU;tXd4LTjsc)w8omiW!^rAZ9 z{Mx#OR(Y-BFwXsSK^?9qtvuAB0MIcUYA6B;s2~nN%_+fQ6jC!Ek&*%Ut`R~dYQ+N@ zEM`;#S-x8K{Ar!t*0c$Q_w?(pju*lvFg_VTy6<(`xo*w-Ke%E$L43CC+&a$a!KaQyI;F@Pa@U=>j{_^xF^Ej*Y2@i0~*dVUJH@Rn@L4i9M zn8zFpRSaK0;k%gAtVXyJ!{W`lluA3J!F1v{N5Zym!ji_Aw9xp!{_GnZ+TQPmv%*lh3X?%ySArPzGijYP}NxE+kDW&vYTnt%Ab!(w7lwa&Cxxg&~U!q^>@wxm&` zDxud2q7i@7P6eiEe9#!$Pa%ufcBpfbqD7U8rgCjVsn-pmDWqa3HBX;_5v7)CFYsef zHD?`sWHFlG794lMTvN!YAB(Bla;<#cfW)u7 z8=?wBN;%!18pG>$t4xC#vIK08$dSC+DeJ8$C>1NMUwwco>ylk{ z;`F%AmE|Gp0=T{`Qz#nfWCr74L*$|&N{N9a?NPTT|KdsYoBB2k^BLY!zrr?tI^?cX zYJjq4pv@bu&!=b>6w&Je_(I5H_2M!56yY2e^2sEjKA7BvM#B>1!@8|X-;Ed%NqC>=5R z%yt-~yI!FUpr4BUYhqNmm8rYy?n&*8)wsZi%tdMt3fGM5ET^@8$~y+D_9$%YnRN9@ z8~L)Av~q%OF|GZT`I@)g4~Z7uobk<4B_XR&8?Hi{+_IdJ`y2n}``nkLRokz)9}WTZ zMuvhV{fK>crKFMe$X!Y)d{joP6vUbmQoh8C>=<`tD614lk+Zm6dzYcWy}%&~FK_Sl z!gq{eovM9LsbNSdPsu?$BNMlcuc_q>IKQtU84u2rKxonjIp{K?kg*k(HtJ&mpvoqz z=iC3RRh^tx&0^<1mBM0>R+D%%bj6a4>BDQt((mL=OCR7Igc%U=X)80F-!M6JJ3bSl zwsDeuW$s0t(<(g-EA|OokTA}CYCDVeIGLEGhFrgN)-))JfNyhqq%s^9fz!P4eD!Ca zWOHBP!$*R?1tQUNdc$IEO(q+^katOP`Ob*#{bh@VGAbe%L@MFJD_^WfEEX>c#T%=J z1v)Z(V}n5q$>tOT-8n{ojw3+elmRT82i+OYVD6n1hSQUw41y~{@D+pHIW}*OCqVF( z0cx9v+!;Q9?wb_3!&9Mb&+qR+LbVdNeY*sRI)+XWYq>(|2kRsfV!G(0al+Q96x!mH zU2KCSOd^ZTFvtk1`=67I5|k@S;e^z3=to2uGw}f>YKjS1(%?^3lF~A5D?TN60@g0T ziUuIlJE+T(j)Kb+MIoG8+3q9{Nh$0INCc%iV8crw|E=pj^_{NNE*@R2S}XI4G8($YEBPD& zBG#78`rztHUk6p{sq*I#J-ZLe>oE>hZ~I}zsh6c?09UU75s}W;)?;?7)MCyPVKw_z z+%h2>%!!eNy0QU0>O=w=<-e^T`WSz#nD()9+C-7mG=}9ppbytysgghJ!*rJ5g5);H5mxeQHobhvShxpgbG zDHJsVJUO5gl6nchR_{kribR*zv7y`u|u3iru*|2Z} z_WzFXMi5xtFM7SRm*H~0{?)~igL9zc>2|4wc^Ug)oyAE}xj!)ykmm>p4VF%otU;U1 zY_`Qq*l(FL2?!+`Ow7rII?KmdKDA7#jltzkRWN&C>)!K78w3}4KNKAumm%c|Qxb&ci0lj2S%?;zw{@vVAubhr)N z@gD^)loPWOv#jOmZ0RxmJ`PPSmMa>R3#sMp>3DuxDVP)yP?vuccG?Z>$=J_`HzN{S z6hhTSbx?5_KR9whxg>TYSsq-5T!su(3QS&@nDNYJC}!Ax?cB6$U5#FemW~C%g|bGs z3**K7K5gdHvTFjvgNorqLeay;Q$Tk(|8MO5LyT@;+%D`^t+H*~wr$(CZQHhO+pbz= z+pbz=TVK6H!cZ1ZMgq;}Ze$o{kajbVe)!PC*EyEAb)BeOwO*^e z$HZ$yf21No32X+>etR#IP}ZVj-tfw7dS?yAP!mN+HSM2!L&#yc&K(oXUp>Xq;xtWC8E$5p%drJsGqKuzSggD*QO_n zY}V;+)UcMg?aTC|3lD1a_Zyot1ZEu@sibP!V=^|k6MZWqs~2(9>X;L(>r7v|pW{Db zvHp(xTS-w9(6V$SJ)~Xt8V8$iO|B)|=OOD=W3@Maj-l*%s*9R-#Rkj8O1{x==t;;2 z@uzmyMJ*`_i=S=)_%weM;+{1pr3GyAe@;O+E9I=L%{NWU8%!!Ze?B9NjFG%uTBw4! zFwlKjHRBQ(v|MD11|B^tOol}$!~0yS4s72ajk7!Lc1%~V%5=nIYWAT^eN?t$Br1m* z@NbY?%VN|9Ol4!56bm%ZUDEm|xIPt$OhAp6q8d6oo4zdQ=>gq`}!(T;)in)p(T~w_+%_rKSFim#L~e$O5mkIe~;# z$fDi5eC_OF9V>ZLn+88VjSgr-VR7KXwk2qXwGdI85?lehHp*Wdedbltx9wnY)I*|E z2*9FuYftv5yWhwop?#OFc9&vE!O= zb+R8-oqt?84YV>{WiFhb^D>LCUK(y8lc$jH{Gl~7&BU2V2k znFuqbOpf9>8u{~v-SRH-uav=$(<`jA35krSeH0c&#Itl`>r3U8@0pd zw2BC++~pp{agi^O1biJ_i)qsMa=&=NQH$!HJ+G8@IdO|-@8eo!(Q@5S&G6aM zx$h-%pY4L{x#zyX!7`%!_E})_d%ql=RBs}!zXb0=4q`SMSqKP{dFig2C8Z2>eu|8N zw#RCV=$3A#X5@D9%veB>G|CGXZiwqVc4_oOd{9(Ove;)9dVgI_mdaW5X?8=_#t29` z;V{Z%!71O{vexkA>@7J8)hk%$J3M3Ad?5D!ijyg%V0Qt%+HmRXXhXvs z=i(g2Qrw*lSNX#3;7UMIA=C4=->s*9yL1gWrxn&cofR_$k{>WzyN$b^Ws>y!G)!m5 z!2J|`;^11~CSHel9PNvA=o+8_i`Gf=rR()s zFK`t;>1`JlCFo&Hh$XE9lymcVPbHX!GZi3~iPCN{o+oiEORo2uP%dsPYH&$`{Ia)3MEBytN~yW_qLn ziGO1=VJ3f=>Du?^tn#y0ftwA7GV_EkwicVzo`;B!ScOe&62K_PD@35p(s}18mcz}L zHdN=;Ge2&*s2a3qIv{2M?RmcaUz9Wm^C0cw$OMN7>}f?lmcHJSe!P3o z7)94&2xXzWLAk4u@S>Q?>o27D#a@DI84+?`ofGlQge#T{ERZ=AfozmbD#Te;x?Nw3 z5zn^G6ok&F4KWS(m=1${63OqQ&DR*?NPej7Q!FjH0p7NLncNmNeQ4lM%kia%Ba|mr`VqV=teo8#~4)7|$!K%QWEv0Psi9u4Tjb7Dr#u#klzno%y$# z47Wjc_lLo+q?aP`uC?@s1yg&KB!r#P{!#HEkS4mUWqOf18?Q$v!Upz;N@E2(UVZC- zd(i}&knAAc|GsYlRXuMO-K)s5vB*|&qcBR6H#0R|-1;KS zW;sIFKTA;-#_il+DrT*1cRE)V$2HlE#LBX<<8XP>3Nw}TYsbtHvTK^9Pws}EC|lFZ zWSJJC^|hJ{m|rymHBu4yXa&#j?n@!Z1x%NFlg;);ym8gQ)ngumuOmC$h^4v2nbL?a z&(>0`65h^_dWg;*$&sLLN^wC-j|EF?>fr-D`1}>^OMgrbqAiG!ybFm{93kJD@Ajvk zQrKK!$XoMfZBbGAAu@I3tx7s3yV{osPmT4`uFhgpieGJFaOtY5cFUvy?uN|sT0@vp z;RuJ44qKI;h!uc$+iG~J_#r3GZ&~27RhV`+>up3pUE0W}LU;HTQXitaR=y&5lLA+w zEw9`h+@I_uCOT_!oxxU;Ogj0h_|kSMYqnU$6sELm-fvf<_ww4K5s6wJuq$*zvarQ5 zR=!Let*=Ty%F=R0ymE4=1+aGQ$qlwj5?&?b6zS$DG-pt2i`G9hE`qCmGF;denTuM| zq3GAORb(_}?|4Uyp8c_1UG5gPi_A@`zJs{B!R4pb0Uop#R2UkrW&6%al2eVKtfATM6f>tS$O~Wur%?2A(f6LY2aZ zM&{nK+UvrQF8`4QXpoZxR{?kS8{ePK8QPsjbKFLv^|!_oy6e~skB%d_H&b#3)r0T> zDQWxr&)!xRv}m%~mG&-~q+W62n4;qjw3F{^acXlVUHD1$h5MbZ!!t1|Z9Yw^=soTW zN=YVKyrV(S!JQ8+iJjve^%;h<>yx%<)3J}Kvc+Abhyrrj14-V&NEh1 zo)sO^mCar2R*j?fad;`*JrI7Gt?ep+gJe74To-%C2V5DD#<(Uk9zfMZe>%LIj2dLq zqZ^po4XZvc8E_&tXTk#`Q*lJJ&rA!kzu+~}=?Z6#lF*XK@AEqNIT3agv*eM2h~~Mi z-0{8hzB!mrh;T;wdw-!aU?ntPRRtTN2hl;)FXo=V&RlD7l&09Bhrqm4xM`tC&PXLCG1h9sKQyS*F7{ZK`{}E1d41s)E z3=U7XYeS@eAHpg0$Y=ijurj%`J}H>5K6pVe)s)T_4}6^j|Aw4EMP8#fFbhIxB1x_W zt($%*Qm_}A@6}qhtUxd0wrP~ z2H~q6pky|pkFx*QPV&avE$0lD9APih6Go6ea=GNNRr_278sd=PTe=Ws+EHZ}g7Id| z7|P>mHYmtCm#NbGsV)79AGOf^btI^%Cp_QXT{Y3MHvE%cSXH6IT z-CRn?yX<0vHOHl?R70u|Mx#2BI(l!iX3I+7sZr(pelJA3Ta;z zs6PPN^_euFTTYS4qO<*H7KAcvlx;R5qA0bcs1_&OZ#&Ho{Y7W?$EE~n)&I6Q*mR^p zKiV5OmPt|NP8a=YT*bkjxkzX`QNiV;g2VU41y)jjdNyQXW~xh^33<*U8;BPW2?ra zofAIq%WJ1p$=6@2#j)Olt&K8Z+!I7697Mp|Y=o$W2$e}Ek)wJVxJ2{;{83+)D!oJD ze@SHa1aOW=fL;m*lIs;gjDqxag8hKA6Z=oxjp-uP`-#`>NI7xwE0f_RQ0OTwlHFA~6T>{%{C57!a<+UDxef9sr})!5Z#Jk=cWqajEd zJ(q;{Od*RM_O=>Tb{}^e{sP+w(e0&2yGBz#$1S{&@r9=Ga{I!GJKGF z@UEOg1VBRUetCB;&5Hd5vk4Fq;d-_{d7^9K7;dx9m318;Xccqdd3pi=s8Y^1!cgL+9}$iM!>B0dWXG%iS*_Dmx_Zf?fekMGSIq7vK(u>a8iT1zX+w^+M`` zP#i({pmsS`@+G%WXSy6q2OJ=0kkyxixEhiFqaieDE=&R;oCXw=sOyxx6?~wMP5!cq zUk%WD=V?8%YPK8T(pSr+iluunkg$G>0n%=FwtdY4`ELL|pHC7U2zKDm2jIf=r7jaG zd%w*VIcme8iz*511_taW_o(U*EaXA~o|QOx?0n!>s`1e@V2ER}^j6E6yEh<|L=wV- z1^*|nIUOjTDmP~no@>Hh&XG8A82;Z|H1p&q?gL9wZq)KkLEsl4(8vrMPsVOKP^Jt- zVOWNe9xW4OY47E2yQni3GRnzGoS}^QaLcNvWiWglkYcv@tFgf8;}>a*pZ%>;AbCiP zLcn}L&}>e!9wr!icY0VGh(pBSg(P9pZzZa77m!MkajV+ZDa~!>@+%;A$-3FcX@ex- z8m&dK7g$q0&ravADP3XP*(feO0pdPF1@i)4c1fC~#;lN!cXkxob4jbw^{8-ZeJN(N z7cs7N6ab?1U{F|#w(_a~iIq9f?)v8%fc6xzHOihljv+MzIq+0j5B&qYNdrAQL`aoth$2LZu5TF8M2i{B-T>TSA|R0(is{3?Z?@k z0I{g#iUPlCx0#U0D9jNY{-AO1(*xnmgVg#g(BrI=tz0NAK zwL23JGnwa?$NpQh*!9EiY~Bt+YF6*KMf8Wu)rzUuCwx*N9g*jlB8XGFI0vl=_W5w2 zwnrZC&(}Ztn^-W>PK6+=J^1sEVMl~(il=d1+L^F0cm?u}RW&$&Bw=8(JtY*VGtQ_7 z(?r^@sPcMOX6OA@2YjL#2Nhj^R+t;gOftYlGgoQmGo;N_LERRFT^G;C@~HmB1+_Hp z(D$3I7iC|*_Rk&)(AeD!C8R#ME={M?!#M~E8(aA+2!~Ow`!Mph8?vLL02-XVxK-C# z-8#L@Y>M^%mv8m7cL$xB(Gd9(I6S^@UAeh6G3f$8ZfEV|b2PL!DLPb@yM**{Vv`96 z5^C)bY&1&GVPjpX0|os%02`P9n!ud&U__4Yly%?VG!Z0$83pw@H@FpjzchCNv5>1H z#0plwPj?6t4%8!H{q|wXQ>xn4WSt$fCz-K8ny&X%jn{ii0Kd2V0T%X-5A3J`C(~fVkT$Zf#6#bXFUTd*8l)!C=QtFckyrCq&Zzn4xyy`X_i$zq-Lvw2utl*LilujYPu zf26fnV2KhzPn0-x=~67CX&zoM)~wh-0&4(PTOdQ3n;BUuoy7rhm+ynR*X-k=ssj1Z zD6sC~!$RaCAudAgIVh>F?XR-tg=;s)b4|=wHn*#?pG>aqR$4OF$m-;WRZE|3r_QP8 zs~t~{ot-W7Zxl%l?Z?MJ&`KpcIO4mf*#@)F3~ZrfSLUv1UCMnE$6v<046AG`iDKH@ z39A&v-z-_{OYmVqlBvDz?RIDCGJV_8AR~ar$=1QlvY_{a>%tn}$bBoEX5N5foI_W% zl}bUO!fhXtiZmI|B`-?dJ>JX|+}vEBAkbKHU{NLOI%-x*D^jJ_vFaQYhQ@$TMBIkFc1 z$-kvj{1;6{dVkW~rcHL3t-}Dh|SPbe2bSiNn`Ms}&Ht zHz253?(iE&vJJr8Ow*{QVflTRDk{Of=59VJa$LQa~Ja`96DjW1+IP-*=iN8V61ha&(s+8F}rphssv5PY>v+UCl$X#Vp zcPeEywum%8#`k%j0%S!3kKI)(;bT`98y8efiavoMpfFddfTgXO8_5&`cvZL)ANG#4 zZ$gEH!lBaS=(V(a1xNC8vZ`7t=*|KL&ocXuT{OUVi9`x!F;F<=(&wGn*TE4E>F5m@J*84Ux@o>d5b^v*pmY>I%GO!Y}$Jg{X@1?Mt*iYW;Z|E zjCxa_&Tn1}4MAP`IQ>W(=XQ$^0ss&kPJyrU6r-06Wzf~r9p4RUXBg{RBsk=6=;YMw zmIaH5oQ}VVlKnRVF^Wms_6)JI2mNE;&#yO0v|S>hR9LT(*G<5r%N#&3@#4@AR z@OaS7PdW>3rD((6N_Z+hpv~v+WM|8zinlzA!BDjPxrhelSQ23{rW&a-eC?ur?i5qRJIj@7$NCc;6Jd4E$ z+srrg&LSNbzii=G2$YE=&60tp6FLNpsdE@j-B%`d&Q$fC;2!e%$2HRGK$=?1&6ZI#-l+{wN>Ok`Z1YE#@#W-S* zOahTtc>poDBx$N5QDjY9GJ`!0SvFDHqp`2 z?L=>)R15r_S=+JrNa;p2Jt9@Qes7u$x(k`HkG#;Rq$y#D(}^;wR$NL zlv_~(B-xzr+AEIrKYs^oPC782^KSGdpX(`cV9Yhfk+DOsItT4BTVBH!8orMTSDBLC zVY)pN0?1~Gh3?YIViJRfDKe;)J3sy5M`coNLqqs zjQ5XMTdfksts42m0({4MqtP~#NrvV6c8?N&V$oE8TG(grNsN{9KEB*6w3%m7-W7;G z@O&NYAyy6{QgbJ;mS+`YB^*jkU+`To%}Je+7#}U>WNRlF*ef*u5hd{6mcF%ue#S0J zXPr?xV^r=40%5DFNY|cJ>^i6`|46eG+E+4~yBT}Kg66R50Ta`#3(}y1+D6NazYN|# zX`e3}lXx*(E3az3e-h8Mp*?ALx!I1+tQvQmOw7PU#?e4Lv5y|+)?N2lrthW8jHOmpz0{ek=$+Hn47M;j4Ab)4@Rb2z7~Q8tCM8>; z_&A%`6EK@JNZB|=NJ3h5e-1-WOM@s$B*7}L!8t6tZzQ%KE4Qwvz z`3X~Gi?YkVlnD5=qlKaJm)ZUpRkN--qOtM5-e2q`_9zZ6ENlww@t`!yYYc%#N~Yw_ z9Ho;56_D#inB$x2O9EhTfT1(y^QUQJh3LmB#Q?+LbEJ6-=cCHxV`d%FQckwZm-4`Y z-g!zJ*KU}Fuo`0dCEQLD?%4(uP_uC-+3`S?JNd5z*_v`a1TsE+zB^*;4uGNto$3c5 zVyUw#K+@=*xa5dw065JP5d~EbstfUHNCM{@&t&4A1xc9|r(*zoaVuD`1O1b``%&pT z;N@&YNvzGp!k`EBp3`0v(_~IQB<2t>IGqzlR~YywI6xoUA5QWa=l0FFu=; z4pB^j+RJ&+twAtnbkWgrUKc_eV*hzQm4MOPo| z4^DAQr`)lkQJ(=pKB)^>$T$D`>rGvd2HNP$x;XS2$Az)H;1``DAm`I_Ay;Wdq#b+}D4K0NWR)D=yL^v>pmS|Mduur+Jfh|C&!m+cx zQu);g`7MC?c=AgjhQ_cj8NBo>Cy7VL!S=tf%+Si<_m_MmztgR zVlZj0Ao=8CM0CBGTsAq}_mAFY_IH-qt{Us2`?gUaxo>mrI+^??p(8`M+dveK;&+4N zY5vgqaX~Wb%c(}he4eNnWTYQN=URxOzPU0pX%SxP%D3YKXv^KJ&@U81F{~{l%uT>i z_8+1B$+qxTVsNjt7T4I&fdS#&U}eoi`lGsiZH}|(*sybQXuZ4f{zYY41FqqbU*)ro zL-WDqT*tN2hW#?PObfhgoV?q0?WoknrM)X_rJN?Iq!tucDhFa+;*a3u9l4Fz>YDKz#Qf#BS0oz6Q_TIxF5~NXB?5$mu zH-Sqs#Q;9;X8gK(lOl@tq}=}NpQY($+}4hxgUQ3ua@-`Rmg-qWemmVxiltZ=XZPTy zF&i_iYVIl*VaAdt8)pYSMoXa$_v?r8m>o|Zb-*{6U*t%6f#R@P(#O2;n6ZuUzS=-w zEB;2#mg;Bm!VW<-ls`Y~%2$Pw@BG#9-;S#$BR=Y+#K`B>zL{Z{s{6Mjl) zyLiY&EA7ikGn0tm-4W0bulA1~9C%a$PNME2#QKUB0VUo{G^nu7V=Z)K%jVscw5qXt znB3GcSZtrEmy3ha8suN!_vHR$1IkdMN3l52QxL7aWD5knM|-LHUXI<`SMAgc0hBFAZ&Y5tDZuE`F@3et_-x#iQu-V1K80HI5H9T~<58T-|9-BM0 zVQ;Fwh>ewF}^l)eMjR97shbFaXnyKz+9jq3?ZmOr9+(u$b7D&|tCA=10|k_1pJ zjrFIbDVmipu0w9OiTo?A4?I{_aL@);!)QAw$FAbOoC@M(iOOz{$Wx@&~P z0DIG7cpwsa#XQkW2m$US1Banb{Rd3Bbnr2T7r#1b6@WJ0X^-a&h$dP9$*Z&e@o5cy zEJxu`pu4DO5uXf}XaLVALd_A^4=1lmiw;_0pX{`q=yY^FB|z>9u1F)WcLiscoOB?M!F=!7o)18{(nk}ou1|6!IDcY`+0%OjbdOlSkFKQ!vDrH}D+%lf11 zUdq^_p(UkiLqRSrn6+IoL6X$RDi7=0~L@2&SCj}hl-j#@Vt?zojPa;Ko?gY2C5_T((IB30ft8H=QqS}M33*PLEa z{l^g6jnZZerz5BunP1Lc7N?zhagcJfoRy3!oqLDJRgjAZL}ddz**atw*Poyfv&!nT zw;F!Y3zdsKHN54m7RF0$Xj~#BbRMH)NuXW=`{!ljDL#>L=p1Yk%|y^|nr)7disw`` zo~92*_z2o4MDk;=(|7wBgFeTzn#rYM{{*Bw8asEBiXI`ovGjX~&q1^N+oJtz>}h49 zCXGqv0=7u+l>4+$Um`4BA$%-+sMp8JRR^OA=N+O->?OGS-ey2BLNvK zSjcQ)330x?(J>d4o>G;8J0usofJPy^!l4LGvRHpu3vqmhm7cBd2+u~dr*b<`!kO1Wb?%;J+iaLP?kVEpSbS@EEsL&Ab1k%oGGB*0nVK}OI=whI)k`NE!yCB&?Y}*J>D%r5_WgPOxXQY*)AjRudH!fB%ahCT zcKzO(TyLVKPWSV8s>JGY+h(H|2ZuOoZIGa)(BQG#DG3e^O-?=;iK;U;bDPOg+R{4dU^-&SSqj7)v0VOvB^!d>qeUqMOO_@;I4#fI`#N?fpEz z-hP3@_4d9$dT27!%jNsIzg#~}qwDMS{kmGNs-x5M^?11+-E7<4?S6ZHe_DOH@$-Iv zy!iUK$>aNZf4v)Bt?TRaetUX*n7!Hk@&0)JxLDQW^Zk7L{(7m?^Yi=ud^jAv+3oxJ z{&@Mh+4Y-D)!S_Q*`Lvjn%Xw6(CYy7_l`etmY8jGW1CVW^iRFCX8PRMb)ef1^ym z7Rpb`=Y&eo0n#HF4f~y1{m#3nR_D^pz_P%kuLO^hyGwL*aej2HhHOai)Sx3?V=OWf?7J#U zamSaKgq;}crWyrtL~ZUYp?suF-FbIt)Wj8+Tq_4d75f^T%o)|p}$}lzE(6TttvB( zs;^nNE}xvKPFSd-xLjFcF*B_yH7zPlYB@Fy>VLh^*yv7;%I_Yw`(6L%7sC60clm!l z&woD8e?HHDKF@zX&woD8e?HHDKF@zX&woD8e?HHDKF@zX&woD8e?HHDKF|N3`#cE$ z-(NERSDt+K?bj9t`n82=Ph_TiWRo`Gm5To{ErxYSQi_EOmobaIB3s#ZM7#yJyoePu zw#HBM2nUNI;=LP3PM|2v%$_#g96s=Q>+x~>`EhV^U^nveLGVFG1N!@v?5~`tYP($? zoD2>Ra{0yD%tF72W(jG}R*(&W5GI(Ln3&kw+Io6=dV6c*!#_Sf{c6n2Y-~;I)~Hb< z#*7%yqPDiQF``k?(Z%xQ1Ox;D0Rg$Wx!2d%#*7)_#F|=KSs5AockbA*VIzhN=+Vv1 z%(s3MuYBKLfWyMW$dK#mG;MW+g?x|nPOlD2i~4rYz*L_4Z>nMONEeoxl&>51R^-(t zo+)T<*%u9s%aSP7>g9pW!@)au=6a^acv`$^T@JsDKegoXv9h(cxw?HD)Bu3r@_W!MWdx_P z-Alm*buOlUyJosT)7^~Aulu>w(`oOE(9(`*4^`9_{^SODSL*o%)Mqs zZMp6DRN9vC4-=CHsMEJt9uZ_1K6dk+kN+cbJIOMd5fMH2cl%oI)8(ndt>ak932=#k z#jR?)i+sV$*YlfvO7}>)LNuz}g}-pReg|;ltBDPbUozfbXX;SI9O^npiT8{g zDw;*$pygzjo}&2UyM{`CH#j8p<1Bwi58kgyBN~1 zTy`jn)dR9d+^}!HuKJc5A|B#pNJE2FvQJukGNsXyM>po|8ng#G&^HIv-Z7^n*WOvM zJ?&#qiqyL;ybh`|z2=;VW`t23yrP@`k064fNV52;Ny0?UZTm6eyxX!QDF7)c^mO<* z33Py|9u0rt;kG}e2e>~Gwj97eatb5SVe*kgP_(jjX#qJpKJN{4s>znC3RPkGL9Z(Y zcwU@mqXNx{zS7yuRKm24<>@?|(%Tp=<>;b!@PJEnIl_h}s6(B`g(IG-#;49n4tf!C z)sVK_qO={+fOk{VX{bj%N6+&_Tk}?Dw&<)##WMH4^ox2zU=mJ$b!v`Rq162>x{$KK z+Bzno$!UG=%hl>LJY7_;`2#Hqe?UVy^2ei^9%K1UO@9Bm*lSPYavLY-?M_@RrQso97|1zKzmRb&3AbdZGL zaHX!#AkU_VJE*svVCaGrvlz1H-PY1NdC2mPkUs0*e(2CW_W|qWz}kQM&7uwgbRsLj znmfA|_wS+N!xzwdAqE35&Fj1zWw%8poZjlg?|9UbWusttvz|cCO@Ffq?r-ze7XOwp z!jPp6jX%W~GNl!t;QJ_H4$_QlukyM%;Acm!Qb8%%T(i5=FmASe_VY9*FD{UC}2BC#`9ijbkGz3ZY)x zJS`afovdA|`Cv{?rp30wci#L+e~tP_oAm4-Dv#f}d+Pmr;xiJMHTxipQh+Ihco%20 z?NTUK_&PI3FfOS0~RsKZWvphO7L z_IhkT74g~}WP0~+xqn>FhK|}!PK;{5UOkE;k$0UekaXMOk!7kP*d2Iz>Yod}i5e*x z%cz&8-4tV{t&Z|54MvrjGV3{pH4UYnMWveM=Jj6^QigAie+%=~O)7zn`u!Wnb)msd z`#B=5>`CFWw;ga&+8ql;Fw0#*Ud20XU}(xpW99Drq=^bA{q8`>C)=e8_6Bia*;BDx+sh<|9!*D_NO_u8#ElR@j5@suFXVj$V;PWnLRtLkv_Lg3`-uF-9EyHoMu<67}#LRAfL zwQZ9_wE)7VK=QqNwnKy76RP}CJvj-xN#vHes%UM)i(5tRTXJt(V`y%_a}a!8e?QYX zu2Xywl2l@5gMXH#qMnEE^L#|k#rawxu{5||k>mE1%2V={ zH%~(o8--Sr*+)NUE3=*YWy`VF$l-kWbeZtQSJJjIY?WpYV1MNIKSp9*6YinNFYaUf zyZ+D9B&gs2VE?;(!qVxtdgA|=vIywkN0sH(94&rFt^YF@i%~SNTcn5o!maq(r?2E> zX0dG}fJs#^w?Ie%tx|_SD9YMGESjR7DKYqb&skI)AY&J4baL~(*=|a@<61j|ESPUS zcTbAE@vH+uoi0}jtL ze^H(2y*d15bnQ)iI~ABovCg()pshfbMp85o(7C@4FDAgwIf$FNR7$`R%?!)FB%obg;XGni`G)(tx#Z&OuQrSB%4*`zoB@d2GEM6Dvo*13@PA4 z(nhGW6-8)|J-}gG%n%p1!{}urSw1u7&59wbcj*<*lQr#Y3$e$ z$vWa(Q4Fr)cS1;2dBjV19fJ0bk<0}A)+4%$0E z4`R4_le!!$1hmDoOdFafhEBY`K#Ac-AMP&eZV%T-$@(31P!&5oLELGtTDnIJqOQ&k zEZNVOvq(JP+oQ+rzNdJ%Y1h}yqCuArM+b4Aj4f|`TTK#dhBziwtmR_)cJKQ?1iJzk z#~s_c)r*z)W|E_B9t;efomL_OWUCO)M|s%Tj6VOC-9>G&YCkM7Zqp;4G~>Y_uhMb; za4-3$)mC7BzLl(Sgd8B4WWi7t$iBWII~cJn0;u5P@(mAaLsvkg-F-ClW)w$$RU4v@ zV<=%5TXanfW66KmqI3j=K9d3V%}!N>gTw-LdfFBC(^A{>Y^Xe4f* zt=N(LjMI?uI1Iata4WuIPLn!KdB)>1FFt(Q`MFRek>_DfuZbL9O7wCq@a|1;DB4Ho zL7wgtsmLk@KG8;~S2}pf6{&S;wfqS!ZjZL|Nf$_?CbZMM!{hDGpQKw29flHoVlAiA zT`QV5=Ms(WBC3(%)!Q$36cLzY10am=7<|L@g|z?a*@OD+*`wRa{_WW-OW4IV**uu>RAGSKO(zNfdu7JLvM!@N_ zw5UX|4ozP#f+PF%Q0@Y$GQE|nDi^SV8r)^`(>~IQ zwdIXHjZRkm^jodn(K=#Qt|ML$m85OBO_2o6TUX+PL}*@O{g&{Z5(5Wv#yy>vEauyM!NDL0)*t?;?mbQATvICTY_FP#DQW$(J^1sJ?vougoyQN`S+=rRY z+y59i*WbVZA@MB>a zbqg#(T*A7&alvy6!|KOVN|zHB1V!eTte%z`C_h8)^rwKiK1E~(cdJ~ch`C|zZa(n_ zRmq3W2sWhES4f_ld*peBu`KEDT}P~Qa=hPw=>LQGjwlfrPI)XB^EpuW8%sy+%|;># z@)<94W6;7HXI}U|&X@AF$T`+*-?+cbNqT!YlfZk=qCbYNdgXp5QB)D{=)&FdhIdMU z2z-Gg5W%paSp*AO;4Ku1W38pxy8-R{?nC{%cFy5r3G%95^>U?d`NvK#rbIp&%&m1s zOoiJB63%)bp}zaZqXkO{NKU>+XquMo^&j)IZ1<9~?#t4zgqo8#%T313vT>+7Bu=8{ zAU-@Le90W8UTu&+3jGG;ikW-yB#mZ``UPrZF1apsJLG|{)@Z)=$iqU@oyC%&nqR&x zYc7k`n>*l(BbT4oDMg5x{;=WXe9Wqg-g2#NwnUTeR;^K(pHo;4r$J)h-b;X-PlwSe zl`gT@UIHBJ!&w5ku_*(;e@81t_ysYxq| zWfcmsx)>2L5hdsTw}vm^FWw5k3vrr$Pox@P#gk$hW?ah0LA(|xnFoMCvKq(n0B8qW z$JbE`fOD|K2`)6wBId`8`RUQ)CGnf9z%Wo!lX&%PLrt&!*Et8rPzMIErqbO{gVVy< zApZpIapVK==~tW2Le}#rU{u9XJb4BrG25tH9S?{Tfk_`*$_bkOF;$lZGM1AJsy0GO zqXJX|Z2wo}KM`au8QP@+stk*UcAaup!2A_E;-RA90} zfIUkzPg;l32bRn$`JK@iWjug|Oo8xM>!|3Xi3BI>(PtKII#U%o#;ySNafcWy_Grm> zC%WYj$xqUkP7=);j(_Ci)y)U@P(DSP`k8vkR^G08m#rJ|keiRn%cmcGbze(2h~OWX z1savz`Vks~!N|e#iJ;s(8Mq0xw>G!4bF4jdW#Nn;E@eAl$731NG6c|rvoKonqI!AY z{vbe{)uH7(_od`w*reAUGha^ubT0$zhZ72TN)MG)^h6ftWYcfu)$GGGI%3(o{j4um zf3J&JX#lfMbl~-4s#(zAaq3CS5M*3-CWVKj5sn#~3a1xCFPHUU1Qe z6;kF#ijMeo`uwzyP(6BS(R}D-*IZegubC;vF-{%YTd7Rs@F;Xh-XlPv`vFWBoERuV zdNgD5sZ=pYC&fy!17}Kbmrw8rVHQVjAEq{%h^bnY)Ya}$u8^vKHy4~c43%O}ObWha zswjiRYJFO|8dGi~x9H*WZ#v_^jk+`K;0ZGJj4qASNAUS;U79-n8jvzJ6#tSLN?@N! ziA&*F!`9BHP#owdPD$n5zecgr1SNbRN*Fr|7?jUW5b#Rh-aQ+|0-YH0wpvxL<+qP}HPus?6 z+qP}nwr$(CZQJhueE-aixi5F(K4erqR7CBlsLZ`{?UiexFtW6JW|i336vMbOdw6r$ z;3OyxZjP6xxzfm5hN0aq1Okr%wlFb&%#R3GIV zU$ZHZYIfZlf##g>8Vf;<@J$`a)nTKRYJy*&WXyf~_{f0dV`bDP%r+(#It_~nT#4j& zd%`eVY|#6y3%cM;WsBFT{o=^|bx`=)f{nIDM{SKY2s8Ht|2s07@_Y5JTq59{+j+Zs z?f4|FijSsi_p7t-smvgardV|nDM!7{NirBuq9zn+41}$duCtVb#hF0VaPG6#!h+)6#y^TpiA+=wqsRX9> z;^cLG-GV;vkCX-9(;`nT4i27|a!Wl;k7`TS5GZB#`mw6}gg)XyjI&Qp;(%B;?KyxU zs;-iE=@_>kkHE$*a!JP(N^($wz|N7O;|>i4x8?Re0g(M$WLTaM*X-gVF&LRRdH)n! zsYC$K_F?Vh!v?kj8L<00DqzRN>kq#e>FBn7{j6`%Mn#f7+DO3hJ?2-uav~;Br&HT` z`CY>%!SH=#<&JBlfnI>UnHGyot4n^$`r=YcnYoo7$)^XqnA-B)L*OHgd{UcIzfE6_+XzCCTRW#VH z9oerqln}}@Nx*7=sAE@d0v+DaUz?bIPN3W|X4P;CB{Iwt3k(tda8&c^I z@jz=7JI&Ja*sK=J(ukW6Wl6MTaRk%<|MhQRWzEhKYf`ybwtP&1rq5Fdwx8-h2A$ z=Iyf!HRutlN`ybfp$Otk_RsvM1$v}79WsUVll)uMl#D3tQ zS2AA$Kv@_e>(SOa(9!>r53l>Z19eZ-iDbe0(X5C0qk|9Z2vk#ZjSt}=; zYejB{BD(spPL1G`I91-{`sSaD^RQ(3sVe=2rsffK^k%n(*IW^-sUN{ZVITR3?_(ap z;W#A6yimqMft_@gHI2-2Ve7H{;2e2e?2z>zG%4`^aD`c9T&%UvS&@G;{(N?CO7}bY zM0_XDny__u8EEp9gFKSKB@x#!hN5zd)%ng%+Qtaf2B{l)cniyXw_T)&+3|ZqPnF3M z{vwIZ?G6TW9lD&WhZXb%wo{{G1`;CD>*6kk&{?yyV^pM0oj;d|rlAkOfS=OPAP!(GRSb^QDAEyVD^Rv5ii8W2W(G3eK_iL(DJ=Jl1(i)5!OH^ zz-u9sM`VE82Mh56{ewo5563GxM*gO^K|^BuwEH(Heu5~W(X|a&k8O7(M4@<{e3ShK(^vLFh*hQw!@np*oV;lKhR2|?|8 zj*i9BvJo%>X^Cr#KN(D6cIElxV!ti+dwmvTrGGeldGwL>lCl~}9G%N_)d!w{hLh+sRxL`qLtmn%&9k zhQLx<`8oVf|DR?5<~ z(Qn4E{Fe&u8ljH(5U3)??1?tFx%3>Br<$`_g^)~JI`#Pd`Af_+t7$4olEFj1Ubo|y z1|=6tV9C~yhPm->y~Uil1{w0*k*LVVy=dKfG)&uxr0B+i!%&gCv(dTf4`fDyiE;-j z=VIG^c`$e7Q_9myzdidL5lbhktO1TwhjuNej;Un5_WX+#)`nK=%+o}@7H#e952eUz zkV?MN-Tw^82e+zFJ?;)p)1@`gb0%J#pD`Vl8_D&hF4QR)DE8bRf_|CbP`d#002AmF z%YPuEXUdx&Wus?z{|mq8X-*lC?&x-D+E%)t%Hc42rjWVoxj_Q z125k1N%kX_Hl6Y=7ZnrsZUtq|5vhJbN z=nDIxyDGX{Ww>)*y_~i-*nul%ikYkn?ZE?Fko(SS=LPW>n62kFSUBzUk9*%SfEgHT z2&ifl6|go0N7X4=>}B&K%r!M`G&OGV zN0ReQb!#he7!Mm=C<`#e%0m63xH2{cXcjyAZ?i_)yBs5?GYjcN%P=+n&f=?#v{x+5eDWBjV$+Etwj*<>lQ{vX!Bx~k5ffq*EpCEg zY9{xrfZft0^#>KyRcFo_Aw(Mts)cTs*0~1`4-m$fEyYWW@@Xw0qo$?tR{&CXJEfPQpKUSzZ{kWAjc9 zk|u}iS8fiXC&&&=?}uve{8Rm%{Z>|rm_yCX>Rv#f@i;*2bw5FhFeql8@zi>Z!fD2} zPMdwqg=j#qV~P_5pMOLl^J6 zX^51j5QW}q4QTz~3d}g`p5KQ?M3`}-qaeXlAFc_c=kKK0oj+*)4OjGix^c$jbjgm^ zAAQ8*_d%b)vVeXud&kl=C_z${&hnS#v24dLc7m(mn`DPZK$LzgRJQX0w408{9w91k zUwc&w1ey(sxzF`Y8qo?$!X1XJWB$5697QZ`KbIpw6&hBA%98f^f=EI!__!!}Iv|p0 zBio(Rf>7hkL;1q5AdqvAUZ+#YYU6dyMS1VjlG{hY{HC&p&l{5waq&dnv!TF9VQ)5> z1B5Jhf@EAC+7)FR22F4!nJ=xZP~!MTd$>{&9DdGc`ovVZAbHNATDYhrYHn$DfYB@q z6{vZOvt_G)NYN)+=go_J< z7NzVujVWCmN3l?o>0XgzNxo$5z<2=)6}Xj&4x;7%n6?X1U5D^v9h#8K_tPKvDA%mh zMVX>GTQ;ei2eg%DK)sDG?lTG0Z!P2gk_zh%YG?JD^T^>(@S72O0TR!@3Q?F_*X2ZR z#gnhJH5CRBo`y>+2m028!$qR+rh$+I)L@l|g@pm=#y}eMkt}t%UEQ#;Tjkwg6Rq9k zr$nrqyz}U`z5|l}Y`VVqSkZF*3r5M?*TuCF=8mSnw9|-(#`G2{sUzqej+_M@GG~R* zDpSRCGyHk4jvU?1f72f_*9w@HTwl*k^{e+Sa^7DC0kA zG3|ec2pq81Wxox6GWwCNE?o)@f$|m4Cmsx zeN(C3utyZI+_`Na?mi%L=TKJL8fwvBsEHIXTMTI2HmGS?Pdfm_KrHnx^SZ3rs(p8e z=c4Qcud&e=z%8C%$UaE^5dMkaXmaLskx2`H`m5m8Je|hb(s6y+BDHrGJCRy60_l%O zoSa{ShZHGs3;RT{=Niv*1<)+m@VU9Yc@gz#)IdT`03^^j02Hpv*#c4-uSJFfXIt?h zjE*2T+f3t{y@MV7rWYOjc;I7g?@YJLrOS)Jze`j9{P7lqQH6NEOnm2WGrVl?reC$+ zqMp5xeT<(w`+?^;bNu@taN_RNdl(7h6!$o8CRq2%rBJuXnTh@y9zT=)moJ?7$Ccu;<<_wad;Z`=Z8CL*b6f=Np}va*7g>*5gTk`E;F?g zckZrjzHdJaA}6V6ALjQ8KUH5}4pK8C`9|g!6E~O4Phu`Rq;oT|3RB5+m+EF7vg^C$ zbZOqISIv*nY&q%X*9z$)iF_qgWy1BRc&*mr=dZ8#WT`ss3rg zgA@&^s-}MUb&5AkVR5@^d(sPZL1J~%n}>UUDJF5Kk-tO9wQ$r{&ym5%A_zK#w(H`} zD9_@CbT^fHjH-;D%`6TH425^i6~`dCW#y}kCea5L7S?G=Sd(cx6t&su-FhG4!+jRo z;~i#2o6`kzjhy++g^S4Wi9hXq$J)iO_O=;pbrAZ19M!~_u2FD>b;F7GJps)4Xut$uo&X$A%vc-k9CJCvjQDEFb ztXvF%$gi@2atKY_*gPRn|3!J90Vy{UZiSKh`$#J8S*Svy_3`mWlg1p%jYHQAx!56q z&4Dyrg#JP0)bODki1Xh#GF-o@r)z*LvaL^4pmH&Tp=xA zJfbtEnB?wr2I6wrrLq^)NBLJ#t`78;F@c{`#N!&lv4L3{5*^F#e1tc8ApB9bwTF3% zOCUw0=?4`hy|yac+BZYyq%ho@BTTxeJ`_i)Hl3QsN*-m+L z&rTHVlr9w%D3sbKS%sCv12-=ijFeeg+iBs>0(s--(l1pht`xHgoVF^rEm3Ye{0%|R zh2i$~ZzA8?SrFd|Bfq~L1FpZxA2&7rN~j~x6O_Uxzl8je1kegAn4Tu~RBB8=J5a?Y zP9>Y$lkQEfBnaqIAJ{Lo59B||G$!%L6({W)0Pf6)waw{ zV;0Z>$dYUYfu-qV$yV*-CW(x5jtLIST?>JJ_GK+H5I^@NM(tiC`U#c(4>#M{&zWcp zGz1~DPV;k*wF>-`bguQX6ZY2I8#dZsEr7G|2~ZPDmVabsYNRd$y?Kp_Lh&*IXO*c@ z2LKm|Gffn%mTWTu-<-Bt6P!B7>y2raF=cDx4?FWa@SK)WiVOhy>`=zEODU_-6>)f1g<~ScLo|(rP^h>K_N@RuYC9pCMnOva~jLxtM!4I95HYmM5 zzPukkk0x7dt2}_{2i}>~O4l3y?l0}g%_kLw$~~=O8Hk#j#g=4PKS`+Og9&3eIg(NN zzS63D6T;?s%wQU5dt&|tF!dNgH;b$6@mS9*xz5i^5Y*LLp-~p?sF)SUC#3G^h!_j{ zrer!TblgyYKRN-r@}g~d^DXub##&SkXIF3F$p00>EZ5_s%<)J;h;=hj#RW%t+1m%nFeo+B{=JIE%vEsu{>a<%Ewh zx??7NT(6!0b(Jf#=Idk~B5NDc;URPmcFm$mXEoh*6vV2RUc8Rs6!ci?bFG zncm*SJbgY2r`hIU@i@R>m_4`_j}b^wZ5Ilv!f4{!9A*I_X;%s*Ovs$M)RIMJ#UO*Q zWHXSRhp+qmxPiPT%A;i!4hSlc7fzPcoEM=mYRHFsSG%Sc6sGlwVOxy+!Ez6g=>4ti zhs~j!ZMe;Z9R?g+8FD=T&ZjN`R5Spiszi=~$*h0w-XM&BgC7_g6JN)%!3b?YjmSsM z03v!&q4;rzs+OOsbuUoo$=wz#Ep(&8{bVS8W}OV%g<6KHOErqmK@lXaz}3ILegtGsH{xGMRCOk!FbY9qH+yZ7~NaiCLz7*6s}SuG|1qjN2``_ zQl!R_aYt5KD3TJL8A*B%K0%st+lJK-GDw{~udlMhoGo#Di`};db1rkyMXW!;U1@UV zzfOBvai9Z8yuuW6Qrhg2EIdNo5t0qaoU&SFKI-i8Md8_Y=5 z%r>*xF%fq3vGk^=od)XHTCojIizDs!xm)2Mf3?3bZ3I`-1-a*_+j)XB~}cVcdP zMg9tL>&Tqs+<3X4GD$AKcPQ{V3vc0t=;uC>6uK{*n6TK4-Fue#t?$8hgWF{Cs!VvL zq`NKK!Ev)0RaH$1aFOf+SVYOnZfn~Tm_`Ksa6!B&uW7Uvc=5UA#5hj-X+4U#JP3_e z7mNlg0ZY}{_N6>L(LyVS=gYfNO^A^wL2$7#C)7SVGkeC__z=6pqy)Iq(V=yM$vAU) zHVCI!I0al9*!Ch1O<7ZT8}5Gkno-7>pp?;%bz2}OKjaz6h3|n;JNINRW!doDf1afxrngtO41wgl^K$4uc4AI;?lR$g-4=v+})8p#xalNxjCpMWP`tlx>Jp( z$u<*+0MvXBGJ7ahq%UTm1&4%%-%k4e`cDg;1A!Z7_xxE?Xf1!$L3Eb`;Oy0 z{m79;v`ly`c*F(w%hj+hC(QZ3k$oDn1-k5|a?+;M5lY-~xCB0QjdO zP+9e?5i{fF+9xj`;O93L8@H#X79JV792dVH8@Cn{vm6;U9~n8Hoqds+d6u4joS3xb zf+ro|Vf~H+XI~i*)E^o)(AoX#?vWoFRvDkr{8!cA+BVh5B+St{GbXOwHz2F9q`k7HFD0X< zxou>0d@(DpzN2^S;_h85c2+ZHMmug+H(^dEepWwm&M0}_IAz`>W!^M(!6JRpJZ-@` zbIB%a(Kc(zF?ZQHf5okE)vI_dpnM~^YBRWUGoofIx_&#Uc{inXFSTtiqhmj-^Pr&j zu&Dp2bnv)x_@sLDw07*YY4T)n<$8GaW_;szVeet(@NsGXe)Ht<;PU0{_U-oR*xLR`|JDX;{GWq zJ^knR_wn^*VPkc1Yi;vrXY+8ow7RUMsosXVQ*pmWPR;;ZS`n% z<#1(be`#uMYU5;M=X_`DbZg^yWB+P@b$@kier#lRq_wYg|8jr#e0S@3t8c8Yxw|>P zEdTWG^!VoZ==$jJ>hR$5V0LwOYH6xxxTkxlyKAtkbD*=MzvJTJV)t}+b!T;Hb7_8U zzPPgZ;{M|N?)>cb?DXdJu_smV(8}S=KAsa>Yu>I?)vll^V8eY z&yGg)9cgQ$J_VMzwh()`SrPUu()!#ym7L=eYUlAy190^I+}SK-OipEfkh{i$mL4R01Zpvae2aEEVjn#4f_Rrhl~*U8;T?n)rYS>0ngvJQ*O{it+C^3(@Qqp_Iv zTR6(kMM{-pY|9vq1Hk68dBS0^h?L7>(feQAm1l&5;8l#)vlSxaGa4%x1cX@oPx4=5VO0*uIx5SGM{fs*zy!~y`4QyqZIiKD2ByB4ykaUaAc((3chWD_37 z3MVr<$B?8sff<=X0AwK+5Q$Bel0*a4k(8if3+y0DLVuDuBWWxz1g8ojSBPfm2Kp%F z2@x~;O9fo5ToTaOk%D9yDvBCpee^=!_o<4ym?!9>=(u1QBUXMJN_hIRm=UmnwCusf zd>QPKkgc^Q!dS}70w&0dI)I>jOGlU{=`8W$gAheY^sk8{TH2-l&;aELqe_3(&l4KV zIe}V(gfBwHuH`FMgnlE2QIH4}#SI}+m)Qj&3ZUFa&^DbhO>rCp=7j(l45=dEMI;+h z3S5jCM%1s_L(r#(UJ$_`3N-Z*5l4|Yz(N0cQjDU_f+>_p1VA|$LUl9yXYV01q=3Ml zo3v1qR}HeRn|=d<1A|DP6*qt&jKDYq_XlAQnr_w(X^LSh4|p9NXf9s?pXKj-Isf^U zfh1K~nBq&`AMVIAhJFx3VHhysIshOD6b3&KCaneNKZ@YLN|pR=5BUl?Fp;i$#qnq?_iS-A+C#fPe;if!NA>fUp=k_ZzQ0(f~p@0D3_f8F}$*Ng&$50-(cd_T7KGgwV3qM4%$) z{2)jO01^EFK!^~8_Wmg$jR1qOG6_W6Lm0{87L9xSf*@54Cqtn$*@f~DF$R$V^#c)8 z=)Ns) zh9Dmaf3Yz}+dv$_NV(z3^pM5TG0t$83nmdq=&=Ia?Ezv!_>quf`oV88dJi9Bqn9$m z+Cl`u{8hu1xspf7W~@Oa6GkDA$O8r`;Ri>)10W?gmw*tCa~taeXLD%_mw7`3FgP37 zGXn|>z?eiW;6H9W>JJyc(gUPZ_5(KJl#*CMiXHOfG5Z=ps08c1lg=y%FTZM+0}+g#qKcrK zEBq3K2-bC8F#k`OA0SGeAA5&#LF!kQNbx?bi5)TSF4C$flQR-s)hJF8zX%P`nJl98 zeU({rF-W63tgR$5PSjZ-s!KB>PxcWc8!`k}h(DAD&PDhm$Q2FkcsoMh9{Q-;2y0q@ zlua3NmT_B>K!p<$1BDe1J{BSZTU;R0@7haC+jO(6 zxtPh5+PU`xsu0isjD=p{g~n^gT5~^4lT;x7mmXqIUl1D=A?)ITKeS;Qk{E%qDnfuE z-p;u&9i0HA)Y@xL%3H7xW&iHa$1BogUodkWV{`^n0Ic#{uGofS0<&~DcD%ZSsn1@TAoh%8z=**xge%EB%8gNAYPVi zVqZ|ar69Nv#zz_$`@lQ|pPE0Urx}PnKpa|zRX_Ztf*40vKBSs^!Qa8P(A^Kr7zc;~ zEycLYHigx!L^nVtS@tlwswXv?Fn?G(gdqZm{2;EOepr(;AiW$0uO#&Hs)6Z%RMfzar$nWzZaTo%9W?jCGxC?fypuP1!I`Pi+VQ=wG$|`}6&II-9H8 z>*M|J_VIKUSOmqlfq{vkj`_?_*>8!7K~waqEHPO z75INCTm6s8aLTz*RP^t6t+h!_x_SDGdA#|qrKA~q^+u*jGDG#kz#7s3tCS}TigCC^ zq!}Y&0mC)vWRfIBNe~TVN~Vq1Q)ln*;O+O`_gfZtt>cUaA3pf#n`s>K9WnsVLN?rY9D=OX)Z>;2P+=3(oQ z-0-$s=PgfrqE4=kQzZoebQyM)rSFzc$EVY*vfOGTof7&7*D z>#5Fc_wR#`ixk@{mg=esdl+_8r9HX}D7H82MfV_gCFSJS;ZVlN%+ZgXgSVIBu%W#l!KFmvjmmw6bB~KO1jC&Yu0z406f9gr)H-Z*B(ZfLDunQ z_EGjrtCdIB*~N;5m7*F6j-0;s33bH!fr;G-wxyKC0Z8E=v!Wh(?H2#oY7>sD_AC_^qX?kqO0_Qq{=U%HbBhs@ASzArD`4fTociE7M>bpi)o zhwm|eDewa70!NRAb=IrD{*@24$GI0=!$(Zqqui~kR;DQohH|4TPs_q5VjB!rCg>)$ zG1|O7pB&3U9zqU>!l#g_D5;L$r-BVaTM64ACN^0;-XC+#|9<$WhnR;bV$5&)k8OkP zf%pB<8vIA8$4DNO^Q@~a#(BX1m&35>yYKC<8o(T>9;pI(hq>ZZAW%=%t88rB8T9qH z0iJvL0~dPl1H(9i??VxBGV2Nc21c>a_8-mlB9|SrvoiHHR!#)p-=A}TpiJOu|-Y}47m$G&a`WUBn(;12f>Ay=e;-5t;&sEtgb2kLY@NmEJF*6G#wH7w9q z+cXkX%WP}5y5C5GOG?FA5hQHU!Zx=CWeLnZKsxfocO$yjDlx{=z)aTbbH=XH+Isyh zX!VZM;8eQ&mCv0*ChQiGDpzF{WMTTIS0fi(ci--RgdVGj+7vYHA0&MqwGT&1s2h)~ zU!$`(HIJ7}{rBOgYalCibm6D5blUETYKhN3w!)v}*iV%{4E=y68R)}MrVsdceQ}-@ zqIOf4jT6U9KCe`0&7H|{qmf?@TBPj(MKTlA;SDEsGH5y9l`y0=&L?-uu&nt4Rb5;7 zmh+OfevTsp3cBZ%9KE+_!`2jw9Lfb6k5bdwSR*^W7E(N>ZOUBh8o|f&B>l2o$fkG2 zzTHcEO#2^M;E*in=iPCd4*b`1oGV#>`e!42GGwOEifS!C7%#(uLl z?v3)@9RU}=nc^ND$0GpUS8ZHtn`lDEg3bW^tQIv~QO^3ci+j_hx(03<=qO&U1n+ci zRFnRguodHRecO9hocNG5s}i~Dj%xpW!6Bc9q9P`nm#Rf_X?NxXFKoF|LsQTl+{78v zb>1SZ?1cwX3~G1VC?G6f{6J_G(GZ#V6}oBOan&;1k9j#|hH95okiq5ilsKyA-pE zeIPl^$)Z?Y!xPRX=d=}B=&E;nojWiExGG*j?Bb<3zPOW+Rik^oa{CjIJ7f{OTW7nr zIoCjq$SUPPRO1uL@Eg6ms9~s;tP|nxU#SXY)q(V+g>aJ_VycHYDXoHyVG>VOg3{uN zx$~~oa52GIO%A#=d_f=Dnu2lG#fqzDvl9Gh3?#)zD5{SjEyz&Z2J(}Y zZ?3Ax*7SQ+Yb*>BnzU0z_A$pox%zOOG>kF}Q$8>gZCl&jKSekVHY21cJi8=O&O{Sk z=Ty~+mW`I=P`zSiuqyKzZS(LY{Aptmkjv5kJ z7+-R3=CZ{Y!3$5j+f*Z6e;A7deoQ)Ub&Vvm^Q;%uxNAdgn*&+%euq%4xhPK<;}93A z&?=JemEDSd?|c^rO3MOm*UU+s`kqO(9dS6`o6`-BEZJCLgxLfSI_2CfjfN^**>b22 z+nQmfspafmE+yp7CNCsKBnQm0R0jU`2M-+#Ws$D<1*6PJ=g4<0X;-(=&;41CpQVio zt7JRcWg;u5$|{idv5Y4w{DecSte!snIA)aza9l@o$ISKDaL|!w;)VyG252ZPGKDU} zD*I}Sck^RPV+p!5HecEEVn}tu5Qpw$U8M0~STrH2pK_xfdoyhzSXK_aVqm%ptLxaft^Pqu%ZRM)V&2aia zv+UCo?88L@>TCfP(F!)^H6tmjHqVrQY;?m;g(w?FBY#tEd%vZ%-awYGaHE1sb3hft zs-Y_SnWA1MYk^|kb>F~z6RcLKx>oDw{oMo*d{_R9)c3x#*dGvW&XOj4r_3++VRdV& zp}(K`)vHxl=JVVzrGcO(w%uzW$?zGpV7U{?M*u-)>#(FKYg9iTD|zuk#8ooa3i9~2cD>YpwPL)O0L{!9+_MX>);dtc-%k{a$v^XwBO-*@C|+luZvHOx*pljM zt>w;8Et~2{Y_ff}+_;YYc+iy*tsygm{M9jkFJ+u*vDii~h4@?J84o4HWo&xQ`lkI6 zP6Da}!o>fjt3pQ^kS{ummWWoI+e-V{*f(=aQ3Cq=HOgj6_GvR3DWsETvsk?z2xw6J zLMY=yS524)L(q;x+r(b%f6w$vnCLF9%G%$6{YAKeuqCv!aPT0?j5u9uRaeRLX2oZB z>D`C?(@E^n#u}-!L@doB#^r}NYR zPY1(4V{CD`{A>vkM|pT2SlyoV;3hb-kW*al9~bDSKXdvnHWTm)|NHYcS685X1*r}- z2+nQh_CuY9!pKP@cS>miv6yw~2a#?+j!`usR)!QNInSBi`!yQopqSK7w)v}^9^7SC zdb2hob;(4H0B;SWK`bOg!ud_qz{9)eqBa0~?3Z$r1bo30%*7!NfM^C0Eug^;V0Z-! zHs1Gk0-VVnNC+f2F}v*qnJ2^9=Dgj%XZ14E3ODst+f+nOUkTnWs!I}5yy zF)mw|{TopR8YgD0YQfwGqEe;OQ`?GB$^dRIZ}ry&%NcUa0hA!Q#>TuLVL9TuaKAbY z)O{ZGNaBpl)0U2V(=`0pG|Q}%8{L;{Tqm6@S4eE&{7e+9K3z7#Bg_2{*OjE3LLGTi za*6y@h#7zp(cm@mV^omlG|ZhB%!?U8c_U)(`?i9#vS!jVdMzfBcEA-UMs_y#ah#`b z!%h~VMYo@1~Jhs7rcvn*yxIJYFN|(1CT_NWgL=B5rU>< zRbu~%qV>DkGIymD14>JQ05M-9`#YWne#jdWXq#{N1&~7sj2iu&VVIo~mCIwxj-+5- zsHnyWNy!34Jy3!9proV`zlZh`?BBV#y$>w-2jVsO%{B@aAnrvp?i zieOfdp(3Dssz4GqqS|FF$xqUAYUCqyR z13{GZDovxwxb|Qi0$W2$NQRX3cKI=h{rwPVLg`7r4)_aIh+yk_`lTXMo_)!v+b6vVo;(e5G? z9c(oEp*&%mr_1PHRtjX`-4efRDVjwhbKmU>y@t<@;zF~=|V(c*g78kI25 z62#M@x_kBQeR^k{*N=&}k3iiEq#N_1_=|3zw(bI4eAlkKo`H})p=*qRG~Y@G@VpDU zC5^Bw2=)e(L3Jyf7>5jM!o8HWHs^*$OHA>F&FbRbDs2igI^^PoJ1Bq;S8@mOAoxTg zV#Oy0k(^PY2jNsj#;;-1A~3f3+O3;9GL%se84P}ST$d!oE{w3ixVq$qXJ&Fq+Se|) zOXcrqvTaMdO)ay7wCr?{){v4sVz7&05f_s?DqjZz>~{~uwb7O4_$wC#gaRWy9BkQC z|4ETIA&e*I8z*y1>sOH^b03rBy$75^x((fY2<}B)HxqkZiI~oTlGhK3*{5*)sv}yM zu_I{vda!g2FbhC*8W*#Y+=_*HxCoxuy5S(M5&{HbROY>5>QUNad2*>7IzJ}$2Ufvd zcs#rFh0GLQfU%N(8w@NmQEZVjZlpFrC`FRxP$Ss$TZo+mEoVj~0s=P(`*N0r^LHsR z5NmRZBV;G7C;)Wnz$Q%Y>s2~t1=S_crf#pnknuH-oLeS zg=9`?ePnm*byt-8ei#z$Ld(J=?36b^{09>A$PJx5_L{{gu4&HZ#K92m8SdCB)Z=>y zm}!Urb?belx_f>g><73=LqKdnq3RGFqRVz8ES$7?+p?gh?Tdrv=<^W#&!laF(DF(P zvdG%m8>7oe0HboL(~kUq8ZV^{CkX*aARug)`Z-@G#VTy~7seeIGy{e6Kr1_`DuaD= zdUVIgs#FPXZU0&<$w^uM<)l^gqT6ulwbfHY`4!{)k?u_w$$miadf6ZRiCQFF~Ls z^?V5C&{z8S)X+)>u`VIj4}iAfIwBC#0D{MlQ!WEUAQGue589pKaEn-zCLZG?JiQSD z+BhzBS)EKGM8Zy$?F5!21ZLBRuY?BfxEEZM-%!BMshPp)8M2A20NLOV+z4^%uk|BC zu87YEbP9Mzu>tn0FyP>n@GJ-Idc|}{hIOE#ER;NSWs0K_hy;F5p#z&-_M;-&4uMzk zcepxZdB|1zeK*)s_6rXlJBpYFmJ`US{(UUJN_y#S;$KFwmIRgX!ZP&*lhXKxz#9pj_o1 ze9DsqA^>%W$AsIU@+gP!zJ5M!PUlc~-+z=|?kU`xpLQ$=&D*a|N^hGJ#fMmUg>pFpN3s5uI4c3a`5Cmc1joC+Yh;*KtRS?JL5kErb`b2`bh%=SOReE`uD=-ZODWh|Izp11-Qn-nGWE1D*e8ZqZQ7J zJ~|IvzJp?OvH^Co0%ozV-4?d<2lGRr41>bw>}(n{+_NB)e}f)3$SV*e@K>)0e%1&J zZ=Q0v-sspN-CgAHJ=!ZPS?2lf zJ6mab=boXDgr8Z=-1YAMHrV&2*P-vaQ)5%9#I~U(U^O0Y%HoHt4KpHG0~Y%uM0{Iv zhz6c;f4hmIY1aajL?#t&u)m}!9s__ON}Oei#k$0 z-Lw`N<@LaM@fxqx*T1ORRuPWqa)^W$(}>QS`Ti%Z=8Ch7aoOv`I{vMCV_?%Wz2I|l z=f0(gj!Y3{T4`~SsQcWu z7=HJA>+bveu!wJZpDzAAs%J_V>Icft5>=8AKQAJNTUsn3h$ARO{7=gj>h@9#*%g=_ z<>nj@6y*i*%)o()IbKxiYdlqQ8Iyu7X1_2KGVz<~#?(smJ^q>tTC3fH${Ao=zZh5* zVxI!gUL0^A%?CH_G9NnxFh#oO^06ZYbe4{QVxyj;Hc&afV%s=57j5NRx z&h7`8tPQCij>l@3umRiZ9==vOaBwObc>U0fncbxyn&$=v6;j2c8u7kCMGm;z z&iI(kvA*8N09cSa`eEw}U&wN3hCcVw4L$cC-d(zZs<)^bR>O*AL%851+NP^UP%(YZ z%kJ`Z@^(!xDQCk+uW#3BxO?e)2OYW2%Wf!$#*e-fLl1u_F1U#>hh}d4zm00aSq;IS zgA`=226|K6)dO!9TR?kZ# z+~7a2udL~WhUT-dVA&1$Xy?G~5ri)O{bJ9aHHt6|MC709eg64}8(1250O35eDG;wJ{uWO^?z}L?K(y2bkPlC|@T=+hWr+y-w&J zf&gi@3)?wSNFminSD?eR zW%?{)`!7hXQ(Q~bdw&VM`FHgmmwh%SN|by|MwydVu`5`swe-M@HW+wq`J6tEid*a~ z38y@bhe|05Tk7Lr+giq+H?@|@3|gLXW4k&T#jjV8m#5_5YX5dOiY8DI)s7ZrZFW zN2nEul(kZ}LOMUaEE?NFy*l4)=V&AW1lO$#)(<s9hS?`gj5gtTm>K<8zqct^4r__mw|H(S57=slJ$k zoL|VxjywFgbw!ovj0y8{KP(y!mgjG7<`UvIB}w-=_Mi1o*aW_OMtwarxzY8W&*Sy+ zzDW{Me$vuu7&xUAT^_`Cg$uQ{M*pqy#n^tWt(l3*kummF5e|vH)j?l;E^$09WCdB( zCf0TxqU!am6yzYB5Z-?Upt?NOj$<7(eIr-iaq~xj?sFg?N!bzXwhX|8QNl^8BSOX5 zihM8&WG+S{7v_b!r9}%inMCCn3pdby;f@o}NFP=L1I-Dho;H{F8KR&*FPJEx zh(io_m-mdZCO_0OpR@s11}UHn=>PC_mqCqweVTxQ;O_434h=N!(zv@jH16*1?(XjH z?(XjHG|=es-*^K zc|4gP!pQ%LeNd}ND63e6d|THtvGN5Vu2!lh<`QI7GTw8Mdz9c$54lvejgtiK ze4G(Ov9&<$rVp@)Jf9TYEJ7;I*NRQDtjof|`6$b@lE{*fS_v@ov26RHn1UJ0f>(iF z;%YV3j-5W_LC96tuq8*cc=i$=mI6g>3f@anaSvyb6~3{KqRpVxTrWXX#hiWzYz0;f@ES&GO-yAIMigdLS;R|q0#WcElF;)EZpN{ul0mi;{}j-2Q=`^ zsMIk00rKP40ht!c38zK|xJW!rz5?CE*T^dH9jgdnJGrd`_WMAZ4ek7Pgc0IN`lSFe zS0N{k$1PniEM<3Q>(jNsE=VO5UaO4>U`w#c>NK4n? zenlja+&AXzj~~cL9ugG_&Cwm#>P*PbbJ=>t02l12!#%*zD>emi8y{`vFuj+(MbQZJ zJ1k$BiY#2tK@sq3_xr&(h}xIcJeWbONZC)b#Hq5>PSx%+ceb^K8zw!+%KR12Tj1%g$khg)n@;pwWZH324z^SVM?gLs(oE)cFtcw{5>L{x(Q$L+bBq z6t6)3kKp%xHu*IwAjn`?`l?0^-jJrjvxx#2+JwhNI_}E(;M3L=6!#2jW34O!>`E8W zNJAE0KRd_opOK+8@O}CsNpj?q{1P)lM%L_tBc!!?@Td~7370z<9=vk>9&iLU`UEqI z&*;Q-e+XUpBK3m#3dQ zJb$8H+M|!u*p6I0D-Coiq`$_KCk4cga$4MPc73#_wUe3N4eb@nsHStpMB$&a+R)tx zlQV^hit7XKm0)d9D8&7lo8vSTyMEDH!ziUpDg0_C)aY|3J($uS9|1*`qt?(&iHpRP zb1Cnk8vV(5=$UviOV`sV1Z_cfW;vDW4265P!s`SxS1OXoEw+~dXfcV=2O3YwlRRof zDiC2jO>jGh4L$Xp=eI*}+!sq70Pvl6Z|pHG2aq2| zdo6P*u2P@0BGmm&O5kzp!B5F261Bz!>!=HoCHCAd~R3!H6{W0P6XgTPy2NlAykibCn&Rd{0ypzD?L z;Vq!{y4Lb;litCyyBw3?{dk5XV4nw^8xXcZ8b^`mpyH^>izb#ZN^y*8@S5$QEwv?}u9j&|ov@>rdDd z`eoaA&#a{(l}AG@9v~OS_frDE_RWapr^Qa|N7M!P_!63}6&q*VoJgEiv?-aB_y? zS4h)4xN$CD-8G{?Q2L|#>yg|b5C$M)28q!|@`g8_$IDk73S@T7Z3sP9+0~!f*P{Q@ zdOnQ4toB@a@Zrqibby%|2`yhWud4zNm>KbzCbdT%WQ4a=1!^lkczPi@*~Q?4ojjGC z{3bSQT9uc%n-v7^xQu2a;6(p9nLENptyE10o@c*Vg!X`m(z{m6K^?)5*fT+hGuXhW zITwzN>WBp@jU7AM%Ikons{wA_YO8CWV5t0H*#1_UoEo&~kzkP{>TwX1q2&}N57M2%qi<@7PcOa?>5@`UXK zYnN4sT=soN^i9^Q)~G5Cu=9uH{;lQV(>1(!GTLK$NANd{-=oKNVCr>;v{9T*(b9W7_o_dH~dBrdh-{hDMS7=>BdfcR|_?}2bPqrJFi5C{UT1}BOQ!S%ZY zdokvW0^F74uFC`_45E&?F?&y0tT0K1b6cE=z01JDiSYx8#S(yw)3ZSE2I;o>@K3w3 znszeBUBJ0F3wM7d5LhD%na%!H6~Z|h$8z)~_o{X8NG85T^xAYyPkyEzxN3q|r$@`L z3$V2CL?z8M7W_)SLEyW>_L}{eeSA436Y7nKdoz|KFxAj^fN2mDFaTzELzPP+5>=w# z0d6t+vD$fqXGRV<8{v>-D z0flhG<^B&S;kqwYE;j&Goh{VZ9K@SOfEiA{=1^42QrE!qfSNuUD`N}Bx&bPNR23|G zC-dgDkz{^vhfoy)Vb5?x`RZUQ^|blEDyr>yz8Y0Gvj9g-CQ~L_vL&n39dBV3_!p|! z$3*2gRG?yQd885S5MpR(Lpc1G;)J}xzB8R`99Amx_=>ppNq;q&ek!!BZVb4Y0{6YT z4kgM-=F}3p9Tu^{^&L|t>Y~2iBshc8^tK(6Ehvd{iby}LZzlFRI^aykna!t-u4h$5 z?#YEN_vhPIT!iTB8+KN7IDJ~w?=%!|Oz-x;TMJ@wMF>mmnM~`qYltk!F~!Zm%e3Bl z!1pe;#8MAE;7DpFBkZFcpdwmJDcYKX=$!1`G*$AeZaNQ~2o1bb@`>5+tIA`(+>mgY zz93e_?CxkmhNOq6!jh=eUE$aTH={8*g8TgEN*e}_HR&zZZ|9uehrTW?dx-~H@iVs9 zS#JluozdrIKG#v5-kjkXI{kI7_?`hu3wOLagM?o`U<*D}iI@=C)$?4N7^ZX(@LIO$ zf_rTBmIo@c=^}%esd<1a^aySYdDSuV**;*@D2D*A2X4$<3)W&~-#G%H`(j^kH2JpU zHwo{{2R@*OTFU%l*-Nf$F1AN2Nyy%hU4KJR?8`|vb5<7=o*MhOQ^%h2xA(K3Y$b;K z7&_GyQr355j|3UXDleqeSF}Mor#H6;L~aWS7XFl|f-$ukJpu|<~%3vFNiWWzvDDl5@1T zqb-Z3kWZnk!9GO052iNiwnwE$;Af?)KC*0xYj9A0O+$ttbX0Yav{SVweBNbu&18rU zsE$$Dbh8jqsO+!YbQTJDV>TGrW0^<|ab}g;vcor)kbEX-jYBqW0%yjA-P%g!ze_vj zScvu)m6{nLD-QZp~<&KXhT#u?rrUGrNjMOULgU!&ItI?~3FrVx^| zb0oeC&hxu2xA_s9_k=gQ%2P^#(;hvau5#>x46UCucM{vWs1dv!-Ut8Ab+rUp08Inm zV+(uYaImSc$(p*#!`Jq#T4Zolukx~?lBF}cpQJOvK=ZA7U(dgUejbXXSmE%zLW(ew ztngB-O!KuO$yorAavFe*AK!@Jn(8Uu(@qzi>c3&kX<&l;M5FfGiM zh^&}~k(NaMwt}Pkt@t}*uJH>hCz2ui=2e0Dnwf~sy@he@@wQIo=;?>Ed7K7__l^v` z=G3LQpeaGj1s@+FTo5a0mSug?;f^guw3Pt0EY}Qw@Rb`;1R|R6$IT=i*yuL+t|A=R zu0OX+ZZRO&2l5#>A9K~+qELX$m&NPvqIbDhcLaZkjw5^bB#>P^5*^nMqA2{6b>})5 zskZz2yoNWm#pIGQEayG~pWpBAih0BM*3I`Lzp$y#w7h*w_3N=+pBnRQFfF!h2pz_f zUPeV1cV6Y%fN)45Y?5c(f8IwFY<5#w6Nnc%9MbF~e8z$`0m)G=B;K>9f0l9FFKiAP zrCRp?@jq<5X$iX=h4By>`XI2S)qqeHf0?qwmK0a^atIKO_XyfMqbhOW!|Aqujk|BU z6tDPUc=hxG4qzWyL&RioZz6p`Ao$FOZ}|cs%IS676b{FKyhoCb4}A(Y5Gp&Hg$7)Y zd6t2X>*J1-Y8u=2eT_z5Y_S%ZWqJjq+>=z(e*_@YI1vL@qruFD$vta80(S_^sCXk? zQ=?m0mNll;yHCxyl5M?xYBSko@m-r*|Ii@*VcR?;c#TtG=25Mf{QTiy9mwGG@an_< zZLNS4n#YzY^!~uT=FERz@A7SUt=+l@nay50!?-gP37zEAI3C+2I0w1-yyw~G&t(9* z?Z9L==&%USP3pAiST=nI5R{b5* zx%f?Udo~TC7P3LiZZq-ro~T>*HN0M$3_l4I;6=J}I*!MuOE+=S8zI&fkv-+V^o}2O z=r_3Z2{#(LLGUI`|4C-hLyECX9$@-YZA!58f=4l zxwHf6`&fo$Ke2xOdrBVHyElj?$aphK_E-FJ^h)VlBqWHtP z6T3>XNB<+=aHpkaf#CP5_|3EcAt=Y!|BiH$qFwjl(g6YC(*IBAtN*dyjqUAi?1dEn z!4{X)G;K&)(7c~O-Uz;Vm1R+qD5H@u)n!=ZvETc8U6yLp;k;0butoaZ#3iI;RSJha z&$#g%MR> zh^EHedaE)xphk_ejUOKa1iASQWC;&s@bRar%?3zDk{a|^u8Mo{M>*D7t0Hc|>V1uS z>}~j77FjttT{cc6V!M(i)EM^J!ckd5`?pI+C3`P7Evo#WyH7O%2rELN8g}n33;MXa z(F}VhcT*5A&0A;vYAoh~Xp;5J(KWoHh-k|yT^u?!D_4KaHP76*yB+F1aZ)6)wx_M} zkq9&#d^jf-y3v{s&nVQP$M(eX^l9roe(UEh@`SI&d;oLv)n~*9c*(J{1ViF8zJH?h zKs2t8yA`vN%(*K_c>Ce>99*r=I^`QO(@}3Q9x|AX#%Yq;Hxx~tvKtlciH+Fo5Spvl zTgT+bSitpA%CP4^bur380u&i2;n`imf<~Zr|K#z3x@_8Z*@N^sn$vyu5wy3VGpk;l zVv0NtIIB?ahry(86ea8ZiD$iq=0K7cOy@XgBht4#71+)5hknM`WG0MheBnzrND2hd z`Afj186ju{$^)ZNbqbICH9%l<4C@KK?u3|{7);wj#nnF7QY8?&J@F^2q|KZ4Ox|Q9 zqG0heJ?M!fkFQ$S4M*pEoj^2{iuly$qUnb1B3cldT86An$CuA6_Y5c%ETl#MH52rU zOYS~xOQy2C*)Wd6QpW^3Ay}8DH5CKh<=v6aUXv7$f(D7AF;W=}Ku)#-idhn5tQc8E zHF15SL1+9q8mLH4flhJNmYQeAb%M=l)JaQ|++nqET5OP(ca~Ert z$V0Qk>*RvNtoHlF@`a~Sk=BVp8aKBc9Zo-uh0ziCfnk%}lo>f5F4uSbYiun<66uv;GiTwS)QzrE<}Cre5;u32ZU+r&8$xpX@CnR>Z?r z)PqG>;~PwHMQEpJMT|Y&^*oiMGZ6#N;Hvy{#o5BAQ31B>>5W=P<_tV%7e8vOj^CkX zO9$h9UE64HSjK0>PJ`IS)dT6lCEK_|?k+2XFB0fKbEPYNv>s|(!lURu<>-xi?Oo7T zmdMJT`FHE%cy)&r6f3V1l5N|_b%J#O-52vN9r&sE3OdGs?@(Jpoo7p8??%fpl_MwH zk!$N2&;PY!cl@S#tZ_Qe@eh<8|GCj`LI(I@*^LvzVV1ZNWGtJ#+l_53$viQ_rVR>9iJ$1 z#{;dZwqup4JR4x+_Keuf771_L5!HcXP%VCtuA4gBuw^aRHOcNTe;t_C{FUDma2GMT z`ZLN1G?(+2mtgPcs|n<5j>0VJoLk;AT&B7Qq3;Rt;%8qf3NsZ21*UV%I=(uckS_K% zVJcG!w;ck!XAJDwUVJA^4gA-=8w3&W0goJv1Sot9=WK~eimBnR8gqwkI)43j>8%as zJ*kmq1-Y$TVJ(T0Yp`4CUCVaa9ioYY^3;yn=y|^1*4QG?$U+3aQwM*EG~v|NAkkK2 zq<01V>Fl5rH`|j_fp;FvGXZrotgf+~nr5e(7mOotc4@9_ut`dl7@wuzqqn4#w22z+ zA;u2l3$iqC8c+FL3oirLHD6P(q;G)Z<&)|&H8VfX3BDy>k{>2p5R|t6%`Drc1EP_S zLCJJ?7>a6MXY)u4vm+jP&MW9jFS{O5uy^{xNzX7RT4mja)eag{)=18`?#%QFWb_B> zkd-@FvI2VNCBut0=LbfUI6UNh}(gaR$DKZ6!3B6K^ShsD6)tzyk(mdriUi{Ol% zSv|7Szu5w(4-FYC!3 z29Kf{`lxyawcy{mt?$J)0#6xzFD3kc%yD7=d$IqA zjnKEX)ipA9{udho4Ey=;|F98rvlrP}!!^~*?QL5l!xz0hyHZloN=g}edX;i=u?hO>VTt-4db~-xQqN0v^dfA$q$)ck65)w|v#(9E*X3own5)!{{ZHof}`nQ0B~hKG;)`}c;2_Zu1}%F4PYCJr_?@7C7N zMn{(~E?$q09FC_;>D|rDs_*Mx*3olt zatVz~ZT<7~`uP0*jY@ob8Q-qNe?}#~MT!5;NjT;#xfibZeM1ueO_9iG-}@#ciu;c$ zhmWgAPZ}mp8^(`2X3u*TE(e#d#y4)3_V53NNBm2Us2Do0d!*6G%_4KcqpKfXBr%|mRTZhs3AGix(_<9**e#P0d-HxIG4zc#xz zTUJ|ESW)<2goxd<-MO{7+11&prKypbk(Tb3y4Je9lDyN~)772TZzN)QYx&!W7@Hj% zof*Bjzxbvi{)-c_bG);$ztKP1|1T$E>tO5l&+UIW5%*8`|JjN77ZOobU6qrYGru?Y ztwnrO5$i{5%eza*H~(M|gA)Ti!`&VI?bVG{|AHa*&-V6CcGEM1eSG+Ga&*5hvYwut zuY10l5I!GWzJC&!|AmeCfcl4x=o56iyj52eolK@xZw{qu2#(3(4*EZA1fRonV42`Q zY=r*wLSa=ZB(3vzkindu!%UQ(CI`+EEG8W?! zB5oU#_(70wHo_-x+o&$>=vU5&@2)3R+7Vpdh%NaFDhtJdp`YubZSX)!v{|}oX(qk6 z`1Cxr`V)RrL9z)tdypy4B}*_VMgzkirJ}H*DD!~*>N{+-a1;v1Q+8`;0JIa>OWzN6yk-yn8RtOeOb2oT|x!oaTvDt zM5N7O4QBb)bBV(!PL+@)z2B1ZWqb-sK-W)bt6R9+p#DP`Ze~Uh(yEK{vuyEtAd*xC znaBVz_)P}{P(TGMjBWMYkiTfX$__5>IbP2t17X+gij<)P#2{s zQ*A+@Ny}07;d!5T6J}OXcOxHw;c@l;9wll{_cC6CI>7R@o3U(@UF1|xTw3}C}uf~@l0@rhxs_4FC$phxp6Cr zftrB5KnicLFpt{-{8vIfzCyx4LP!BfC|G|4pj`m|uULN$JrMY>*jxd4>;tTI#L)~% z@q}I2L6odrVKT`(NQYY?0zM#qK58`qT-013K&~H<5fA{Q7YKq`tq)p@(HFKq0Bh_t zh$+$z&TkgVhcymSfN>5APJS+2tzsI7#cShGOj;S?ux2|wx=9p3Mtc!K;<3;2T=;&%gaAc;za=+5O6Bmqq0-(Ofg0`7e3C=*sgoX=PQ z20tgFRTilXXdGAxuRgKTcS)O|avxNvg;G3-5)h-Ag_aGIYRbAY?iV8f>q$9QD=(U` zdwn)mc+k)F9;k|%5!g^n(jQY;0E(ij57vw^0Q^giy?oC1jH8qcB3ka8)G#!hzh6Fl zS-=1_h7cHbG-Q3KyeWrW?i?9h4zSj*2WXKKW-O1>{QVw)pwqe}Iw=uPo68c|$*AQc zE)PvHs0YfxUuBWw0SvCh4d)HgH`XXl)&0+&zsjbvz(&1hNt{aEzx_lOhbB9U`ZchnB1K zN2?1R`gs_k50^oLKL}|b8gR=Edn0xE>HlnTz;e;4z^R{zTfUwuYmnX$++7Ub7OEiF?N`~Q9tyjS)a_9dbGp~W2{b^Am1C42pQ^JAY~yx z6cu70Os+4a11t&VTB#UMv4Ew77yz3p-yd^$cd+cSm{g17h9eS~l(;A#z0Vbb>9=2m z2?hY;3I?3c6*$U`+b|l&OVkg{E~T_>kS)2r{9A#A6;JdRj#Y!84a_@m=_EnF)(c`b zBZ3j-2Vk#&Q{as;1+f|F=Zis2N%Y%p`)C2s&g6o~lmsF)I`{XQO2Oz#=R%Fw-qytu zL)hcr$$bgPn8_>q(K&b!ZTSs_$Br|D>J*Y_wJTw;ht&e#YwMzXcK6I#y&`pi6ys@1 z^HNnGz)4K@!Ue_zm1$Mc8XN`0ev=BqBdiD5g2tn#hYG--AwhDs&cTXOLMw-HrO?|0 zEB^K!Kv-M^=}fffXz$S~^Th={^#7(t-l{T}tkunK{PlT8{~ zNEq#2u3PXwva{m?`^MHfUdcq$&#M3RD6hWuYP#jX(LEYlbEDGuXm0Ike)1CQjGAt^ z%wCm#)2`#eg?85s<)+_%C&qWon1eft+b~7X(hv=#I=8%^&XqBIoY8mvQWM8!-TnCf4kf_6W9aM_Tqi_u(EY$bch~i5 zBJ4&E@x7H%5`|bJy%|v=rK%a^n4yms&0ujZpsu}Jc($qcryZ~0&10jsb^eb07U0FXr3K4$d?~+nwvv$pdjpqudUA(S2REx zRkkXjH0Up$iJ|QqLioiy4xT{N!vHDoo<8!GPRfYyZ?=xaqpM+*0ELc+Z0%j}o;WRdj7&@}VAZ6-rmvNJhBIvs}DO!v2ww zBk~DdjT%ncs1GH6C|k(yrSF-7uT16=yA!P=V1IMJ#7wnY2vdxoO#K6$4>`a8 z;;xWV-zj&g%ywtXqyQGV2+zA4Syul8Gj!sCBM3}t8Zi!)Uqa7R&l=Tlpb|m&oJ7B) zKD+$WMZ^AOi+9DlKO)wXfo#FqJD4S^&&Qo?2&KB~oG7C5cP%k1AGaToz2$kyLb?Cw zBARA^Yvzd8u0bqM4Gf@2^HG3Dp5Hwfi=LYS6V8VfmO3Z}5Zz@e!aTBXiHla^Lum%agLYHOXIK~CTjY#g~V6UiJ+s~$-^E3vtxrSp>!yV(lOb=;Mfn@^5i%49Lrvh*Q|r10bc`$H)xR@-fu~(V?R0M7O;%6%OW-0SS3N zzS31iS_70G`7OpGHs;p7HBLEpa+ez`8>NVpImqX-h-7IZzbn1Orvs5X5XSbN!j4*= z&(WsIo1~;Eu+>{&?Sa(@xRh&Z*0@sig06g}?Gtv^M3Aob5&Rp|wo^>3RRK z7kTxu)ELr~+t&k*NrPr)j~cQOlg)?3q>10bIuX@OQ7;kpG%(<$oWHA0M+?4xJ6Dm_ z^6Cb+z6#F9L~^}@z3HTU+S}6LP>88jGzTfH*q1;)1#Smt4-xb1@(i!ry`F~FaRcjI zOrQI#jmD#q`rX?14ShaUPCj&*$CnFO?qn=yuSU>d)h9fHSi2OOQsPlCa>zbC>t21; zH+Z#nz1^2wopk&J$J6PwoK@d!+GRlgjV9-tuUQGDTaTTv&Wh5^pv&jOOHMx!SlEu(qay$lxt*k#p>nC9R9RC83Ac0Mx&g%q!fpL`j+J42C{9R^RLG1%Y&Uen+@+#d_V0PW~2L4!Rv8)`i zdr99yp^7vma{rziXOk#``!D7*MbV>AeGcSd`SNp+EA#@ZgO}vF^&Al$F6wrs*+hq* z0Bn({1T>?7dmVDb{ly>s1jJQa{&Q);hs6i&0J zzR60#W5LcMeQ{$8A2?V={o|b{@zk}(M_@iho&CFbMqcp1sT!ke$ita@GTZ@W*Rt2L z=5Xas&LO{21^iY1q;rIsV2qht7q{%|3GdXa%1YH$ni^UH2p*f0;bJqUrbe1?2i|wz zD9&?7`HH@QV<`e&|MbhJu+*z9>XZ}Ph*UuvC3Z}RDjmptoKo_}m8BffY_mT9c-JpP zLKO3fjp+Olai2EOzGQ7|8;t9GCA-1pvMEn9XcFv2{hc8d2!Z-4KijL``U*BbSR}}< z5XQkO5}~1YEC2OnyN;_Lu3fg)gJ%b{U|x`kY#M5Dep43aAaJf4ZXgM$e3sftZywGH z4-R)3iP^Uz%sieOeMwh8wu$?6ht_@~1N@~Du%keRIIbyr3ogS=$bht?)-_=ZLhUFI zDT-ILvA_io8j+lE3Q6-9kra|nUllgbV}_3C&SS9=9X})kUnzYnPG7Poau98x3eQ)` zfzWQ8YbZj%#^lAJr9KaHPMgTwt3roFu0j{5)q(;C{eCX(mlM&xL`6YNHHuo5Fe52? zqm$RGuBxX&vM~>^cn#;$;18wbPC7#>f{um`ge!+OaSe-~WthNbMllqm=zqqhEwztP~J%Hi*?%Ybcz25kRor%Dh}$n_D}>XnM01kkn?A|R+#NI??jwC)`Bff|B9QeLme1pau1Rj%JndSN$xtTx5e zSoAd2i-=Cp0^pnEm{!GLe4M1Y%uuIF=E3Pu+k;Yd{jl1J&kC0MforwD3f&`+Xpm)uP#L0i)mTJ&-l*ajin;?zVWCeQzT>}A6P3r#ihCOvi7Ghur@hf5FSziWRI31F4zJmUI`Bg% z^^xN`Q^-TTHAi6DhAIXbgvcGhDG@9`XI2K68|Yp94l=+JE;|AOlU_{j`=ioUZ*KWX zW-<_QT0qI@3|D#$fdmDu4BB2jH!gKCbVk)B45u49@(%Yj2?_laQj$P~9wdEQII|%^ zRRz@En5|(2j`(B<8yvj=yrveSYE(Jk<`1+sKn3w_3%wFBos1l;Fcg}KiLKz#mW{siB7f4Aa$*;FeH zsEHa8>j`G?O=jve6VxM^t=$rTTL(I=KFKAyr;6>wUMGVk%Q5*&Nv)1rZ|y2X@`Deo zD5vUptHQP@M>jAmIyz|==Bg>TrJtxmN@=NNgT%_FFL+H@9ZiG+8b0XhmzeRRKvoEc zghDiSioq!=y6+{jaRib-PQ48W`Fo2eC0Or6A!Qme0(d~k@?ykdI7osGv(eU1|9AjG z|AZAH1aPjdSfPUPXoFO?8Qo*;+z(U@YXm*M35cI}j96HqZ;yydlCI%h7<7*POMV>E zdgvaA+4~J`K&Zv_I%;QNe@YOmPK8K$2USHfnrqUPvMmJTUFZ2itZ#!~K#zW)LqUV6 zU&i{U*(|ceEc4gk!3u0eX1lAY$f6QDUkaZhPypt4;(jvEr$U5xwL`+TnsFQk70t)~ zY?lNsJc0^ILBKY*Gy|3d_54YOfqc~=BOyrW0RqDD$OS!ST!Qal;tFza=bIb*ECc%v zUp}0b@%7w_$2*>QG`>mqL085`D(&93d6AM<6jFiL9uDr#!!o+<4`O6P-{n<=W_+MV zu5*V3cTXVEI2x~O7KDwapwMgQQDh~7t8NOmk+rWL3!jl8v&TfG6#D3V3kuvr3kuXh zY6kV|NJ)jnO2gKi5-iy`vR>tD1;0AD_U@xeQ^|SF_~*XfG=vu@p&;YaBNGw zWkVS~VRjAmPOee_FpislMSRVKECtb0`CjF**=@7aVwYelwOC=<;di3`1dK%uy2Y|k z`dI?{=$4tCbOMyVaSDId;xP>|>j3S*mqiS1RxCEi?x*bTn11-jl$2{fA=4PgofhrF zDwXNTb^wmEekJ)w!8|#N8Laim+To?v;B0YvCG$(6f*4-8WG#itjq1vey)_|j8q)Zs zB}5`trqrLgz|uPfhpoV}VHfb&Rg;hCMvR0(ViJ#)#5w-8s0HL;Y@f7LQ+G zBO#_?mes1lhHZYp+U=8`?*(>^c~p@3Wq#jotk`Dqo`n*2dPn!19-?#nWy!#)6_=PZ z8Nxt(oGdoS9cfGf!rqFqQiW{dA8)?V`#qtQ`LC_=YT|9^{SGv|g03RqtI;S!<$1{2 zWMCDd>3A3}^;|S!?_3Hlo|}7>I5aF$9BO9NMCi)xx%36|?+s(Qfwo`JjWSo!!;`gk zI-&dA8L(7O0tDGZ-cVJ{;k!qe;f)rqI!}4C`E1=ZP+$C%2#X_pO^5GSG6Z_(X#853t$t#0k z!<&a4B~42YA_{fu4Wz(-maP$&CSang$$3BkijZkaKQXcDY!{f;Yce_4o*Si#rdZgd zBiI%fna$g|!fFQ2vpjsa6n;)wEH>v2jeNV0u zys|#8GmPeT2*feoWgtEDD1!7X9T>DJ3zT4{i+H<82`rqal?)$#ePW}n?6}tCN=^di zl!@)e^2(IHDs@5o;Mt+EmB_n{8cMdt)=i(xgzjYpP6XmKNb9j`K?u2Qt#}Vv%<@|S zwLryazYiK#trFy=aMv?i8ONixf1 z2Y|-*7xk&0sb?)97sUBFBDJ52^Gp`<9_P! zdd|*(-w9#Sz2%DaSUqE;-OLT^MVM;oOiD;65RhPNIW?JYTMLLTOfU5tW!jZPl%bdN z+iL}gmz7yY3VSOmiuRFWwADY1^INB}Ne0y~*k26SVmQ%NaBQ~^w>%_(Vlwo^&pDl% zlzey0B~=Tqp9l+hxZ1dcIVNCn2&9;3)kBe?)HgXroSm=%0xsDU@p zQ>WPs)!3C%<}^O36fzB8?oBhh3Wm5UwCf@!-KMcM8@S7ReR?G4*O-8q<7H>*q)wB_G7O)D z22FePM(3Q)V}RaM9rkMgx!z65|=cemAJA^?&p>;Ux*awfV>2ahM89M8-OF z*X&R0Hw&ixbj0i=*{`2Dw#e+MwRJXrM-2bIMI$Sad5*u&O;9kOK!Lh`4hFyQi8*kw zDh(n@cl7!wgkzSC{=I`jY?+$;Y2D8zXqll3226uBDvCKxYp_R5XF0lr+ihAyV||YL z>7xeMbo-~%p{#PT+^stNhimA1SXOT60JBa=V0+1utv1>nMa;aN6UvYAld&rP4PwZk zeXc|`L(HXJ6zV~-5XjKmJXeZ)%;+Q{#qa)9DjzJg*Ge5ks6r4-Fs9FMd1>IG5avNgsc0IzmpnNFJJTncKt? z;T;q@!dW?!@@`4Z=T;Qsar<7h!Y`j>1~?^@$?i41XY*_Z&L6aq;SNHm$fD5&Y^d}xRgsd046&+=bFQr9571g@W_J(FPD7;S*67oYbhDb#naXP* zhR`?m^B~`T10ER-|L(hGF(C4dL!7dOmk6Rb-##(+G??SY4O2J}`B@&p)#g?!1|zq4 zdGe~hm3p#z2(zIlEw+$Da9FjNY1?s>(%CU@hp&YRhHIi|3*zRREsYLi4v9}Kb^Ag+ zwEWyJDod5`Bs-#k?>b9fd$?qtCK%uX)_@~ySKG(8m5)pJo(gJJG2?l>%hAKg6i7Mg z7b@^JW$6>(&u)byvV~9-;JOZ@O-@5LqCASB?1>{IEm?Rw$ zuIQ%7intQe50k4@_-v$RZ^Urt3}zYiOuM#37Dt$HErDDBRS7W>0l1@lKR>$pwGDor zT$`yXV7P7W5T1mrBT*E+{MWc~S1n||YuXK^H&0U=6{Xn~Kj1zT$9A$xHmbY0@~>Zv z1(*~YnCM^D`6Sm&P3Zt^^3)*4AOqs=K$?(Q3mm zbnK#$`z3Cv;bTxJjZN233TsPcOg>FDG+Jy{u-eUhsbhdzY?#=%+N{V13E%@>Kd-1T zOLI{EpCt*;vI>p*-J#Xoy+>2Dv4jt*hKJa z_cfR~u!0@U=~z=)_}RGkC$HBeVO*-g5T`Aw_+lO@*`XmzVPnad@&g*oVPXP@VW zN;(z9E=AeOAMUi3^vjBk*dHiJ&gMcuoMpxTP^O_GJc4zq+>2f|Tf*_TI?4~5=F-OMUVj`{3s$d0Pl zgTaVHZLNGipC?G5?;q>H%^^|!06POnNqVDQ1)Lk7*9fhjV4|$bO)%2?GD0k+ZC809 z3dVIMrTw0~^{!~p+(Da(!Qs zAD(2~4Gr&cv>7fd&EVi28Xs(*Jwqzo0==d!=&Xdi1BZC|+hps)IcSARZmqZ;rEAbv zsG(yb53~pxCyQ==ILPjjPtV=CShT$q62o4c;>iykiz5!z&)iVl zJ$BM85|(5K(BY`zeXE==%il4Q?`&M5T8iyJX8t*1*z`+f`V#<##{a80k9xX%-xWKn zdS`M8v%O5PnCMOxi_b|DU?7gcdu=pot#)P~byE9#&0%JhW9T|mm(h%W2>b=3yzwyL zl(t{!US*cW^v3KhGuZbwby-iZq((%3rC;&tQV}GRQ%PW`EZJS<+-_E071t4naj&Ps zDqd46`aG-W80ZuqUYb1{mL#n|`KLjS=&q|$yJMWq5KPeUE6f~$uU{8h!<`^5OB|WC z-49+xN;O*r(33%(Ei&$9D@dcauDST@DfpJ%MB)0-W!}X=*OId%*uTF1C~?w%lhOFisErVZesPGCOMVv^=xrMv8a0?G=BZ&mh^l znCFdM-JtAE%uGd<`M>zO=OEF!ZbA5MoVIP-JZ;;yZQD9++qP}nwrzKx=GV{r%r|rA zR^3S@`6HEN*RE8m)=t*`tvB(W2Lz~1xy>U=6i;x2@tQ>y8nu}%XQE#;Qek~`N%G#x zY8(tIstK{yph#(kLSYh$%DeUjo|>8lY3e3z)6}*S1DQja^6YkRYfmOc@wVMnPMU3% zc9L5N2bvfAsX%p|JoUyzC8fp2Lv|DUpP?bA zgBR!Bu-GFutqR2hODUV^>-N5XCJ#u3oqGzrdV7DNmrMTLM5e;+g3~MH0q(xintKKx zgrn@$>Z1ek8@6)HLj|$-?uaesy`!s-4Y5KW(lEV9F=psJ1+)ZY4<`bAKZ&dSs_5kS_oceY-qCUU zNAP#(+KdyCVV^QmdeyB-qmtMbW5~f&R-wS0cdxpv?z>GrgO_qx$sOM6Jr^CxHt6^K z!vk0`H%H@D;S575jp>tnpIOJ0SZjkW`G74_4d7W^mo(L!4i{pIfdd=HODe1m6O zd{-nRi@x}Q>>i*F6{x+ZmYN(Q#W40uDyuMuq_enbnc)>|xvX5Sn?DRun~@nLUw8nT z)aLpGC%I%=&*sdl2fGysmN@|%jQ$s`?inWQ^86tro!BXG$N7P0~$` z%PDIG3MQO5q!a6tD>xqLi3T!U?P;-^I^=ctrA!uA+!rkm!B(pm8lz`Jgn-<)8Sjw3f@)qzEPesJp?Nmtfh$?|=k{yE`H>IH_@vAc59A}fLz0fWU20m+ ze*3jaXiXhc%25s<($gJOh#u!C zjUCT-GWM7?%hFdLif3SIv!f*)AxC&vq(QyX%$H=h*Ca-)>ETc)dg9twvuMEf0^6QV zhvQfzDl1l*6H40-TG{ElOfmA({pN_a?<*@8HO@^$&snE`FQ#p5&I5L2zyw9wEmYaP zt>bJW>;^|mCA15Y5m;jT>7}cavO*pqb#@f9YTfEzsIxp0_^Gd;*EkI{KZQ%Kxkp`2 zC9EZnLnQ`i!p{(0+Q0_9VAAIoCXke^%PCZNiNq|-+&Qz{7c|qEQBYoH#WclW#62kX zrktw`F9T)0i4xf+b)y*1tfwfYMb)qkVdaU|9&!IUn`bTr8IM6^#V1Q(e3qq_Cyko3 z!`fb;O%qW~DNeL?%k-|*94gAlQGT|yt-sL_De$#VF318(F8Kd^`bOo9-_&l)Xm=2zgh>96r#NipUj29MYVyEQZfy8`)MN}Yx5{Zr^ef-U zw16uc%|#Xg;Iqo&_hPqiKPl@QRh8l@V>gOmC=gaZlQ2{DUodZ?#}!H29gtsF)lv0= zDAXn#tQOXT##=Ay@y)1cCAbDzUybI$tXM(JwBBWfNxnv_>9}Hpcg?TEDkiJEJ9fTY zGhZvh7p%`Uiq9nt*SuISDG!%;7a?qo-x=<{svTM$p)2Xny3N%mSHgv!8|`gDk1F%; z$8sOXw;kgPL9T}`&eedOmNgeQXHH2*nFA;5hq~qpM$%<|NJ_$6=>oNn2VFVwrc;j2 z2SnfV=fxhEsDl%=6V!B_0bVR5IrmH`@zbHx^cSwQmA`itc-+qGB^7#UQQYNCyguwu zmU5`z$Yr1qrzsgnQ_mfZX zRLqOwSu~RV-Vx_RQ_X>j2+>dH&k(ClpQX5*6D~*xhtZnM6VjcDjTv;BT*qKB$n8*T zVd>XleV4}aH21(m@4!)~e)C`}`LCV9|>Es>~bXk3>z0b>l=ZCTRLb%G_-rA9^rTAz4Du zdr&I5TNQIO_&|8}kf#ZyL^;dOfQYHx%7V&`!0+9%qU+h3+z!Y_aqkGLu=M3LnzP3j?9K6tB|@bTqVhjG)r&SUuG_+myHPK9bhaf2KbDK0M^~UXEgG}Q z%S(wQKLV@SjBNqq>1d)QF9=DxuVD8EONSztya(0GZ_N{xh*S`)Ap$v3$~LgF2H~iA z=D^FYEHXD`>TFlcIh1!bwNR~8bN6p4uECf1HTtmf!G(g5tF-SVL8nMdpqy7298{oU zft_EyTX^}i@H?1|in1DHrDG-*-^eo;tJl~7zbryO#R;f!#$vNEj2b*+kv#bj(W%wa zPGWlZ2$-1yd?}Hs51>S%?J^Clnn0^oxI(2ewJaFCnrT3p8er{MRZ$pvAZJtonPN(63JaAFYXU?y!LBTi%ebyvG}i}lOSR57afJ{GWuarQ zoN@7FHwjc(;J$$y8xmONmAoCF_<&uiipN>99{|`l7dO(J5lsLOc4L2|h9f7k*Cn#| z2_4FeD?L5<=DOqk@~OMRswNi`-|#RG$CQRy91>cO6XIDDy~w7bn4_Xo7Bx8viBg&5 z-mJI9sfTr2Op)5LCsk4G8LWC-+|JW8JuP! zEupdHnA=alEiY@iR7uKLj6^Y%du-I;+Bl^V!#8s^A)s($8}_L3Qz}8 zxx!P@Yjs9RL;vIh`L}9#l}FQ1hj}2%>b@3Q@5_wey%7-f9$X_OX<74pD7y1VExpR# z6yW@FuRDM+#zo)iaj!u2x9!tIwQm+F53DGtDIsvdQ?wreMan@cv-5Nye zcPm9P^k8r8K@eJr)Ge-#%(Fz2gSs4TM$~p2;RbV_jq@7#psCPv^BK6Hkfho_!s`kOn<+&z|=l2I}{tS;v ztL*|K0&cVQxZ1X8Zx-CE@@Af=uw*oOwF5ohol`yC*sfPZ+~;7>#NgDS{9DLaf3 zsny(7ZQ?+7-P|*D>1mOV+DVPy;5hs*#J@rBewoiB*xW3<2L>u)B8Vu#z>t7$<;ZY4 z$5%)1%O_7XrhrDO^$3M3__7m_E&u;Hi1Dtor@CL`KIgaq0m0cef6nbb%$9Rv5f=%F zNGXV&+Vt`Y@aD~s7n&rOKbIc^>>Fvjo;mr0_hXDRVZ+}#>Nv`1w>kN^52*H%zJ3hI zU>Y6*6GpB}jj%3iabp$mDxx+>?}kTa4ywTtsjVnW#tIcUil?$iVpCvR@cvthBDo&w z5@|`p)j4a;<0lsE8C~vepKB3HGjg5ttl6QAcC)Lh49Bfj^FKH@#nRqWsTOlx z3Jq_}PC3VuuI4(j<||sM>h4~F8;rJgip6_FG!+k@`pLuS8!H0h7FB{aCbh%AX+9CE zw9Gi(jgyrr!D{XvH7hswINm?AR`!MlN>Z z#Zu*ooCOJ)w*EgUv_31p#sXmVwoSrf8tzcSOk)YWXX$SZtR=Yc5-+FY$wiAGJ3s## z(wVt7@=*GE+Wl!<<|IkAt@l#iNVNxj*R2f#J$-SnSmlMy?)LfnYNt9Dkn2X=5^7Oc z8zkyu|If`+g0V7kpuch7j)+4z)0NY4^|p5v1KxleFXC)Vtq*|XZXEB zeB5zL5MZn^QtJ0jRxA4?d|0KJd7xP`5$ zTG`gx?Q(ln56{EZqOWtoS>vB9z|Ydbu5C-^JPPuy{G2H6j*SUOiDyguR8eyT`@`vL z*cs*)RhD5I$C;RR@R54EyQ<&xBR=9)U@qWPR2e4o>}VVaYTkG7i#vYbzmuTCfL@@L zYfKfAtGdKI#nPTnbEwD%A<5AdZ3NuY$P$ye@Tu%l;luG#NE{4x8*0pxN!#)=SJUO1 z*>bM^NVcix50#3M`6hy;g56+S_o}$b>@&-Q&?OpRPcbz`!n*!f&KyVJGWUY>OG}m8 z&ezj(PC>Nq9o5x|(!A+x>q*H*P;{mp zr3=E%rvQ>{gN#cgnx39ZSI#!9*e!T2mB(C{tuqQ2{M4801rbYHr-c&^&h3^j2@MA4Dm&Igi^4leo;)(=*Uy>TVd@7^duR;eu|f>$ zlx6L|O*N`{_e+l%MLESm!X;oMSOr|A;%I?(Qv zk-VxvAb@Ym#DF|ZDw5BcID%H_Y{N!5QW`Da)rQ{ zZ5t2h=vCuvtjy)IrB5Ca1#ch%liW~+Z$VbRY>iygLG^|Km7*=ERhn%4(?QPCy#RaB z-;4Xch8u@cW^E$lXN#S6a}K0dS{KIXST{m|105(0#T&_JCA&BaShrPDOyi<$8m;y3 zQ5uYN!gx!@S{;O@d#UH+X2H<4UtJB35m zVJs8GeIBF~cHQUeD7JP`f*v>@EvPESPeGz~UP~$fvSZ~B1QpDh;0Ji>{L2`vl<$(v zze=ps;?qXepmVbd!_xzK3W})-MMrofL~OSKy40tuzuioIe42d)TOyk!5jH_H`?cVmORVzx~{%+WIK927F)z)UWIWc|OVsE-$G(XsX zA?aixJghF8E}VH>7t={yGA7zEWf)UtGfLNvx~+P%><+6D>C0F$et37YMjj-!>dt%+ z0fc_DyB?2Hycy#+`S{C~vy$?|NM`;xa!dZx{#+VR59dN2hIW58Je}=M*=<^Pje%Y_ zj(ofv)R_K`B6g;r6!mFllRCqfJY<_}pJ`xG`sVh%X5KeaaLAJupu+*d9X4`-i!<~e zP8)!TkqSc_gIf)P6PT_H%HZ>*b7u~xe!_VewHsgo6sfnrS!S9t9!I_5mN;Rfty@(=}gyZb0Yy&9zxjxWF2b zVPP>M+2h$xrh-&$NwBM`hn7fsb{&mw#ISL=Mkm!$9Fy;lQM#2Ct=%OSf^F?TOsZkf z#MOd~O{Ytso?IoS3QNdZ9py0tmRQ}+%3Mh+(UI@qTB8B zr8T2eQBz29XKy?OiEXWit<$^9xd)2I{qxDIzad@FQCwciz#5gs3=ae2W?%cy$ z>%g!q%@x;Uam=D32^OR4`5(RGtc_c-DV)1%9`@hwB(_B~#oQ5+PoEg%*W~xU@Gvzo zs7Kzq6|1lN_E$~1epD=~Cluv(;%mwsiP(Ra%qV0=T`bwMt7e5MtZBySsAt3Qaf zG0|Kt(syCc!B`rsySnm&vxe1Z?LQ8(lET8w6)I(Tgnqg^F3)2Dw57Q&3U&Z%8*kRK z!qi76#6;105j>=aN9#uxGH{;LS0w;G3@iCgTLqW2N8Wj^aan6RkSi5!y>|=nYWCDH}u=ayuHuuni8MinH41H9Uoy$4Y*U81ItYdyIpX%Ug8S-*=`dTURzc!fGw*%IbI$;-phXw!0t6_5bv z5pg941`}zBOicW~PBJ}Ebi~SP&|a_KT~kVkn{1K(+swjnLSz@Q1vuxD<0vDFmdJFk ztd{3;8WktOGx$tfBht?m+X%`_3RccA|;pb21Hqrx=M299j_gNm{`!}uTR!Esjk=Jtr~ zoCq_qv$UqB_Q-q2*oril(aj{G<%%R$8-~dU?3D7ls@uXC|Hzm{fc%mw7p#)p~0hRmkP>{8keC#3)Dn)Gb?B0krcM(Zq@I28Gzvr zhmBU!;*(l4`G_egY3Ro8QRjQUCVG}1yP$k+*{9u&sqSXfefIBVc{RWHYw~_?muUHX zG9E;zVF}5@#9bSJI>}p&QWOPG4c^CX>qW3ET#vGV&V!9z#-IzoG3oLd;3t-{^3@_9 z+~pM9*YU&Kkp@bLIrSolGVg(e^X7Na@$&+6klqOdR=4(Hc+u5gz~R)fxV9$S_)K^; zSz%hd3w8DK=mi-Lqt%u1N8Z)Lc21&+io*#xP)_GAH4acRbrN21)CcCFtnoEPO@(7B zww{XBOE>WU7wzl)I}HJ5_4vU)!jUP@7Bzjh*;G zq38xF05U_uyfm!cgHfMVkou@*s}Sck{O-s?Xg@nudZZ*~glEOrbCHn8P+{(zv|{I- ze+sx15s=FF+$xoss+3elDZ6lqP-@y(QutckMXluH5SL=*lC-v%Y-@$;Of|Q{VI$Fi zGmwK3YapFruAauvfX5z4&2~a^HHAFA+Nb24VU&cb-(Rm>fM|9go+EDHen>j&h821#0?e+Fh2)^j@lGfD5)et=IgJa8%j26LjlBTT^UtF`7RU04}f)=DW2 zS`uqyMrC%9B;Rq^lH1&r2QXHv_cxGGa>U&$-D|N8+9_#)#3h%lcUae7e7>;P~gHVVD7XiWTEN<~=us0j;egnZ5&20bBqI^?h2|af#@HMy$TEOrXMh_lV|wI|dmwqu?SZu7HfQo6jsYj-ZY zD}Yt?nNDf4yg%$(cV1cTB`Wsr_pC10r^wWY8(KNIeVKwu(Z7i=iHeR z-V(aH>GWVU5|Jk>l;BN2;r7U#F;bHzMaj*Q;G@QTEu`)~)uq{AQwz$@1pR_Eu!@cf zc_C>DWg-R3qFp7WpVL*>UQL^2sF(1z z3?fY)N_)M{RtMM53So3pwJXq^EfUomRIMa@km|(Gdq0uy)^0|`?l9?9&P`4%EpydY zmwZt>L#ZU83+g*7>nplE(y~~gYHu{DKX31nw#e3NveQu13g?QD5QBKpwpLWQqw@O2 zJ_ig=g3H&Bz9)7q!nyw$6kRQU1$oKBhtc%02S^vQUfGdHvL5dE`Mt*?y*@!VI@ROX z@OhxayvjJk>oUlW=_ItR^IBM`b??LCUY6diXw@bS3cd7D`nS1Zt5In6 z!tx3nnKF@AYX{jK&SLf9ok%;H^)xw+xp+_L-E1JS;BAhwUc5QUPh1cDil2=YLhfm% z7W5KCfg~1ro5Fc9dvn58jX3P57Gt9xK7F>}lgDaQG#GkiHBQ?SN-m&g3hJus+uYUaA!MPqX8_d zumalit!GSmb-Z?`^Y^cvSkPBfibUxgG< z53vuBT1bDpCN`F(?baoMju5um(=Vl#L!IE|zm`?pJ%E2}LlWLgLN$H6bfJu#n{4_j zxsn6-w$iNU-qWx*P1lI&CSKufp!03d71S*lfQh@8Y6Zby#|Q@R%!|C(DVn{rD10Y{2 z?_zuuyxoL3QPnl#)sPoAC39-;*ZAmcI8`q@2rQE`L~5;CtFS$ar0t;`e({w}DdKS# z77!u2ucS`$807H_WgbU2YUesDD>5<6Hk@yh2R%PD=jw0wPRy;OvowIMIBgO#dPk9U z)qNPXeycyg(F)n2H+ipMu4DHrz^RAyBP)8*HQ*wUsHR{*KjW63;;Cn7L*Jg4CZ@N2 z|JPz|e;l17l4*aITprf~5qs-t73`_etJE5y>gtZH3{{jo$jB+y>D>vKKFX7&diU4k z2#A^+l`6`FoZK|~ zda<;qzFcqSZ8WJ-@d;Ee^JJw{n9ecIL*hP<-ofvxp9C+=JfCvr z&TIDFiax792RiyxeXsl4KTqB#RGx?^XMYExl`?#t$(q5uE`fCT4v2mHp|5?tR^9L5 z{XE0`QnfGY=?AW0nvk4uh6bu(P0A}CI4(H7q!!)KySz+#@5M(xM9}Q41BOcx=_=y4 z9n1EXy}R33Dw;c=@AdGCj*+bdr{Ho+(SW;`BYIc6S{t5+x={baB6-o5N7-2Cq{sb* z4)ogKZl>PvM*}ZHoGde_K%ERbG|xLUzhNB8+8_)c%W!D356&3y3HjZnqJq@Yt33!S z_LI%fN6QVzYQh>{R5%viPdV{{42Po-GCAg!x!0EtrrT8J_XjHcH9$a;M9Vo?Kxb8Y zm+;#HdVN?uTY5O4S~IqHdcvV|?m}Bf$AyWUAGBTFXL(|tKnYJ)CVYE+-PKp~{i~zr zv+AXe{if`=F#f9#&8kXg&@}; zb^eXN?O_xGCkakWM4=l0SyydNn7?o^xpL_)2Ut$j;7-AZR3~tV4$9n^IIb>n>SJi4 zs8ackaL36+rPDn*4!v|h9x%Vu2kUsV@x4Us>#EAoaT$qum-Lg159 zslOsei-m&S6SId(R|Xz_`ghgBKMF2{E6njrqu}p%maNna-1F#Or2P$6; zFOmFiypMr(p*PQz`w9Q}d>F}eV9;Eq=EAvehZ4L{ucj+fnJmx!xZ!1SK!S!ex6bWG z(*2FfDJVD;pQrEyU9QkMIUkc*2?sOncAFLw13psoK(xs3`OH=k$q|JH%Do$hkdX%u zy6#`Z2s8!iWOLxX-{TEt3z)>ku9OfUOT77Qk~IG4Kg4qiNG#L(?OfE-(cq`mg9jwe zRp-+Kbl>%RTPT8bJAU%%ss%+1&t_Y9ZA&_|;MIdHr9>t~{w;k?<3m+>)mpL@QQl^mb zJi48jZ{(F^sxWp~`wRX~d)?R=zV}VoLd8`*k(c(@!8UcZ#u`#08(T3~x?QD~Ncht^}t> zlMk(D9HhKdnR_rr^djpf`uAnKCYvNtG#i$;mtPGDUxW@T)8benY)+3z>uT~G<5Vb( zvKfS-AzT2%40W4xd6hAb1FyJwO>#oiQ;+xeXVfeVftl=Hj}MGc!S6VTw{|H~^S$Ae zpuB!4-w+0q(swXV`5-fV+Wun=Y!#vCUB$ zScIj$Hb7vB7wz&JNLR>3dg@0b96L3_J;R@IYC3$Xd?_&`jm4Qp5?dv%;1<>Tt^Ijq zUU_ellPm6}uk9mFq$F|Xt*-3tRU{QA3b#|tB9c9AE~#W_4zUl>n7qw}X|19{Pn1P2 z@`K3Pen^u+XV4~7L`O%Cc^Kxy1n~e~424Zo$QpWPgd*4qDYxBy8G+D>?T_b0R)0naD;IhENl^H3FnV3cTGZ za0jHnE^`y-!zI@Yb((oh9We6p227zUSmqpyNMTeXc>J)?HIbMPs61V0bRNHdDIQ3-Rm$XJ;dypS3J`8|K5r1y10rW4n} zOc9{P=1Ev}GrxhnutJ5nCem-s@7Tc~EMj$|&4F{NNP9q&Q=u`?kd=t1vsYwE6$2`U zlrUN&R4%02uRFJ?u%s96xhv`GLF1$#>1<4^&bf7Wz0Dk;FjfK|S@eN^prQO?26)B> zbEcq!7Ar1PEVEG%ZdZVRB7%H$Tc{$9`y}D~-M~Z~v20dFB$6~)%>;P;U!36TgT)XN~x}rxh z`t&rtE$WgEvO9NHchkklv^>Pur^v1sZo8ythW(PVX3W{Nrq~T2QU(1X8t*A0#V$L* z=#jM)@slk@nFSyyjrig-%TU?o1S5nldfzVo24I9Q51y{Zo9%2MMqlu>&aoGc^8?3a z8nqSk-DMRTfdlX-M9uxY!7#KGs0weu#&6k?^2U1HuqR>mZV%$H$Bnck5VlXr(Qm(H zXBNDAxISJV>}v>p8sU?d8cWqII9N7L#~MmZez&G77-UIq@v|sv1V;9AZptX&(ITB5 z&&Rj12rex_TD=-TMt+B_PX~d(LJ;9v=Wuy&h0XYQHNSri*gYC_s$xs&d^`O;KEJB@ z)^d0!ly^e%;Y2Luym7{MWRWD_Ei{alZ;~f-bB4FGoD&n|@;!nQMMTSxk*Y7c9aExh z{d*P|f(MA`)%XHpXjEz0_IeMC=qR4Y%u^IE^-D#ttGL4;MQZaE(^8Q&37Kx!STgxg zpgZsn%?BfUdOvg-^xixoD+to9g0rz)XF^ri-PXqi0Fiqa<-IUV12PKt$JSf&k)4Gzr;;> zX9R*fz{x!68RncDvHnVtE6AHx<}aMVBfCTa;PvRMdT4ba;9jhBNbh2rXPlCswO1}q z)lE^Fe(}#tlL7J-2_1e-YfpABo7iS7Y<^rk@$kaUT?@Ej_exu?@`73OZm-HGBBuQ+ zJ^Rk>NmeppbWRR25p*Vw%)(dGpgh`JvSQww1IVwourqChDDv9*fLa=YUa$+UWIeDy zAjCa`98%g}u(z*JeAuO-r&s~DxQ9qVA3XUXvfqfJpW+y{I%?!1Xp!cFu^68(NN*^{ zzG;sMoju~W2Mk|hd@z2z<|2Gxzl?TlU*oJ^3H32khaLZdz>^b$jm`EE$csUT+MnSo zNJx#lImM44=1BQ~W<9+gHKw@jjY`qh4ndpgt6QyQ7iYGXR< zLmhSZuf`S)7=K3Ew30nvntwTgqEDmy&hKRsJdjE*pHpAuB&EalOi*-9HRilL7a+${>O~Q0;q==FTQy2JBmEvQ@d+an0Mjg-@#2 zc285H=IB1k&f(PH(UX59EZ_}AN?*3!2mItD^M7L|^S6gjaw&XkuH^0=l?KA^0gM#z z0c9`y0-SYt$|~?CSrm`np_wI?{_dN9H1`tNRgbiZar_c?{_bo2HWYBM_H+;dQ1|OL z0DOxFJ(byP!Ez(UN)`H>WJRpHlUMZBW)%TiY)+Frr9JjcDol|fsATNE2obQNa3&0kKdDtsLkXM%=PCd-#0O zmeHu7Wlync71)n<;w3A_-&TwIdk-Yh??yPYpc!`m+UI5Cdfgy25*qlm>+9+BNm%Ih z`#&_>92EnJtTX_?k^|uX1Bv@DUa7pI0=sYD}q{nqhb zJ-yi2^!DaLBTw(oFHk5OVq)e>HT!}x^SfvqxZ{}}-~GV|C^VhRb?5WGK)4#-kJ*_` zo7Ap>dc73qIh&Jv@9Ly?Bo7(lr>w~wpJwy3q%kbpsV)1L$*LB*9pCT!&zH8}H$2|& zPk7MiW?;y^_4GjEU^wvLhh$*Q)xb!2z)uUW2{6w|CXnOcr$q4gvl z!sjrV&Sdc(jOxMs$MptleJ{cR1OTx9+5TsV5C6x%Gq=_^HFl)?U#_>Ht&OhGkA=r? zXzb|tukI}j)&BT@>E1sV{V>P$^m@j|RZdPVZf>oM zqob#@v!}bexBsHpi+lImr%(Tl#@36UHAt8>N}BrtvQ7SDWSgbTTcj;0CI^0O?w-+}e|he$-+0JLigC**y!wN=RjwBU;7W$-Q3mO*wOd{ zcGtGlRyS4W7UyOcW~XGOoZp{sA8-F}zk6YQVP<(|dTDxcVe&`u9+@5)njGpM>u>FD zt*oysuPraDDZ6^S`k}qgZqI&n@5773z06o8`|0)R@#XRL?e$;d`|bVhhxwk}nfWokH&1`m@*lE%W&7+0 zE8o~SUjHG#_b>L2um2&xI|n*84>p#!mgd*ye#r0bqpj8Lm4&tWk*VQ>v;F_BdjmuK zNB3q@B1XOgJP-nhM(51*+bakIp)~zh_vWXUv`Eb5`$zXCv7iS0kM1q!^^fjN8jQ%3 z`=fg^gu}x8qkHEP{hBE-3i5*=ZzP2vFp6#u+Rvu|MWC|#fR7IrgU4f#Gb%k3_|d(k zxag(t0w)qF&7hMZnes*>VaT}YIV|C$;-L7M7VUua$uKDdP2xNCh-r5KOv3bP|L_kd zjOa&3lK=4!!|1k-l&W?&5FZ`^DmvY@Dx6X$EihjX^J~w=pdl19SoK5>*GNbAL$0>I z75^2FJK0@1pMMNWPy&;EkbHuZ&mXv0hC~c8m(T63r2h^4Qlpo6fUKdkMp0NCjGt4) z7BLtqm(L#ni=$CEI*Th9e_1#3JBt}9+7j5?A4puF6ImF7#3^%xR0Gu$i zaUh5A?)626I93R8?04*;eiR3Y{T(1E0s0XFX2o2g06JLG12mp5!2A{g_H{`ZA<()$ z;U90VdojFdE?`)GF*QDa*l7DhP&s!BwposHDP@(>Z>9Dxgf_fPJD!&h${q+Vbyv3*4+h{%JlzIr@HNY#MnagtX>4 zXo6tq{LnH(+WIixxY{?$%CgeP!AHiR4$8j<2h&2FU=zP7?z>goj z06-wXBXmj3irE-+a`^rt!m}X#B|u3BVw^$jmm_Jh#Oe?EHN}Xc!+M5ZkyNRV@gr4$ zhZaF1?%BkG{5$yjjFT=>mtkaXE$!ir55K-|dw~HzKK+1Um~;IAMy=+@dFHGXagh}* zK!BxT5Rt)`&MEIYL2R|XK%r!c5)4k2`$hoprSt(JIJ3kDd{?cLBd)P-@qR$T zDYia;3v+zl_KHUpCh5Kg@1y~&NA>(g>XL-6`2y)X#kQiw_<-U0dVw%w{YE6W?|-Om z5Qtsmdi)T&kGn`~2qT%-f-yTV#_|vfAU`0XUZAuQK1AGVz+c1!K+*^iY+^)kGqoXn z_d(q0QepVMrI>^~uO0A=H=)1i34p$-QCTAy_%I6L!Kjq>A}t{b!BI+aq;pAQ`G^JN zxS)3d0!M`j5N`n>*!h4FW1+ND5zr=bgBkq#BHY=5v4G|PA&5nhD3FQaVGaaQy;p_7 zSZ^crk%=%I{Ua0?2~ijP0-041LP>uafl=yVNw>=s1#u|v5(YyG=QCx z6UIrOgN6#>2N9yjkam)T7lH>83pZOPZ9AQy_h3qdR0CrOWB~W&6NH^HGiGW;@PpLL zg~B9IE6GO!5QGwx?oxBYdGT1P(2P5v6`#OR2IFW3)W$_{UrRVV{;HpmTE z7wUZK81eCO%rG@yeoV#l}ZMrNSFX} zs+l!~kvx><>ON{qsW4GAV5r1k4Mu{n8CJ-y|CM_oH`y6~Qe_=DgY-V)ZC4P7xPgYQ-!IOsDA#O5T%up z)7x6s0@8GWu#zzVauqB?|2Aq6N`e3-V$6e-iTyFtX9uYQ2*PzviPCtY_BilsfuW7| zsPo3~K&5i`eeDju5iV;3iQ_lIRgnde(&e>IkuB%?_FF^I#lf^<_+tC5;w0 z{lVdcu*+iyJ?Q|!Md$_4tKc!Q1@@p+Zu{}d`A%2{@8Bq;Y#^HMp!B2+0C863@sC%B zDf#68NDK-hy1atWIZQ$62m$LzHHNTl=7K`#`?CXyLrKfz20itzW39#xP+~rD%+3v1 zPCbgS&)Wh2vg<7!MTJnds1G3JyTUt}9cD?FpLORhz*v42VQ;nuZK~B9+d~yoNOp+- zl?wnNOMb^U%5N7?!w=0ciVI%d8{&mENT$X}1!+MaMCt|ztsmBlmZ=9qRjNmg+zS9Z zziSsgSg5B$NdXDz=64hC2trIK&H-sgAHtG5bwtA-CV;*VA0`F@#x?o_LF|TjfrI=j zWTUyUb4&b`?Gygl{^z(H;s3?2xM;dKp zo_&f@X?4+UM?K?Yz2jDW(|7dUn`x3EJHSnf zHe=?r!C=a!W9Rl&V>WvA=C#vjW=HbN&p#kAC^!fy>`!<^WK?t%SX_KUVp4JnND_EP zW>$7iZeA`_VNr2OX<2z0bX9dtZCyPyWCqXIFO@Y+wJt;Lz{@)<_@Re~9oDlk0u?%w`B^1<=R=`Ic`&eiqJ?cEK^{S(2zPlHkGdqwuAixU6O zQ4;D;@BdZ8EgWra=>FN!Sex7Y=-^$dx{ev_@V+x8x#=Ci}iRB)O^C<*Rh27hDm3t*xS=tV- z_Mf`|E5xSKidj^)suK}Zc8nL;RN2&mH><`nN0=E4xRe(n7Dx*~IXT zq?^WJnM|Mv*d4R$&RxX`Gp%zTQf~NJtE_}e@y!Ex&XK9Zjg>s zhduC+gwgJPvvgJG*6rlT{@O^C9LpP{6Olr6=U@Ww~FxO`y@hOm;CF z!&EPG&#vS8W|QmBv0@h}xOoyXHkx5(Gjf2qc~ZRXjS2mYt?kbct6Njm6x}A_aw=0h z%$AuI*wUa_;>m5#y+ujI_5hpX`jl~ZWah^D>c;dz|4Lkc)IRFH%i(bvd_7PBAI7%# z9mkEq|7TOvh@ZzME?SFJYz~R07nfR{vD8ByDzAy9;=m{jpC=w zK&k(Xm-c*F(CmE7i3}7~`OKKauVat@kFBb|Q^PE4)SdbTV~3sdj*r)#S&eVY+rP{-+g%^{FGgF8+0=2{e>`43;7` z1$nQDkYRsVBS*TYix>#D$-_Ci3q(&+EuT!%oAU5ttdTn+jzBYA$F|~#&dp&wCzQB1 zid1;qkdpElw1M#25@qN@dhSop-4YMV8%x$lyR`(wLVod#2)CiW@-n5si(3H}{qk@Y z4s3#kA5zzg+c2FbogYinEQ9KytGF93of2dHa^V?!_1h^py%FB>KKbX)C^Xy6$R>Ip zT(FB#MOD$OVf8%N)7v|?wI^n13ayG}`vCy&GA7nzxf9fe#j+Z=*HZ@y+QRwYy*OG9OJw|%;XXBv zo!=R0GM~xUj`WHktgEuco4aK*ATx{MVq_d3xQFF!QW2K=0;&o3j~=0~G4p9JV`SIv zz|WLaa_3SKeNU8f{pRr$l+5YHH+A$>B|$QYV^9qQ^Lh?s64{_SReY110&+v}!%q%l zxI17(VSiOr*%J26dd0=Y{z>4V!_YCRB^^f1$7sB(fzZ#J)yjp2f*t&YYbR0#Hbt&* zK4xK}3$-Svk$@BV4OhxpkHao5{Q7|Xzy4#poJwicZS|mHas5=Jw{0g3;0mp;c?%oF z=3O>{C@tR)3HD@Z?kKzIx5wCDT-rohA)HGX`zm9wEqoay{3)OZfK8i&BGmAo^titL7i1rwa@dpF3Vz&&ZMH zM|KsTL&Z>2aA1Wup9`h^c^dcxJ!+pwd_4!ry*^q!>b! z>OC&JbupuR=2WnR0Rf$GU)NRsH&D$CZmH&vCWP?_s90gY+DaMN8w#a7LQ`ry2oKF| zxAyKZvSEd^w`zYEBri(!>HVvLN4@OD*PJbB!`Z7IYA#*siv+(Ze> zrpB|TGXU7rI+OzoE(`P zEiG)m_XgHX)+RR24F6vvgTXfq*pCMI;Hhj68K3;auOA05i3{mAypBr+c9Nv z31ksvu`*`P?Oxi2t96hjv9H;N|JGUx4t1I8wj0#eC~2sBXJR0k}wGH zHmEQ#jB@E36kxv8%c>EvTPM76n#Hz z)%W&)H;oX#TmQ#pX=G&Ze~=;n;|q?5)r!u{o>vv|QQR z=(u@pd$>87-0-}5dtV{)IW@E4oZL3hsGVpxZ*hDTSQ-C>;ipP?lRcIb+-Uqaei+?y zeBJ7Kyu6Wm)8qRJeBaD=&F%jDPCA2c{1yUhVB=t;V>=1q$K`&L*$F7o-A*MQbJa;3 zg9i+OZ3T(s=-{hqcv#eSFO7Pux7nG}hxnG6N(Dikb|S%3q0uc|+%0e%qLses=~H9r z7h}Cc+he+lgv;l1)7uFXLkp9Aa~elH_K+R6s7A9vG3nV>msZ*hsg=fBJqFHRo?FXr zQ%zcH8{F9YaG0#DcEwybCWl<-{r$+jy$sZRZ~=-sZGIyz!Q=)Ojr z#Y%9oir!5|+TT_v4wk~EGNY9+1>XO?X=uc10k`j4@&Nq5X2UmU=6_5x6PNGk02AQ9 z=YAgq0sGJHd-=c5B;@bb|Cve3=FZlJj*P~Jmzz-P%4-?amp_Hbp#zMOm4%Y;M1wACp6k#pQNWOB#Py-Nzjc!R!zK+dSL6&WIv;%~u{V{O-hV_|y zK3CDWAeem_d?Sv~djThr_`RTZ{tb>kpm~tDpkRK;#9)kIgCJuyIv_va8j!Rhsr~Rk zD1;zpzfE)oA*fk^8VIBxN-L~3pc?QSgsm4g3;@;9wBfAd0;@Lb$C^qagKu_;y5YAbg$40*sJD1s2$EZA>9EI-CPs8ax>ABjFVA7qs8a4em=AVdymu^)~;qB=;5AI2?y zEu&>gM43U z`oRT=>2P-1Xu&Fz@ENRv%D}ndRjgkTD`w6_P&nV z%=8RJfZiXuM?nqvx6k`TpAXu(L;rS$zcdiJCqR3KzBGVb6QGTPxeuQEU-WueM{x~& zb`K{H)BCKj_`w%_%XhCYYT%5+xW2nHA*kLceN*C8!qM@G zpS88My~q9tgHeGZf!^1fYreI+eqXIvcJ}smb}+ZM(|W|D#H6I;#N?e4zg^BqS!h^D z_9(`s3sc8vsHwvwN=s?R%Em@%MrU-v;qdsNpsqaq zLbJ$*`YDI{e`G(B(Q8-gVUEr~T;Q(`Ke%Dt!a(-{q=bUL|3Y&I`UE!q+-fo1dO{=8 zFs`xdmOZ4ZMBPfh>+ppqPxe4x-*6xA22-UYqZtzMP+!-uXU=aah?&*vd*^O7tkIia zh3Lx%YYE?24i@7}ymZ$#@2z8iI4U3x~yq*nBH_qCG3AcQt- zxTJNNmP{g%6cCw$5k#!B|E#&+f-5LmEax{%IR-tBltx|2s9ll zpe=0pq4ZpxZ<^oYv;x#{(r%u;x2G46PT3)xk&JJsC#Rn7)8@)Obt8N9Wo3_sE->-k zlXykEi=REE>kPr}X)gJX|A5IEP{+?yM2UK~R60H!Pc-GGz|^6E|$YW~mygu}o{r62jn#}Up`JHBSk+5*kUKy(?`h6@@&ye1$ zuhPfoGH}DuH|9kUiu+mZi!XxP$y(n!@AR7Rym$ z@^)b5`jO$PfvxGWxYvy^$)Yg&n|d$Z#*=yCqti^n)iHMg>X6{NFQX9Q*OD)=`0Mry zt?k0CWL}1=R3``*^te+IxGqqJQ<c1q5naurT#pURv|2s)! zr$ssnJL(_8{6Yo#xZerx21aC`7|~clI|6VXga&?*fS*roV00^`ykvH)?kGp|Xsc>xI1&R{ogF z4%*%@qGlMucK!X>j7NTGN)d!C`uZZrd)Tw?xK6>aIQ(lVOszJB_-PMbo1$4uDUts= z6*C|pCmxFgkAZbvk*LpFF{=T_{JvE{W^Dq^qSxK6wpJP=y8rE@Kj)H%WnWMa*xk@~ zbit07@$@+zKL8S#4KEgvE~kD~Sy>uO^jhFZ*=>GrJAo~c1J8|Vn#8ho_ik*+g!+lRl z?ox88o?+7r+k@EN!)x_HCuF|C#X)0o1WPBzAKk_lX~j*jO`|bv8xu#I<@z}*9YBw2HTc_|kz$m8I=qfh@)!`8$4CLv+LBSek}X zqbsmjp&+0cGDS<2>G6uK$^a=W-xf9x4ZdgPQzZslpEvZ*^N}|jK6*4iikk#%=s`?; zQ1@wW>RN2TB2R~!7@%0_me1f{y&$3E{JSe-GorMFmYi{4+GZ%qE2eF6x7s}6?{jz1 zNU5l0hC={#>T$N5c(!+&2nMw$T2OXer0Wpj*osoU_#Nc+htoC$m6AJya{Q zwGs)>*L8+q^g!oMMq7G_8Ts&Y{uppHW!BXBHnG?T zPScJgkvRcxyz8fv5Z)|pq2nivMfSy_-T2U;v?7=6#yfu|77BKl;iE+W)sG3%^tP2c z$IOU<>ZLIT3wtva^mZUqi;ZWC1d8{Ma$AeJwiF>(?J05D8tOA-Um9$W2(%0g1z zT6%|wAW?sV4v8nkztq{b@PiGADYw>p(15#>IAgJ=if5H@n7s6l_u-Bl8Kqb6Wlz-; z7vW!tl9N?7GRsDLSyvYH;eC}6a(beRo&PIMlh z4U1!bm(=ZVpUt|UuUq4kg~SBnAYg^@!2ml5UQo94rKvgJAkX{ka`Zvl=ycEqminfW zYT-6z$!lKPxh@^7Ou{DB>rm0QCgwsDj$U&-M(^;^RpQ0L$cp|_RQbk;4==j$@=XSC z7dskJ`x`2Gkv&_SEa^bZTjKAW9$HuAd~CY~J4ovaLryMn1f?1hBm7|7Fs@dmnkS&r zgfewL8t#A+;7%+OfPo*bqMD#W8`*qh_LW3=Nx9i{nuSw4p-X)nhZR(>RAi?|M@Ux@ z^?D<;Qd0h4_dRtVKW$-BODvL&@zu*Sy6HEig!@^(D0`?KozbbWm#{YSm!a&iu3d@7 zuA@uEAYFXp+S_D~;Zdc#qWe4Ht@Ud7@6e>v?vGbs1l2QD+sRBB16S@8aqeI+2M*Jp z!7(iit2+(B%|COF{ZTu-i`ZWaQMW%gZ zTdQXpQ_ex?qg5P!p8eic64XZB%W_L@n}N}^0hr-BO08sIZnQ1-s>1+vF4yiAO4yn` z#2z(k*!z66xr)W|xw-g8)9+*}dXORl0F*t?Wn`Qb+PpLkioe zWIWbZH^f|9i!L4!Vr7Y&5NFnzo{fi{;+{9MR=B~N72h30u(CF$*)fac~i~C$|xd#Zmt5Ni|xxzsn zAL8gdm`S1X4aI81-j<;!RYm#fJFXjMoE@B?F1vR+GzDI&M$SMzn8KE}nfIjRuW~&} zynNtFm2R4<@6wQtD;=KgVoV_Cd@cBg^+Bu6F-?y-a;0~y6vCHJKXb+;Bg)FNphWM3 zm|87TGkK;-+_taCB(`C%-pH;Jy)&-j_HHn=k_8$zQ!6{mq{jpKxY~B3 zo%U1koSDSMNoMPYmpy7svSc4;dY#EQj|AI~ar}$T z!^+`4PNfn|>!&V&h`0Xxc5R0v=M&@AyvO} zX@g#@HJ{>S-Dzxrof}~cgWRUx6NP0n08HQiOmkRf?#pDCu~394t+E}OsEtB0_KE4VFC4VOv{ zX!NpgN?N8eVyc*F$sD~HZ&bn)HwqoQF`0#=xyBF}|4VaWx!pY+3536raP0iBPWU*} z$wZtdEDN(kCtG@fvrxh<{%tZHiYPbXr?qN)oQ@V7s6wj#DY;3m^0RzXvL4tVWAOSf5*t8vscdKK@mRlM)9lRJhSxc!)*hq zzbZGY!5_iQL)Ejt+EWooZuqj`M&oSOs=Md)030}6iJ0uUzg%pa_*;`iaCsipNzEXh zOe3fg|MIpGe9xk7hiB-SAAEj%=wd0_`8mh#)L68l2VbVcTRQ?OimY6c7EW<4sX>GVR zkaOkH^XBjSSoSICf`77GdoEJRZH3$X8xD$OaU@V&9vXFd1WkW(rg;jT-(4dD=xVG)4CazWOo2jt>uR5TN;qMT3&ZO;rDZ%N?5TdnxXn(Zg;W$$^OWM|lC#{X zC-j;78M%ylw!q*!g;6rH22N{A*||W*Dwjwo;2Q^=BVAlINMVhtwf?h6S(Q=Mtcej> zXZYHbu)67~;HtQP=*P4K@PLutpi|}l#!mEQt5&z=zVJHP>S6eVT`b`?5$-eOjJ z2j{!bp8aGlS9?2vts?1Li24MMoK1Q*;Upx!k&7XWW8hjf-Ce~ zpy4o7qKHtIRpM-0%<))2-&l$em7eOzAQri7erA=98rCKZQU513)qIrM?Q@RGA zLG|?W>}QMdW;wjrMhP=4KGEdqj`df|+XdxyZUK<=gGkl43k;zf(#xMSPVXf06#&|+ zMT`s$7T}Lej1CRxC+V4{3HSTpsiB8;LlOnB2+`kyh5`0{1vpSD6a9=qAicm9{p5sb z;~)zGx&BePGh<*ER>V-F5chswc_1%f=wN#OqE>1wVMrXKIYyoBW;u4Pg@1R6>2Dyv zjn0Y&)x&}NHl!w<48*8&5lC11xNvbw+^<;Nw}p16KY>_izfdwU9Yv;SA|B#jk8 zXzKaV>;YqNZ=vWYrD^izo!wc%Ythovv&NAvzWMSblQ7T}*R;sk(h#uaZzbtB_O#*l z9@VvBFf5iyR6#Xx?D;D$nRO$nz50XY!L6vklQ!h7a5DCW6O|&h5;p-pgSlP!#w#4>kW57iR_KoW!*$$LolzVw!3 z%W#WFUHf7Zd`G=C$Av50G@pph=SC*S;>caVi`w)=&_78`!Kb#gfEz2zB67(wwCS+v zld}D1I=*F7SzUZ%>W%9iI#Wc~p)BJ!Q;e$gC57X?G#J%DdF4qyf5>@J%W|>ZUP(zL zMBhHFc3sJwMe&C!_X4U)DqXZ5Y66VtHl?^pXE-p%1kFek(XM~ zPMGGmG!>o}HDRGi@$bCQIYN3WKfOAte{tkTNl9*9suQgR>U zM1ikQb<@QTSyP_Ct}8RJKEV^;+mA%H-I*`I`woEb#Tq!~d+=UD{-=>srLs!*-UUNY z%rnjR+FPDVi$nAu%NZj?0}i7j9^|~ogOa?QqLnz8=|4g9ua*z72deZQ`ZqP;n_AhI zEVtAIWtF5W{`LY<_&?@rP6OhP_uPQ0&JYhA4Y5LxeAMs%=I(n&L$!NhgZMGKZ}Tk zWABLG2&CV1-nxY3+k~3g0x#xL(%2YMFw@#X@#f1aN*9T@Y0f+)zp*LwZrc`oCP@(X zG)*la0*;pySc_&c_85&`)~jdevQzT0us;tk@{0~Sc{$(wno9kuW6Y35-Sesl~{%^lA^zo`z)HK)XasYUdZXcj9&7` z>w<70`;}1&b0+a=3J3lL4Ew3$zK7O0fP$B$nL!L;wImg~%DC8#rnz}fx*M8`IW)p2 z>JkWlK=bfz3qyB+_j0u)G$0~CebqAuQw^I86PqXm>GXuV(ult8Nrbx2(~uv zf@-)RZDB^9Fms!24bV)wYO-rXz8t<;(`9%$Jq2WUDG7pEKb+J>=8{LR!oO!-jutCy z)t>?^2R{F`VlJ{J=D-ZVu-89qb%q2ypss`#pRj>7^A~Z4ScEs!!tSu1C`8l4vhkI< zQ5A8MUf6M|j#(_ZbzZp+G-3bZFLN~sayb8!{uAcHVzbxsNbW}T_|K1E4HfsD2IVB% zXaXv3tYeKli}8N+7+jv$+#bS%syb{znvYiO?bPU?=G%6k^TcPH7HQ7;%s6U`C%k^{ z(++krF9F;X!TaL*KCpvoJmQzy97J`HKwfTC)z-n2@p_tjSzp=IM70nac z*w&rH6$8);w!s6&JJ%32#=|*?DdLt_*$-%_W|D$#DfXJl;2z<2F{(r10SZZT3A_+( z5#8xSb03}9K2sP;+aL>JzwV0fDQWCCv)eppv7Z>o>c@_?3k^6uZe@P&gqpO`b=`b> zL|;Q_j{;c>G1bZ$Bqi=f2S)EIfF-FpKIYj`0X1$I)wH?8`D>4rF?aH6v6<&>rq>SG z|L|j#t^VN;rzAfvE#3za1!YTj$7jh^*hSsvuVHZTAghJmJkgd)lO5x^Xb+fGC=`{Q z;x#gk%!E(x^en~fU!^bEBHAWkapoKyuE5DcZ{p8l^~;tX0ZnK9g=wQJq@r?qg4AY8Nanqsi>Sp3V;_MM?}*fH(c`3~wt zM&W4EY0lp=f#*Nvnk`a6kHUpFN%K#Hf4puY*Z1ZfY9Q9BP@OqXO}jOZ7k-)swSGRj zw6C<0crC&c1;+e7PT@RfV{j^1p5q$q0_~8JbjoB&+CnVULd7sBfLKd^EyZhjfZ>Bm zkh>Sb%rIp*R^)|Hi&4UAv!4U}Y>ZLO<-2)0+6gN(BjAMbZ5Qx)S!VnreVDgvAeb?P z#v}UH2yFn{(Mvwezx{M6RLR)mGELFTGFEyQXY0W}d~{Jlx97qU?^W{RhJIV$g2&b^ zQ_N}BAB1$0t3AXh@w{JHGZ>qS*Yk=no>8|erBDj0#$WraeN)d9a8~&$pU3FaZn9UV zZ^-0&Gx55HG=e1$>f!uE~ zONbZnB1U7zB#s5<%#L#{8M50$ImJvM^-sHZ=ej!Di!0?fZ|Y19E^WvlUkIfNZTv|?S7$Y84MDyW9-cKLk?Jm z;I~1x+vo)cV|TS3`n>eeghW}Jg2Pafqq=db50fv|K9vtWTCSr~)z|U{SQ|TokC!|7 z#)16Fn7gXUWyW0fMU(R(;sHSO;)!_8h#8!w2bh4@MUMgjS?#RV-ZX8rKOfN=|GYzB z4Uw@Z7t3?Rx0dpET3KpV>vX1trxgyeH$LUwN#8M#V(Vf!e{rn8Rg&mT;%+RzwR~wq9emqz6VbLVwRn&Z zs~{`C?R-k+sYAdjoI+Nd%=v-q_`@$b`ANHr`Vi}{`HiibR>Ex^5n>+R^U=J)L*2`U z4L8M-U}##4FNg-2Ep4yrtH7C9{Fr??Sn6gHv4A6ULlp!Zbf7_BS7EKFOn?U-tSBQI1V z<8+8`gi|j@k@%Q>`&dwt#2n|Edk??D$=!wFy|22cVtkpvnld25VMDBg+#K5<&HgT( zH}ou;YXGJD(-JGmleSeJbIKzu+x*(0_`xMKylA_8L`d^f+aR;~)+-Q7Y4ZoB-oCn2 z5hJ0V^$9|aarURZ;XD-Y-Y<(3_?vj*q9=f!+;Z1kb{9?G>8W31&~`<{a%WmsOc zSN-M@bX)rh^IchZc=%(mv4&&9aoC<++R*cEKt;&c6TC&wDq%;ebpK7p8BZHhR*OUpy;g-MO2^Lmn z$+`q$PW9*y2qs=-4f|THLjB$DjxDd(LsV!IUK|t13#)z=BPEAj2kH5)R9x`Z1t;GE zNI9~K9(8n;`87)&kP)PBV+;b9U?m~xZt@LJriWD}=jr_`{U1=0o~fvFaC<5?M&{0q z3j+jrlYN*$*aGyN5&egGtA7iAkrwV8qSz#A{%J~?(v2j_c)+C`)ojS2?We1}$Y@(Q zVoY~0l)q7OsH5I@hc?L>+R2Xc0;~@Yx^d;<_nnnk2s93s&UJsH)dvpR+ks*@93r>8hlZc*<^1yHQGKi zWWdT}m@NbJ-tRVt6HQ!HxKvA?5LXiBHzDB3L3kh@7r25|>`Qb}IB(s{y)!HvUVq3^ z!)p?-Y6H)gD!OUC#W+xyilAInl1&5<79{z{MJI&!z$EKtW(5Q%YRUx_eLlbACv$J1 zFFkI+5!=VySHYK8&TU`dXQ-aQm#522>dto&50c%NhldugFNiC>;E%WT{hbXUgI({c z&-QB6S5MyO&b7gV=SC0Qy58ICtCs&)z|+iiyx0@e`pWkSWWdLZ1{+sI5EBA$s9uO^ zfLkvF2oW&|G$`pVsStb|NGgb;AABo(902`4f--r)kN+(w16dr2t5ENmR%=6C{*R~( zY!gJ?KhuwzOV&z%3egTE3*m3M}4(0xB}Vi+NR zUcbc|>o~{@Pd|8KxKYq&Q1@NXJPm9mk^+# zpLJp27!_*&UP-hhbzp(u9?{PT9R?A>JJke(uPUAiuZvWLbM%a#T;NFUlJk`y7eL9z z6YKx4oJ7xnc-sPd6#pHvnf;8w_c)U@XehR6yY>2ckA%h^cSr}>ZnM6vgP>C zcE-giNZmUjIK_*dsVw;>hq6^&z8ZrvCpg@Wo~cC)sk$mrUOR6p269a?%=m3GL7uh)#a58d&vw*gZYI%c=JZVD7mmqwDl|LARQnZfm@d^?Q*NdXM1P9P3`8$ed_IhpN2q#XWJ`TPa(%X*DOPphU zUO2*&0N}2lM4TU$^jtU~WSn$zD;rzD9M=M|rlO4hA#vszZ=~gTIu?!oQ1y|5XFn~f zAEp2wGtEr02^6(vHp(l~w?XUR=B3tfO+I;p5}*hkVSI?156Nwyxz3tWv7df+n%Cc2 zrQZ<8$nastqJ}Ez({F^M(9+fgv`F^JAU36u!Os#;GVjlE@WT=-7Q6nebM@47d7Qg? zUSweX3DYk;=(YLxxm+cx!258W`C!*`91uTnlYBZS+}JjT!8_keghbM5kZByY zBP)mGI%3K4#kNmln z71qu_49@kpx~!5NgA3%)3NjG62bdNy?oqWA0^ zEd7A^nrNwZU$-vIh1@urzi=&K$@5 zYZqmxt!U~^R&6*nw*kxfhuGsGr{I#(r8_lB7OBB!rS@Ou@_ zP4ukKg}SW9jH}T5jOpCD;^#7(AefA;*VK!{J?46UsUGN znSP-R731qQ?y~U<17h_(@zt`E7Pw;OxEs37ZTM=Ihewvi^X*yxSU_yzyb*iT7_S(b z8B7X^=pMllHnbuFLzur8?bt)Q!GmyVMd_TSxg3H4u`{K)#mGo#lUYrHf6#QrG7IE| ztnf-`o_X`1P7jd;DK|-zTaI*-`^S6NSYEapwLjU2d;xivU8(}!Krb?#;>4|rt#_Z| zKVf~hiY=0GQL9SsF+s|{>-kTL;e)T&yfpY(?p^WwoOgB!Sd+-<)RZrF4b%r4n^#~z z5=}nzaYqKQX~&Z*Gp$_hyu`O(kvAt-W95EFtq|Zox&T!_x2rl;7qaOn3Oo+{VoeN7 z4aQY#W6v;V)Cf%H=!NB2mnc@j7?(s%;{A^o1 z#8oE=4df11l7p)qSgkRYxcWB{FU$G<57vnMZ1b%Z{NTY$VF@(>PMUCueD9AFG{!YE zoky8Y?)a*}HS>t)h{b|m=U4Imgy7*0@FX~w^{r3}fSBzG;|eVWOzmjKWin*f{Jmjp zGB5jzl6@prQ=GtNI|a_wI$Q8=`KSY<7L9#d&%&Xk%k7?%gUDm*>)73=?x4!GfC=pq z)MRW0Ym9}5f^Mnywg#$%;A_tHt?fRcYC>t%8=81rNW;aa?iA4fjcrvXV)n!^~USM;DzAAtChFpL;X_r0-BQMnu(m zMUX;a2*|4#Cu7>Q^GrFA;e3MI7bSj-I*lryX`>#qM`~g(Q6Hw#KgeP87I4&r6=N9B z`0_J}N^-gs_a8YPq+-6tQ(KC0s7cDZzK5@x1H~Ukg@yd2Ox(3{TGKbTg=h_R#n9(r z>s2oT%O3sMiW_aq*;mp%UAbiL;pn%0&jHO>IqT_(mRpw&%+8IZLWk(2ye!=M$H(J( zj~TT0DL=REA`zHRKc5O~%E5<&MCu=6Zt|>TsZ}*3mX~D^3J6AG5-GvREO?=Iufr>Di_NQ~Ts7iR5oHG~12DxVa`4o==}{N2C>N0s5Ds+sJR zfhLqq+rgz{xZyXmk{zCP!?t6+!md(!rd$PJ;6>eAsrTFI3KFuRC(~1{7g9=#PpglV zS2+h{Dtk}Ni3}bjc^Hq$)DCNobf!sL-71~=P=sks8RcuNO~U)eqtT_@{j1D+Pc_jO z?MkfDGFpTtIv;j4`7>3mlVsJ`x*B>kCM* zMEh)9$f*2kcAgpQ+;JVD#@HaWr&WnCi#rDhv++V{AFmRxj8*Y1Z6p>%=DRDs0q2xM zw;Q85H?~8A>IN8@F7UB>gYy&Txd+LH68YeK&*ZxEXA!5Zo1NXI(B>tm>8yh`ViLt& zq5RV7MzZO@)Fo-c{Pv9%*p(cITj33lD!=l6y|8<@2Z+hTl@`}i*|7>d7@PWFt*urOK!< z<`kH_81*Dv1PKXoV1J9Ka%?m1+wfs*PUiNUQlTX*(N0bi2ag<9+?dbB7uQgxuwi?U zRXz8H=YKXj5nj!O`@0QE$7~o7qefy&$fTY;Rq@ZLX1`;H9o$w0-rW{hUoQaQLIT|* zm6Wgc%+EdJZXYjT)+Iz^nvp_rerQ* z!v${h-^Cg75ql>N(JFA27HgH-VcmSn-+()Yo*Vs5MT;FfOyWIAZEjwG)xnb1@ccQU zc++(n*Fk4bB4`lv;JMwoRATnDy@O_ymxzA#_<)76)rI&<+T?2-Ja zNmG%fmQ3lSkf8n_Zv#AyCZcH#U3O0Bs&XB)doAjr( zx{0DC_EuCvlntck7Jt_XlJDwDQVtU6g! ze`c0ab?1ZB@DrM@xs*s|$~8??Pr`@hfrf>k0bM7@sxN2!hr4L%-$3u8wXZA4vz{Yg z*nL59Al4Vw#8*wPY0rNoG=4<8NZ=s0{zAmi(2zg<*$!u(Tekz9zsqC~ zf)V*~5fe&)p!$;&b0ZD7P_CU1S`0}m!;{EkftvMA;J?A5=`_ew| z=T>6*5!Y#S_a1Ip@f&uFr>b(YFf*h0_Nrw_MkV5xvk^S#T3gqK9&M!bq^xdqc^DsW zLLy>?%S!&3&^qmNzNmmKZtHN(7)2~AuW^(hbTd5n7xgkVBgY+Gc?PGCx7I!Gyr~Y4 zP{^L9On{-qKT?^SQ!X=avyxjCGy|~FzGBe3_fyeq(|G@x(}zvD+?_y5#aVkBV5@)>r)e9S|83NKkYWaG}l@~eRvGlmk$0tCNm^_RZA^-xP! z$5RGM|JK9chYYi~2@S)9wCz8UOcFbT$1MU)~Fj{y>R}$LWbMdGKtV32js=45bRA;-^=`Xp!Z zn?ddNt>gYIztEdgLf#5!{NSdN1KHIYhJHbX<(lF?LF)HyO}f(-`2kP3=65pLqh5NL zaVE198FmN`yfz|OmD^;iB(TcC=i}&#E>!?W zhoTvM^5cPh{1?{NjUO7Dcw@bC?Qi>r42P}NGFHjEdDtA+q-W|#i*Z=v@1Q%H;GWgK z=8$*JU%L4ddkF|sDl5E_Y86tldz{00-dYY1K%PC5K8n31BUiem#jjXiS46y_He9g=7d&=bNMo)|51gdQorFAED?-d5J zw6gPP(9C$|SGr+~v|WdVR9(xpn4(1}`lru{vF9KiR~M`_Uqted#)!*P_t1xCtXQ&0 z$rwH?(dc|?vf?e;F90JL!QV>mqvnh@)CrrdOd&`uc#Nz5gL^+bP^eFCb`$T>0Fzo_ z{-SSNsnlBc1WAVOuCl)*eKj&}eqE7=Nq=NyA~T+Teu2wA^$Rl*ncb`S8clQ$4$=;d2g6PTWdL~V@zOJgs=wTF?ZLDr#e2tE|#B%FEB#-XE ze$eSDKrEvTo2A;r#Wx z=7JC$p_}sb_PFkb!SIgboo4R*AZ=}tBQBdj0}N#ACN2z4u_jG&H>`BvC`8lc!@R-T zpjU2j|AOaW9=gMjarhwD`#R!cQ1+3zMEWyojQa?gipOHNCDKWBDA zI?vral@Bou#n1)MtB@3 z($hSv11~O(YO9=JkN4r4H5@vl-w7V7%r6+U`l;^;E*v_$E;R6_0Yxv{yCH?wVjlzZ7{+#z$gV?d6cZ zqMIN1tYEF9tRnqbZ_=XhdttlTb8WY9fi#M{bu(P}5Z>oc36>?VBdwH%jEoQ*rTuGV z{p|w&Xc`J*7VXUFM-&alQq3FKfycpLVH~zz-i(BGp7)3mKflRgRvP%}^1y znm?r9jpW}ppa`98P4Y6Eg;82KS7@BpMmU%hjK`&G%QM&27wurLh9$ZbP$6Usvdj-f zt#U;5a`BnjMn`y*Z9p$ptVO2cy*2BnJtAvZ>#*-}AbOgct%Y+*q+3?bMo~sIh_}e( zy`W?@QhHVbD*Y|!bbBu%)2s17?dYNhRNff`Z^PuD7Rzowx z`OQgw6chDQxldrlQ1H{jMwfXoHldzslHV1N)%N!|A2*TcadWxaGkumZL^;#SIVLaF zveZgEfoP}oZU1Dr<+_u^1F^WckdxhRs$}+f%gZk2W0$jV&5K64YRy;C_@2bkj#n=? zRpguoD@eD!!e8vkIoI^sy^vqKDnt7~ftW0Tw$n!Q{r+qcIt(Ke+o#>c2<9cW`^nP0XRbOn`IBV6>q zRw*Q?mlP+7kPuWv?H`pN)4Ff@yKQ114a%2SheU`q)2zK;@dKnk68pO_53!6@6PI`zC7}Ov3DO(O?CUC z=z}OI2nbT8L=b)}<+ArLw zH|HRd`h(@%vM*I4zy-yOcnaW9LWh)@F1+>T9CT@5eCQkmD}g6^C?Eri(wh}O&uhd2 z`#ujwHW#(xI5T_BgrNkUqLd&_O)Rmevugc#)>Hon%t8=jWWza#3@fOCF4qfsT%%Tt zd!D<4uLv@B$Lo*f&KVAO$TvT;IR`x~Q10T_`X)bM6?_hQJbw;~{MveGQ_J(_>N`!t z%>y&i9xIEp@>2S$k@q|L9N!zW4iH((uA^tXU3gxMyY|SgDXMZnU`OS?Q1K6KVP3dD zQMcxJLKmF1Q5oq!d|Ylo7q!U#=p9eI@DuWkfOX)#Ro@b_HD#Xq(s|4I4xf6wp# zTn5JdU;h04rN7P}`~%lNW=C=pbD3i3Qx=`1cB=xEM%2G)Ho5w{ls{@gbCxoV!<|as zoO%`7eb(Rd4!k)kkdNb|KV?gon@J}%hcw$sc| z>!E`U%M}llR{Au2_QYW1`#Gq^j6cvBtKK7>`3i59gU!)QeD-X3r+Lgl;ya?n8j@my@Kc*3Szmv|7 zPm7_h_^mxHQRZC=7#SMTS$f^R{zoK2HZPic>i6qv)q7Kv-o86%(St( zlP@iLcDh25Pb2`F9(W2lHf(to$OTh0BettP2U!dY!c>tmXB+vpQoF8@q z&-xcV_XBlLu49LbjqLTPd7bR;L|`9@k2zH;V6z zDDqyqGq_=K)3pLO>nFig#Mb*MZ(t(eN&Ox2wbhQ2)^s`#dLT^z(CX*cR zgPjy?H;dHGkVHem56)g5>kT`LMr>O_D-|7R>K%Qm>xBu&zzC%=){F3~S!4^p zOGB{OpI987qpZdTe}cDb`O2+@4R3(8YC^o!Fz_3k6DKXZRrUvFQ{Kp)4sf`HJj-w( zqmLUa@#CMS3w>Voep3h!#?Bm{xgWoT)&whKrt4$ru%+n3W;$&DGxTcd{^kuwl=D2$ z;nd+dJ4l2~dU|?(C7*Tml<8;g_px}bYN5Zpm;Ab~dl$~y_>F0l$3#A z?&En!9k|R!Nb>Eb?zI;nDIV8Z zMlZ2oO#J#fgbenG%YYfB%RujHpu8_PvlspDQBL8^cJ5LZ#kvFdC>ZMAOV>_H&N|Vwfa4 zC^LFbsW`0rW6FR>;Nu1o*p7_QvT`7(X3daXISv~>|r4erH;>UJh^bPHuSR`C6oH~WRE2l*N zxTmA3fLCC3IAC5Jj6Ms>dN|y(vU5Uk7V735JO^3BCu5E~Zn$lw9$esmXhrk(g=93< ztf@b6yvT*h@>i%O-KsKU@grL-=B@aW@%C9BR>9HGL}}?F@1+Nah}%uNsP02Lza(*uxiY$ANiWku-kno{zYzDmt*?E;umAH$qh`Y(zl^W|s5pHeN zUy7-qs4mLmtjeDf-F5KyV%OJWq7tAyjQ!M0r`%>n%Lh}C>&olec|TF`(%9}e?UK0jA<*eI@Rlrlcc{4;$u$F7@D#6j{y`&AI0ndDhl4!yy*2 zq+6%O-T9tK#I?qXzBOZw0(FWXJJ{K}T(Y#72PYqd*7E%3TX!du7ZL48PRgqLVgahH zV5iX^+I`Ma-#foVmIu!hySC1#&~2UWwvoR!I-{RE6(>k8@BKbkt_jATS=qrUWtFpL zGrz5mh&n}2muN9#rk1HuTE3}@kH*TIsy*XHu2jWyo+O5%Ix3!t7IBW2%p{Rqbf&!; za)f{p67685#rDh^qa@$Cq+U?2N}{?vrM<(FHA2j%ZbnPT`*O{Fp*^Xh&6OVKb9zel zB?@%OZkkl9TSLEcm}Eg}&@a#o36UNN)6{7_JaZ`MwJNH~+E6r$8GCL)`<$r5XTP<^ zlp~tGDs_B#$|_Nyb9_}(Rv4d^XeH}D=z83cXtgW~1#P*Qn%I?Xebcv{^7uL6c&XC+ zVs~A;bAl_MIM)R)x|WGMyk=S4O6-9LT(}7g0pB# z_+G$(cZbV4s3CW79%q_6!j2IP6-|G#WHwsdsOX1ClXT(_?28J z%9@l!QoJv>lj-TvZ1wFf6OV;5P3FfJcQ@}j40^&NZ-mz6%(u2**_qQd+h#TWnN+QH z{P6OiepL5#A6E(45lYqsZSGl0Ig|HB>&`yZoV5ci;9;H=f;a|;$Onrduo4R~MTJ-{ zoP>Tfo`-tUk$+o&-e9{JU-l(t^Gg)2rUgUP2>a1mJ|)1(5EtfI0DAzXP%p6Cx0en% zOs_EBxMz2Kr`Xwg?*qrP!nZ$k_Q|Z&-H2A3-;LzeCJkP93vw1OO}!o>7}UVly0&GU z+zt=9VbiWjYJhcDk)W`0-c#eKb+L?FPRxr-d-)}*p`1uZiBdc!tO3LgA{$73^jJ$X zJGbH=Sb_a-^9Q{DBI}2~06qC{HGlBe`0*bYKYrD`q0YxfKWZ7uk!l(1rhJ=0SBmi> zrOFY@`0PucpTvt!D%5c+ZV+lhKYX2Q-Iln2s{I&wi#}OeBfbrqENu9|-HKCf3Ad@T zj7gYAPgIV`YUXbgI(cTVm+MbYZTsdZ`_?|T6p>eD#Px6-Zs|8)!#tL!OL8X(V_UU~ zF0qKzk&y;HG~(uZZXX1Owh90oA=z`r!}pK4{3?&6s=|>4pt&9 z{AGJNbUZyCiYL4dd`^;2n5;MlW#kjEP;?d*7?V1`RUGj7Eq8VVl+&`I=Jk$LEP{Jg zWh8FoQ_r%<1Qycaeaag1K`^QR2Ts+>2j6F9Wofam%6VBzvRj%6>oOG@O<99f-%XnN zI^q6B?1%Ytu<+yf0moJs%{#Hi-lZ@345w9RZ+}NBUR|Gl|1SC?%hmmD`S(OcinLFO z4A}U}(w?E`J~==cGDXYj^!vGI0)$&*e^75bm_~vy>EOjgR5~hlN|esu_G9InG)|7| zA74DIV_bSIol&)JmuIwbYPC|5l9fhPsni#)ORMem?g~-UR!;USGVbhGvKjpyKeq_n zqc3W&pHR4agrJa`iBVsbkiCJ%#1l8;d8^BRGIaD?UDQjKxaPY~BX#5yd--IFPLF9& zb0czKL{`Q(*MZ^q=bhGgq@6)B^*7-Zrl50>A(g`X@5`HzcJ97btL^QyY5oZ}1W3kN zALSmhSAm>|6lpX@WaQA!y541(WOyw)(0Hf+9+@;7{-`8> zdt!bc2R_4|gSHDU9MTzS)cQ9`kNXNW>&HzK6LVa!9{|y6DS~ub>XUxmFYAo&*VFn!toKh`4@HSaHcl(|IyH9kE`6+3Sm|es zu8Y=R7V2FI$McYkiP;&vtZW={&KJ0^DW!C{_L)ekn@Zv5s5C>TPgUjUJWhCX)ZpPh zSk`I(!r^r0nt}H@=(@K$amib6uF3S=TTFqDkMLKQIM#^gX^DmnOdRO1Sl9`q+ZNmp zv1It#!}DfO_S2+>-AR2c9%pzCT2O#v>emja81mm*R>e8ym*1ON=yB~}=@OL0^M+yQ z^BTHDCJ{)7bRH?r_f9bn)n0Wejcxk!NVYPu9T07aPk2-L935ZlVxkVCV9DF>V;$9* z!ibiS90s@ZPvt%hJH8!1{Y4^^VGrYsBbU!Qj#Mv&y8rA&(z~K0XWCHE;R2e693GVcN*z}zIYhCURHzH|IWIVUN{{?V zzjSlL>{DqNUiouJf!%nugl_zDkEkmS8lbP697ec}g?CxS#1$HCs)W$Zjaw!@EpK0QV6i;NA`_PujO2^5Kp9$==SJQa zUzWO0d(8;q^X`f3%vIOaHtY&|*9cpoVC9NMVdE$Ljx#tE)1^`P1>zCVAn znQ@=JdYX_X@=zow23DrJY(qK`90@ww#VS^&uMj%u_s7cI;De+q+O}Spsc8*bH5#$n z1Tq;|cU?MrcQKzZ+}5XoJN-FQEvB+2aK!Z&5f9r4lt^fGp;=e}!QT+dr zze;og1iAnq23!PO0+0YmFZ_{9cm*iQ0OWwH015ylfC_L8KnocmsR@z5qXfKL7>@00aWyfLDOO#t;9p;|Clg z7Ou$$|B2i>Yg3sbNhK9`IS0*)vCrOfpU+e?ueIJX+HYRaOL#OKhObk^^56H6<2(2k zOE@WVT$?!fWW?37@@x4INdr2HQRe?>%Y*cEnb7x^CSec z2DF4$F7{QtIR~}!v<-Q5vgo(N7cOL8N*@$f0Y~f8567GozyCl>nUL>6e-C&Pv_;u= zYXsv@z$0C<&1(#6=JBX8?-SEYb`eSLm~!2+AU#9#bk&4bj&PrY9t4AT$eJ1G?$jr6 z=X=lC(630;^v>Fg^PY9n@x48lP4q7wK#41;K9EgSR=p$@`%o{p7l->8V4{3jOm1XU@M;EhS_}DJ6-jK$ z8&EWOC7&@Fm$O%J+gfX1Vnv&QtK!Ba2wl4o^w{f#kD=6VYpwt({QC#$#^I$9+9cH7 z57xQ!8J)vzoSckWszH%)Wfr)`{S7_T+Y1mcMJLWwk>R`>F04fqx+wEnq0jRIS@Q0(;13I-VCUSadGS~3&NJXo7dIR1qbnqw0c1IxBcWNWDTKx4rCgP9 zzuK?={olV^(j61&W>ly1?|IGiZHTzrpRs2``_1E$D|M2*MK@sCg2qW(zk6?d!*+7c?;2^s^ zk!in5-QuTp`pG|NnFS{hdDy%Kp??AM<_OC?Z$oWrTWT{5>5VmUz_#DnB&y{4}ZRgn%=DGuS5( z*YoSza9MARZX7^kH&`K^k8b( zyu3|`dd@l;^hoL3<2(8wtJjkw=+KoWb|0rX=FQ;tfcbSrmb`{zgm! z=56QkMBzT8*hc)(__MYtt+4M@n(trpirwKHUg!L}jrjG#P57?EDs-~pXmBWy3&u79 zQ(cm%LT8jOa?%rSM=Z-fcB-UH74{YC!?P!3CMQe`HY%QjEqKdaR?t{q#$D4&G0_9+V!!0(M6vmpQVcXm1plZC$ogAb=)`=mn zam;iqw1DP!fcAtYN zu}e#wg${*XO!wBmZG3;GIa116o%4gm`J{QX*@dw{?g997!D1{UL{0nc+tHNv=d-zC zLyB}9mu_vSD}rEDI5yKh^!(A>S)M%0CbPE5lOyo8Nj6$pM}t99c+x85bBCEYVO;+1 zJ;F~o_03dQx=$FV*LCj}pZ8d2UB_M@@bAIXQYnu?Y+|RV7Hd#bOE56$c0|m<2bp!}Oc5HBfg?B(5E7qhD5juIDM~R4VsLL!)T+dKOo5g?UpB_)QJ&o!smza>fha0*5%hY$%O|5P4FN zE>$>WFrzJVG!xYKO3YMhwAt1NSNcK9lGD8`6Ce8u`Y-Z})+<%elKqGl8s1?d(&g!J z`^0kX!KvI+cgXh~#Mpe(IP-(ihM|Yl!8`}*9P}*`lYk-b zh^sTGvgQBa$siRTi(4l<7W@^zI$?+*?Hn-u{=A_|f}XzJ_JeSlimD`gwPmrb^6}f0 z8;j0c>>IlgaYoqP#qqqwew_Y56R;6De+9ZHfwtlzZ7@eYA#}#Cp zkEc<1+)#cN$5&F4!&4tq9^gq%eLUj#8NQoqj@8l~;ODPvmQYHpk{`*AEUiX_HkhK-_wNWOehNTsYl{Lk{+BcP9FYW_V6(hJ56f z4%R5ZW5hO)Bb>c z)Y??s-TW%jah3Yln9>u0^;(S)*pNJIm~cxU_IRZD5XJkvW~_2Lu9^9*?$tMJ9iJ}x zu{o@jGQ!M811UFBSJQIT^BqnFQusR?s#sanS{##la%kB_ozNdLYT2NX_xC}J(45V+I zc078w_0(G`qdMd>f^L7HBX*r40(%!Odu%)GuXWEe%LX7b8L>qs$qSm%9*j^~?<%hg=Js&B1~fJI_HBq7;TpC@R;lMsk(n zG?G6CplcMpF)Nw&IduFXa=bcvQ(93xrbp{Xe%{s|Tx5C^?xkmS@^@x@=5T6Q=7mQ% z_*=ZXFRg^vIHF-2z0<4Y9L(V?wf;qQ%PeR9qCDdyo(Ze9Xm)V}D?Y`U$y$OIT9st- zJ_iL!S>qi#;1;{T6ds+WS=D2nR1{`1;#Ef#0!mHlE`GgLW^#*^D_+WdA8a0Hru+PP z!KTcI@q*3%ln`1i14iKH{v`kf_m!+}DtqoM;uo~Eq{XyPF9ZbzssEAdL-hBgGybjr zdhLJn`bUxfg83%{0P(dywnhI7;+y?G7ftcUw%9)@J_qPOKmYh1h(C4tk8SaPQv5rA zNBrM&ukplxZ2ztP98>*kjDHmW8vp#ejDJvK@ad(+A^F=4LwI*_#~%z{LNgk-ix>D{ zy{}{odn_W?WyNqXyo^J?`xh(@C(R^qv1knn6`v`(Ce3n9g>(W+haHS%n4CYB4KqW^ zN1I4QqO|9xJDy;cH7!fzU*405GlTG5l6)T7Fn$h7M0}2s*Wn&e6Y^5eIe^$Ww>X@G zLPxrb^I&!%A3mdEWtHu?e~=iEs4Of^v)av5wK(ol`GmD|?(8F36Pxp|_S)MFc#G_I{HeuJe z@$3>x+Jw|JHZV<*oW8D8{6frNG#a~@>|m6 zj#JEWbyUN{x453mB;MZZ5T2X@Y!E8jAzk{&pLzWxR6p0!XNKkV<#jh{j42;)U6-Bv zSO!Ua;m$_=)SU9REZeQ>TDS7uxQC&9MXi0U1m(RFHRNI*b~5jqQWw0;S$YB9-)TJ2 zYepn5<`Bq?W&RpV?NBjik2dzjFxUMUR=ghs< z9W;A}Z*Qh{lFdrh#dkXgY|Afp*|HN41^5T}-N2?zRvyKRNESJA4B-lhFq3edJ z32myL$+uOcLiZJRRw?3Xu~BR!lfd@7d)&>A4j-INMfRm*I_8?`Fv+N%1w?Q?X^=-T zn+&U&ZvB{b%~;y^ndHeXDmLitOg_;XSCF4eo)dB}h9Xt0v8dILVn<^l$1B{t8n0d`+z)3$n10=xG+ zo#e9XyIn_lZRn`lOT%w?ca~nTt>2c{9`L@9Vs1q?^n-M;L6iL=xPz_}>u~f1Ylnog z`owlz+f3?%Xa8W2e-;|^EIqf7#l;13qd}sqF5YJUDBjlGsyo(g`2`ARX6kx2?|0|~ z@2FSvv00oeF4&;awDYyr<)+!rxn11f6M8E^$zf{*M-F2g`D_D?Jo5UP=1!ZIK{Gj% zANV-q*T!58w8iEe^oq3g6dYCsj?%qU`C`k-OVBB?IwjRC#XAEP+unFu`(5O{vC+`U zkxl87ME$P9J0msj%M^lb&2$w*ibv^-M*W{W=AM^DYoK#^%i1Oppb7THOCy4^8aDhf ziDwz~{;&w=s9@55M-R5(R9uG|)*mO~+z_k;Tab=@KN= ztYUNB3yp;%Y3V1t7+r=ogrN<#6DtNB&v##mq^_R!$XYR(nbgP>47(Iw$^Dwqz_J@& zrQ&#}vgX(Kx6ZHL7?-#yf7fuAUXC+1`2LRceaofiG5ImRr!1!d4g-RC^Yucxu?6RYsb~E1(d7I_w<)YLHlM}K3tt(>JnKUWGtxyhO__iI9}M? zXEmOCXZw)X?y2y1#g1=LuN&_!Bw#Hy7kBA>a*&FH>73~~8wCD}BnllU48o&KS!}}+ zbSGZ2&zzdBg8bn6`pWn)UB9{VulZs>L+ zyZOR~CFbI|-%Q1T{3mnaT5$|7S7N>L!vb{!qtY9iPF;KBXAKG4~RSMrIvz?)QWnd&mC992v+HT7Um6)wf&Msi>L`;3iL zNoGf8jo8uKYKfnYJ9IuIdM{hTcX)>n=BHxY%&s>=N^Iu@&|G1aH$WomFD+q z*}0k26K|d#l4N_%UMxwEHHN(D)^}dPWq;zzzGz4-@v@|3&up-|GcE2V}b4+J= zd0Ig>Uf!GXN`!0M*6wt*N(GjS7Ud~W>@B+8nO;3293SxQ66_r05h7q2?eUtsFR3F5i;?SB%+P-ft==J z$`5o0^C56Mv)9dJ6O|gKYaLp#<=?xfwaUwl^lGe)C2xV>J?N%koQNqmH0Vk1d*~OVr;?!<*-F7JSHTERIY<{^C}T`aEytZHx2!c!Y-4;$ZOvms(^UrFI!}4aZt6?x7uEH?$^+4PY7RNR2-G08%F$JM8foyKRYwy2|Gdd=UYjfg}tqGT}F4&D2%`IRg=X z=b$zO9oAiCV#j0p^H?H>g1JWp55ASwO`3YHmKnmlRd4lW+F;8sv5}ZypzN{v3J0>U zl)u$Pn5h{P;7U5$WYRS`7G@%+lUhzlFcF@xG-u$&?X1T3NWqSI^*km2`JOaCEi;Y=GIe^ zoLryyiB4T50)KM$h9K?}k`sUC^z}hE z+p+e=pabJL6S^Awb!gW@(Pkjm$b0G}aq6^C@O>1M7jbipH@XL-!!#%7VwJ$O0|isz0vwN`25fPe7V&|eidReP zeD1jT=?%j#LSD9zZ3a@H2~|k)wBExC`i<<6(asK8-jb0FIYQOO9NpOmd3x-V9r7Xw z=_JCFm?Xw1edl|}Cx{T~Ua4V7PUMU6BeW8u+t544Q_Ac_RjKuAsY28DbvbqWf}xNX zyQB`WZc`!ny-LB#%f&;qhifdSdO8f-r08!mnbO01OHlCE!?itHEd%L8$cI7NtW#!b z?`irGjj$5&t|9fu*V31#1a@6@mK2 zanrvHey!8bJxR+q(0>&Crm9Be6`qzXW=S_?nUO3vrbUfAm-qeWQOkJG=sh=0som$E z`9hNwp;l85+N(tne%$##HQm&?vvIdG?+TN+J->c3dbD`2jr}=-i&o3hGmzz+R zam;|pw;nkeEk#lGf8g5LzyAL9|AH=nK(7J8fH!~;Kqw##5Dtg{L;~Idq5#o=7(guG z9U$)aToNGR&ubbIf9I9~k}v#`6OsZ*1*8E!0@5%1k!zd@$O3!k%!$hbdfIc>d0lDgl%N$^hknZ-5FwC7=pW4XF9^`TWlFs|Pdy8Uam!WYz3m<7xM<^cF09FBOfOWtIU=y$f*an~gJAcMN10@Eq2iON301g31 zfMWm_Z~{05-~f2Q*`NEK|IR-o{y)F|uRKWmulc)wkNG=fAmcCmy)n3z)AddfJR5o@ zwJN4O*LGq;g4BPWq+(`dw_7W{*;)+;UdrD_p%d<7jXrOB!O0t$?L5SoT}-K{3_ACC zg-mk4dSW2$D4D0|nr)M>Gh0W=sbX*HyTg3#JOiAE6l66Wbxb+g*S5_314r3pe~M;? z)RTm{7fnuY)rWq9x?5OqWH!aUO#WfBH?e9pZTJ%MrtXQK=5guA6KlbsIbxrKhPVX; zg=}WiUfh8#&E4tmx>NIlxUpDdX0Rzq%rg#o3iO_e)=M9Yp)5t^bCAtS@tFcLKLi=0 zVWC}HR~EpzWrb9=?2WzH!oBy=c|Q4TfcsKdn3x^kA#eYHB3}Z*NHgzAoFCV~3hEqW z-Ds!X>1Fc?Wd|GV=>i^FxdRdcr`qKUyy0_!uz9i@I4PdLXe1MsX#p#$EpY(rKto70 zUdrh$CDpgpO~wYZM{_i%ehw0R607dN{wZ=#&THa0>I(|5jBDwLJS9ekby0<#5L}E*bq(`@Srm0biHC$KI;O3N3Iu=F~Qz^+I03H3X=dP;W{( zu|a5D+xQ&cwMneR!^$c)?TZ9N@S620e}JItS#0sfo~d0k-*B#P);ul5DdPIZKI_aK zA4nLUD<9j_eZ%CV^qYi9V-px+?;J$+A<)$Si*u@aijh z_y-ud_pS;Ty-xE+d1*nHfAW0=Y5ltT!e7fUlgX*LSY8mjO0FD@vY3Fza~dyX)w<*c zGG;di49f?JY(ZYj%Z=b|aI)C2wr2i@i7IZk05VqTew<=v?_T!1(AXa`7O~5?A``jQ z@)B(KzJAM)td>=wPs!=#-8Ajm+PA37<*@Rpwz|OQ%+1D5B@dyK{*Qo>JA%Zg8Oms+ zUbIDT7?|gf)5F>4&1@l2IuKje<*Mx?s1`pbb0+b$>GhR3&LDituKQFY+}>%s4)FpL z_G$;R2(BH2FUtOeDU_Po^~P^h(}?Buq(;S?f6XPx%R>cnMhLfI&(P4<+XtmsHBnae zc6860cm!)F1J&&c=w7NstcT~)DLh&%mfSwBVMe(~^Be?`aIHQEHDxxLZY)Bg*;p{= zAiTe^QD0Fmcth7E;H)37p4pO#EWRa!ODDaol-c5>mCO|@*1|g7N0AZczlf4~=~Ph` zou}+HIb#%Db`Dw^OD?cI2TkdEXJSN~a8Nv^VW=d*Ul@gJ@T&4#js0S5+(!uW<%q>Y zY!WOcw9X2Vb?lSkp9;3&3z_cu1i91$3rZC?WsB6W0aa!WxKCv@Mq7*vZ_kX~L=rt*&Os9ApehrtPO3@G9>4cqM}b$cz-zm_$KKE{nmX{Y z{K>#^V^gPeAz@25Y)V!gSED)GGH>*O{dqD0r)8oXO1S5<+xAUq!_{3D;@;OV%V)N% z>yp>E`%tm{Ytyc`l8o0mKe(Z^any^Nvdwau=Y@vB(GzoK6z3pkLF)AknPE|I_^H*$Ipzt$mI_Ch z-e;wuJ55Ugy#nTrhXkzssq#~7G7J;jPWa?R+YR|9sC$#FocW4zD~>ZLbxNpSqBNI z(8~0ddYSff5EcbPe6?p_17qR7i%our?bN2+4RV9oo^Sf%MT8S&e5F&*+0=TTBwkA@ zf6y<#9Ue)4G{+I+(2L4dg}>g>$n?iWK_Xi;WFbqMD8aC!-9>%~B4kOE$9CB$R&eE{ z269l^-9m~@cvM$0vb`%H+fWckoq)p`K`G3XU|{SgBvpvkjK-qbHRVf1XY*Clh~oeu z`juk&a)Iu59s6fFyBcmwNRr~u_Nj6;M==SP4oiB)c*#9+CQ%J;@jbPU@XTFay>9q5 zd2+nQu;Z?v{4JPqQ_INbv%xb>&w6%=fjwwqAl#`6fq#7VP5#bwK*kiJEA?ui^KmAM z05diF2~H_$#cN@LyVxM3eA|b+w8}_EiQPzq;z$Y@L0}D4RI(pVG^=zUOy;WhSM2_@ zs4CAiV=Lkiw`FLW(ritjn#CjY z$=JoFq=>~9)b2HG;L%9ejZiEUtXFGb>Qi6%OS!)RSG7sw1AX`{A)q=r-w^ovJ>JgN zJWGm!+uHR8O2bsgmBRyXWAku>S5#F%*_*| zXKo%R)q4HJ1TtpyVFK|(46|U)QI zcs)Z`p1_%|e}3OIuCWOJ1#VA;B8ssIT4VW|O;@Rl>*3o2rfukR(1KYIfoU!vUm1;u zJ85R()RsKEdhn$1+0q+uEcZl5(!PZ491rAZ?LQt=7mDR>>F7};&%x%RHkya0&q1+c zDd1=4AcV5!Z2p-DF40uu0V?O$IjB+X1s(djdSwLG_n!^3HC0zbiHAXKMre18wvEfi? z?=A7}>o2`49A7sXFWi?je|Lp#HS%Y|e{N#qZ}|^{m;W{LA8!4X|M2fJemaxOZd87T zUW*(t3DX)Ou-hHYJ)R2ksH?Z5QCanN@cgB!C=`5y^77f-Hch9_8O^T#um^%h;T%Lx z`mnCK{ypM_O?`}Jc>=p=-0CYBQ9u2p&0uAiGTze$CL7f$@IqV5VX+|18_FEbJ zqOy5kOp>t;xGigu2W|6&?ow=KT((WE|}-l72emvB+~nei0wm+ zz|@XIfvBA1#{guD!x@|$81nF;#{06)vhY}*6($1-g3aS`nxAH0Yh!w zRFAAQluZo8QVY&{_eyyQ{MDXpbYqp?5MzSM@PI*W_$b2sCalpSz~1zFVF$%m?HQh`ayxcm z)e0$&1mIZc|9miSEV|B)qfRie#(QE%5;0|iR4|5VVFFX~AX7;c+8f#?Y4;xGyOPI? z#KkloF6FtL%GV(wlv8{yQ+g4r6yLbhzX?lQ$bTr!m%kSH-4NQ{@)k^8dMMN9xHwYf zkl%mPm7~=4mJTudGKeOi_poFh$*>(%s;}^}Y|2p6e*gB{A}N>aT+u_dvnN8i#iJ}n zzXs0Ysm8D1@#$Izq`CO*W7WIDSy#!{;G#QM?7t&c3hHyGb;)5Ec}2NI7*wP`yF>7Xz+~K ze55K$R6T_+S-T--ZgtA;vC-o}_xDm1h=;;bU3Lu2IK;!z(d&)0ndt|()Rw`uyjcRm z?D~tw)SZckBg+*p2RwbnCbc)+p6tK3V&szSVXI2c{=LGQyfD@-w=r~idTX58h%5a(sal}o;h`wK})auUK^+G%wgN*y+ z6B;tlZa8E@u}8F8#t!aTQ^5qaiC5>KZJ9jydS|IIhV-<73I}vmhWiS#Kf|x&ire&M zUTay-HHA-T;fvPIuAYN>c01;AJ#U*!|9ggpwgVa__RmTV` zHD{iXQ=;t1lF%MKt8)-onLuooY5G6dyAP-)w0vRoQBaU72-1rJ0wP6vM^u^!2ud$O zL8^fCPE@2w6%bIW0@5MUrT5-@FA36HLXAMk+un1|y7Sh%_uZNKW_`0}?qRJTJ1Zpl z6UhGWnw@Jn$ou-R`i*rBEc1w_x*~xP4#JmKI)C;+?lo+a7yJ?(t7&il>Sdij`agkq z{~GhDIc9b+e*GPu_8nM7|OF=k6z(C$@)2TssyT#5MmzdIfsL+ zc5JNaFvs3V2*=);#OR|pT93~7e5IPs1glPr&yMDiDr2h8r^2@4Oxrmj5Q!Byb&T)H zGv2c-TW4$x$rph>-HT787wf# zf!=;MREpJOx%Dr-}j%3{{!~F z-vA{ufBpgxq5sqPfAin}?AJQ%@A3a{ z=Wi+q-JkjU-z0xKAa~kV;nH{__00uZPmu)=j+@nnc2MwUnP~~Dl~DcHVk!hDbX>yTfUIH=_**k7GAGSMC-#V#+?TjP86t) zDVF__7Q(Zn)-R0-LS1QuQ9EqyNNZZ=*a%K5m)v<*2sLaa2@NldY86cTHbu5@uA|>z zYd`!Z(-rl=uGww#K-Rluvm+IPNzs1R92RaHGpXutLT=71v8T-i>+oqRP~-joe}>&3 z`TN?%e~tbZ$)EkNf0z1;fi_LCw2-s-+>2N8Z<)$Wd~rlsTA>B)ES|gE64!~4mx*y2$L&wPtArpgH!&Y(k@E`b3L)rpT9T+LU23}e_ zup<$`(0A2IUhUp)*^c}CUdicwzKx> zYyG4K(_6}6lyioH+tLdM{UUOc1uwuD_dA)=UF^sFQ;r3FAIn8(h%EbfsYDs|Q0Zz7 zljH5^We0wrLX#EyQH|>G%4cL`5<)X)9n74GI^}1*m^^pt@Pq78-U2?qS&pq*|B|0t zGr{BCckgEUy*Pi6wa_0TD}eD#pRqP!K~vAAW~uR~jGY;2<#vWSXxwHnGh-24K*?|w zV?H6Lc}}V)PUW2}Yl{6fQhNgFC>DYoJ|xl+omT7Ole`g18moU)K0m$yM&*dNemBD1 z7S%M~g>seG$2B2;m>2~k&EL@JN=S5nS`6biZXd8HuMs(+#w6@CRv=H>6H-svcSPXv z6`G$+htp4ljAq`AUq~Jkef88!_~SvFppP~>!&&1dCjAk)Y;M&|h9^vB{q;MI?h#X; zdiU3@3btryo15;lb$-gZcLAfl(=>V$D!dKnoz@=(kx`w`Cu~?ClKm>>a-N^^tm}B* zUswujsf{VVKC~c^L0NV%EYbrf?*5U>%3;nRaL<&qIbp>dbI&oe{Bu=Mi($3`({jCy%5U=m zqvMF_-lMEYX$8W_vm3TI*z}-%MP)JlniW>@E=s-AMFLPq2F2S3w}e!m)WhFj<(Iu= zW5Q5TV`tdD^;{-4Z{FyxJwGS+c@vS81?`tDT^BEUiK@^RUV)y?pd!N@ge4C0y5GIv zS1akHo@r&D!gO>pvN+CFxN1D<-3n@P;jbex_jpejgxA?g?E`x4; zY9qR9Yp`b{HtsxQGNXPYPUj|Zkp$=KkRjnplXATOvK{%O{Yd^78NdJ8|NFOTKTcAh z(?STU7mi5P$ry3{&jTWK&m7ky%9r#t9(5_Ry;n|~KkUIMI1L4$nbz5FGFw{=h|nTm z6W`p4nwq&~UHReaGsujf?MmvKW4S<)M1G<*Ih4N-*PHH#gQqgsbk27!9@9@oO?JEJ zGUDhYE&00WVvjoLUJ`cpV+wH)GFQ3tm~M?wM7)2gucpt@6t6WIM(=&WHVYC8U3KzI6PZEW6DbqI!!>et5G+$&oqL zmoL$lUF*Y#TNhpnUN$ys$}xROtw>0l7IO0763@i4VMk@{Gbcpfy)2|KnYv{r~qo$0(ko5BmEl)S?B?vu*5hgl4|RwMEkz zl4L_BTHDNBEhmC_IfsVRiK2_&+U=cGU`Y&%j<6ud3cq+s11(u;nx6h-&nHWdx$FHd zsgu2URWyIQ1YiJVS}^&RN@zf&%Re+Y!QTf*BsfMT0c+arQ^MC2;L=>{-LR0 zy~TOjqoV{pFey4FY`CUzsUI+rXX|uW&OSVe?I?s&JgnJ9GAa-{*&}qekcF! zvfw`;J`Lp8IWB*F{0AWZ#_#ck{sHl6L3!tIh#&H+9sK?C--Z7H@##RR{Wru<{EPUn zfj59Z@D>OJQh*>J7x|B zKjwicU>cYKW`Q|i0YC!?00}GtKY%4*8CV65fHhzp*Z?+xEnpki0Z_m$KnN1h9w_&L z1K<$A03_i0pP)PjPJmP348Z>JLOJ*6=fC_5x8K-D62wF4f|++_F2Ut6C+JjF3^}S< z7wwlr_g(cq@rB&)I^Sa>sLvhAef4wXJf(snx3XFy$vyIn274o4@35Oks)Wo&^L%u| zD|M>i+lcZXo~q2%4dAq_++1)9(|M|{&21I$2QQY>ZMLLcGvaUOg&Ga`QFv58Mvdf= z)jrQsbGF){b)~!>$LQY2qhW%HOv7k2JoaeTuRQA?G%YcleEz{S_c9^vw)!2sN|AP- z>zE}(}8nu8XqI8`wC%!yjQw{H__Cp2u8D_qmRW%^$BitF@?7Om!flM4k(9 zKj&4{2Vt5P?w?>gyj6{%OJ&5QJ(JeW)@N`Xeji@$D4}yL(p^edHdz8LDZE0De&oLG zyX0ffKoR#O$K->V8#cjky7Dk>|8uc_=>oky_B+J<2p#});AgOrr9w06p0Qwp@~r)Y z%Oco^PIXKDa-_ZaeUiLfIXBaL%@6_}?xDFk3KJ)AH=4+%l(JSI)^TYi z_^Al$@GG)cLKuE|W{N#NE-L!21T$8~ajIG*Mq&|_7h1Kv?W`^x{nCC*s2gUbF}cy4 zT59=54#9+`ig#OMOmQvi%}6w%b9^-+EwJ(hPKwRIK`fGCZF0qJL5OZ|VztLDb64W% zc;gz~d^2g!bSARW1x>g5*>$Pqw#LyknwZy|!7lxm?)Z^TY^Wkmrq>kLqVFyUFEuhK z61L+zU37+eDC#JXkU0qw9u?~4x(?eup8Zf%shW{F8dIe^d0&|auk+`=W^ z?X-7K-?6D@2A;`NM2`?;+cRWjU;$&GF>$eHn&tN7>^ED~MJLL8yrx z+n++!W_&y`w$CzVJWiT#3(!fG=@FduYOCv-oQ2blXKhaDSuD}9Pn8UotZ0NoOZgjR zcn&|JYErI^6c*N~B9!79)SX7a zjO0tpBTw?;qJ2%KAmQw$=jcmJue>64WM;;e$>L$ml!t|R`P-Tw1-4D{+6_s0hrZL- zyj!T=Q`Ep>aL97$RCCA&nm%JwepnTk__dWL$-&i|vm`82C~DbsflQ^1$G|7Lq;^XB z^!{zC5AnrIVF{}{S*ezz%#J5d=1(7v2$Qlk!-!N3Fwtjb(o->)i>3_Q1l@1rpYPGW zv(x|8qkS{^N9(_CQ&~$j=rS2{rOK(5Jd}CBPpou7QoOXXu1j^UK5=c;I~?AS ziZ`)#JeKT$2&HwIwPM*K=K7F-C3T0YZ+3<}k*@GDqQ0@7)`M-4AoyUqo>nc}<0f*5 z$BtkAeTi?py<{9`rsN9ejoPY&mDk4V6kgL$e2!b5Ja}-lY%mX9` z7SHTWAw^6^7stbl97eGG+;C&0o!esCyh54`+o2{lz>n^1AeG2vhkDi{-k7F!ZtkpU zrkVDQt2irV#zGiHN?Wae8xDec$Py^&{;F(zfWaW9g<`Vf&}r7h0V<-XsQCyl^+6{N z@etks^&u;vTi*#Jb2y)tk#r>bA*Jj&57{w^}1=we*Iz`xe$N&+D&? zW}GipU<=D5*-aAIhgb2*GHx*6Mw!47Foty<$+_h0DUtkQeFKsFw*rlFzOQ83c;YY| zdGH`<=S8`|BLy?xn?KeQo|wbB13LMreeWt8%LGmxE^Qf8Sv3)Lp!Z0c>TcAR=Gbm0 z*FSESv*4c;YMw9NDy+O3lmlHaw%NI&!FxCZkE7)}cjxRU+?mM9%UL6>B8=^V)vBj< z-jf!!k=z~5Y9jNX^QoHsM_v|i=PP^A!_fNpJDA6diWMKHXN)j#?N80ary2hER~w~?j#&<677xuZ&I7QP zG``fwCN8XB_1g^cSgeCvB|Uw3G-K4dUDrToFcrbFxq_$`O^nRmKp-T*juS3?#;xce(lB;sHO7AoCzb|5ivJiO2hXX*ag~)zn1w9;M)1T zj~o1$#&1}=GST<_oG?uc_Fvg6?7JVERxYc%A@ZDC{juM{PT@)~4pMs5!bF46ZRHPQ zq0ATYz8c-Px#~4?c_v+IqCf1mW+&k~xw;V4$Y6$Jwp6HPgI(*htE&V)#d~>pOuYpT z@-~&M#@7)o>Z{r)c{O9qPhjL0QcTjv$>~bQ`YnP_Xi%^IV zPdCmDxd_4gc0QJ;)=MalX%o>c4^5C1JwD{sRG=?~S-KiIlvtCO8EL_D8@rBnwPJy@*m(XOiJC}x-MUKyXS*$=gK1-mD;PP+mlKQv#_JwL9R4mc~nx3hWCB7mQm~9?&Z(Ei01k- z2k8lNkWDFF;bhS3Cw~xY?KBcwuml^K0(H@AeXYPl4k@$XyCWA?b}8`;|0HM+o=@sI z-Uxklb`?YV1-d3n8G@Ya+Wj%BTp?82?g?SMvU$Nvbm~dkBK}A8XnJsqdcLSxc3Q{? zl4wcV6@BF)iei}ZjAuGATv0bPJ+rNTVQaaL@`LlVc`lrpTzKxyvQmSmPcsbH4Sc7t37+&|tk`YH{W z!A(Vvyf^{tDw|~4QKZgWI(o>W)5T{_N>8J0m-;FFdQ1ezTtjD_bV|S1jH}Iz)4SF- z-I9FX(od&PsdCN2l#-pKBYP>H4Nkc+UlJ4{5_!dV=DOY;<&ku|`|7#&S{|RCb?DVJ zX>_skwc|&BekE{jpDC*aMmFb>cSh0S@OG+j+%zQP3sF=xQ*%T#ryr)kFk3h;v6@M{ zx4O2{V{2RWJXIau1sTDY1Zz-dr2wq~npne6Bl~yQSQv-EUI}eHdiAuyI2w*8(og>BuCue^|d8w)y`3 zWCur~NP3mbSUd7+O!lM=&DH2m$%*;S%$`t+IZh>_1+s;!bZlYHhB-NRwz%|>&R0o3 zI_|n|tPStO<6Y_}Q(LEG%aBa>`iko$=f19ZYV}MEr>kaL>Qu}|(#0g za833%PZDm>ku#W69OQ}oU@6fqEy5TYR7*1Yv6R)1*%ub%n}$cTzYAH&Hoxcp#&4C$ zF(qq!^}k-Z{O#+H`Lp?dnfWurf2;ZL*LV=f8^9lU3k2Z(wii4I2nOE$zWxyk$}k`t zhyWsi_jtdpTm3pqI0pCt!~$_ZJn#|kw|%JzzduG2-f!#FDL^Xl8TbOE0qH;n-f#Ot zGl4818}GM$lDR~RQ`UyYEaeywLl$E4>SOc zKoigmv;eI@8_*7P0G+?zzZ;Z2Krhe-^aBIHATR_B10%pFFb0eR6Tl=e1xy1oz$`Ea z%mWJm;`hg21mzE430MYJfK^}(SpPL&32Xvez&5Z0pa3+m3+w^=zyWXw903^MCvXg$ z0H*-O*#MLn5ixidD_+%QFRxK!iJmHMcz$Fa)4_RBA&9_t0((dcf6K0x>ppBfF+iFlB!qtychyRDtRd-Tr-LXqLMtuFK{5j9eX zlM`O4$78qh9UPJr>>Q-K;5^I_yqsRGgbJB`2@b^!i`B9n{sBz)8PS!K`#$OzAtXQ9 znh8lwq>NE(yi4MK?i-BgSEO*XQ@;tzSTIk}%`wWNBY&9xh6S1-8FbgVn|!09%W2G%HngIGjf_Mt}gl_1HfI44C| zF0fEAIIZK!;ycO& z;_&2poBFG#TBxm{X<5dZwS?#8QMP?wx+7LSuNnKi-qqfhkR|7+Rqaub z)}4<2ud3g@#-^?MWE`AZaS)sS^B&zujYc*1<~gF2DN=(&f$+m1p5@k4%{(_wi1~tU z8X8XMDnoU3v@Lh#(t>4vY}HBa`Kj=L7d@bBiudyNN-seP4}iX!w* zGlv2{UT)BC4mrlIp8w%wyAFH9%wLPCMwvBF9o9Z|uyZWX`x!54b1Bl+oWj44 zu$N2x0bl5<8xmV90kdje$ez#LjtE8IAd$i>?_}xx4N-Gh7xOZ@9$GtJ66f$>OIbYD z?WsRs|J;MO-pb(}4niTVZxcVxU#Nx+so?ZfU{`()**|Gi$|UuwXqTZpLBKYrk>2Ei zUQ+rtk0y&J4Av-o28G0W*3)w!MF;Ty)QR{uIoh)MDNcUcUXHbi|VO`-}jsSDC=*#!z-zTx7M<2HDsANe^em>JisVZ$)(+g@+$BB95+@Nq%8xAYQdjrnlrgu5|Gi%s!v4UUe5>ReYZE4q3h0bWVG)<2n__l;y3;GGH_iuAcixy8#CQ@YrSl0KL&WolLT3Ay_I5!9qW? zhx@`xfbhP z!LVmL)ILw@F!8w_WApmoFaaEk^Q&Tl^`Go+J^l37`zIde4x?Gf2@Rrs>%tdnNtRcq zw-*`O2Yei|rwdA~-3Mbo^u1zB+Mm*6WIou&L7w6%e~jQFOmXzQVM2yKRWF6;Ej)@~z9BNdn<)AoHeM6h{v0#+1|ZZ+ptU>k2t=U*E`k! zYVeuKZ#77!-)lLCJ9Fu(*GGCi{kvf|AJ>lV^bF1Ji*Ko(5l!b7i-#hxr7v=o1?R;G z#<$0%a1io`=od6slKC4Fp78U;xhcBwO}44uPPq*gHl9;KjUxkNkP^HF2YQ=3Yzc;j z(-R^Tl6ZSORFBBJQyihCP_lguJWOblfnqgci{^o`lvY{9I>DPh4hDUX)mo){+dOeG z1;(XIxiURnbbh+DP6KMHa3MLV9oRxPjP`n&7z`D(rsKA_B-m+p`;NCy%PYzK!cYYN zRv9{LQL+5c&8zQkKH@n7Zu~W05qoSH?ZF zt6|%a%i_|yL4JL5#bR&v^Ju3wnyZw;qLTrw)FX~&E>2eRDdv3yV= zQyF>Nthf{Ll|x?9SaQ|(9I9Cv9Z(Q$W5SMZk>zsWimMnZU<FPWKZygM@3jA3aq_{@@se3Fvic8@nN4j(;4bMJu0WS1^{qY?P&?zH3*n zITD_n#bj+=(3JF;VvoPQ#Wr%vePQUP6oapv;rFf!oY;q|gTVxFC!WSLNrhacLw`oE z=+8RW(olz?0z0QrtJ!1Snp2;$y)#)4J{W(G=o$T3B5hcT!K4S}gJoQjM}LlNYct*VSnnBwo(hOFz|8a~oh4tl8zHEwV= zna=i+KoyqUim{Pp8FpBX*{Pi&zQ#Gcd=XB5*X234Y$jcsohplZGFRpY_X+!OG)t2o z@5kxYGq#}v?hek*@|p-mR#$N?FPOpZ{Hx>i}EaEi=e5LG9z zM$%_X5sPBM4)d~=F(UmUELJuB24T5M#5$!+W#RQ#*5D)zdlD!xg9cq|M22)o9%M4 zLo@Ny6Auq>!w8x5N2u5t`?>t+&u8~_hc*|urRfpU_Yidaew-K$lR&|ywz1XFcYGY9m?{0{~GzsCH}pZg#GZN~p6 z!_89A2C?TYTCbz#zBN!Qi-JH zVFjEay!<=MBYiP>#9a2m?Ido|uXrYm0N$xH8<3vQA&;$-*24jNy zXqBMFLdvY{K9798T22yY(@hh9MSb;UPrJmYz5Xml-61MXgCD88{8@WA$k4}UOzT}M zf7AZUKl8_*`Qy+0@n`<{d-KPy_hbBT%pW5Eg!3oz@qT+h%daode?t7K-`8n=eTn@8 z_FprCQV;Ui@4xQ)wSIKrx69)HfcU@S>i-S#ks!VR!EcxUY(M^a@4u-~9+wsLIBFU@ z;~hG^Q-18ac^6@~FtWKB$22Kx(0U`%Z30^Ty-yWFMkCJTzS)hIYGoD}snJL5P|xwD zXIm9b&J+yj9oc;sBVLM+5RW~?rb@k4IqGOXpMfF9L2fL4fsLo(AO_2@=T=Lw-n`L@TphHD8 z!SY?16wmWc&ZRdDZ^IQ;5KoBaQ5wy?c!;I2u`24AY4%Neeap(YWou zs!Q>)pC(v%iJI|L!y?od#x=>X`L;fktruTdbT|=Ry)oO-GphQU9AS{A<*I`ajRV`FE-RSoRa@`qPtE9K?r6w$%X# zk-mOv_v2gM$p;HsL^qb1&AU zXcW;HSL@oCyLO)4+l70Le>K->WC{0l2tE+?cQhxFamGQ`;i@EsV_C`XVq=P>HJ!icjwv+uhCq!vR(+X0MMDBvVrOQ(#l)Z%+2481&e$A3ED}is zW7NSx!dC|D%k=E*c;i}H$v;UaSfmxlU-hR>_vQmGEMaP+Z4>pW~ZNEJZ@+qEUwzPi6Y3j%Lc>LjKmd$Q!cZbx?>^qCEqX}0s z<=ff5+A{DsnmM{>QIG6UU%IXOE#8z6pSq#V+e|jFQq8b!+{;-ccC>q~Lj0PJX+%Z} zqVh3@zTyieRlT{a!F%H!xls4Z&5gAR0;|)jm7~g)BCw6)T}dVht}F+P+<4BhtAbO# z-FF-$1q`Ljr=TWzrMZXConLF12~DRCK9!ZUx^+jbw! zGIp`2$d^-fvNKv#CEM&eF&yo}<}JQQUN!EkGCU{z%CW(0%_Nh~CX%0O-|{_Xj&S?o z(c`YcM#{M7XX|7dYY9J(TF$sD2jI^}Htkd9ET65SS*qHjvqrp`3E^s(PFHbMdCt2G zx=?~;>9Fx$ucRSaf3wQTst9$DPPpn7G3w`2E1v@1#4P)6y1&G9KS9Uk*)f-pX2i!- zDKJg<407YYRE2c5tKSasT?yW<5z4JCSlZeOWrK9+TZRXTH#-rY@^lXA21iG9XwW?l zDe{0Q_ero)`g*`6bfb0Gz3kue+Xq=LlHNUOE3h|<9{c&FZ~Sep#O#P2Cuh|3ZlUbP z!`fk}*wx`_f$de@gWNmsoi1H0b;0T!N)Qz+H5Cpw#J)OnO|C61JQA+|79Q9BcYK!M zANil1;9n#EbN-qC|84R==da|B3O&P6`G(A&c_{qK@(CgC&x)`8mp|ZZ>R9mcwuF=> zzPKG3Q%r8~(-sL0T8SGn45&DNB{k9EVqFp1h1-cyX|iI9>HNY9BhemKNjY9a!7Yl(Fmnw4rN$Vw z^JL5bc{YVdqM6jjVO+o|{XQ#+Xctb&IyN-d*VJcSh`=|#rHS`#CCrq38Ah~rNEv2- zW@0H;5%%@@-mZl4-L|`nEN&m|aj$g;7--EUOsW zBB6O3C47^ndrz}(p&`t%v-7ZUO3#zu>(G+g=%I1CZTjrl#j`;J&K3scQ;9_eZ(BR% zOtz}$3>-{CDU0(JFaua?{Tr{KpckB}&FAN&xH(SlDe^wEAa5h;cvQTC7lm<^z-%A` z`XUjv1}&>vW!VwNL-$DXO|G=jsZzqA4~`QL{jizl!)Kic7ACyh*@#CEOhwI9Gm z(FJ9h@mZ?w)cNwS8g9O#h>0j$tGihdJ31vkrD6U9y=9`X$bZ=&S#q~&&$lM}{N;{- zm)^Qrf!0Djtv3djO$0t!4h6I!7;Z?C@X2+;nMzRklCWUD!pt%|!MRnutDl{UluzTd z?k0)e2F;s0_2%`%OZ(+-5Q~DFH?@sKl@RI}=ltn@#NLJ3{PUcZ2@G$2?4MtF^-?m$ zAH_+%zutE#l_xh*vA@Y0EYJC2 zSbiw07VCcb-PLTwx!+)|P}*H&KInz;yQeCj%fjzI@Q4=0ds8q%VKg4Hy#@k;y&Z%lJq_JBr9h>PfR1xJi^2s?vXNg-)cn< zZYpDz!rO56EQDvIsZq?rQ#?1EC%v~!gTw=`^@?4>*rM`xvq-_lNnN?^_qzM}hC8p~ zZ36aLXx|NBCq$$y+OhkUESN1SUAPueY$e^|aB7*I8lyvqkH{hmkpazU{^#nFV3z$* z)f&gmN)7DA8q1b5_JNu^%RH&&`c>(yT+@Aerb#d5lBslDIXUs?9~-<3$sQVNr-318 z9n!;D$Ji1cw^%z8r>B~|YCb4*)<+elf9bfo&Ve5mUP#zVrAvZBIXX#w2~LQPbpHP~ zuz$3l=l;&~LnZz}^N)&{(k1P}ql00}?}kOAbt zW&GdPT`7Sp02M$DTm@+Ge|wJs9VqDm27nR&w{u6B0TzH2xCUGY*Z_8b1GoWj0$cz$ za1-DGZUMXiAHWX?0Jj0b-(v}bQUnkM!~k(X0+0lx0BJx5kOky`JAgcJ7q|!92NVEB zKnYO({c#_FQWbazr~&GL#;^Y&pb2OJkAWwEHlPFO0(yWxU;r2bMu0J30zd&%;3@D7 zFaykgk7of&OTY@S25bOZ;00g@*aHs0OTZCu0-OOCz!h)<+yM{36Yv7O0Uy8@@B?7L zEByca=YRj%fBxUxe-7Hz!9n(#_)iwJ7#N+`k)_TVxJjwmb$`XH#T9hK7(>^`A;<$ zRi9LpdLU9135T!g&5EXeh#F=!LlYokpArJ!xz?QJ+RM3qB+X*MGwk%5!_g7gB}DamnCqYZ zW81#dQ}36Vsrd`1>g=ks&wAFQrYU#sQq_C7D~CPch`$G*ehk>J?4wV!$L>^B0{aKRkAa0L-kd_m$bD zT&ioQmbS!c3Y!W$w#bejQZX-NqyJw2b#Vy0-N0RF5L9 z_C14=>nCel75g8LHy2!Js)?2E)F-hk9HqBzf%tuV`GYQYsciju7>|RA(g=~A%nL>* zd4t0ihlJE9W=Rd@1GT@KGjzD5#AvDLcg%;~HA$$i{(7l?ca@;YcYg19Cy?ieJUjJd z&$G-9Va?$0Oqj_ok4PIgy~||{+(AQaxWWn87FLh??aLGrk3}*2LNABea=;&$R)ej6C+E8rZ zXyzE}94qZ^>`9sSPiG*2Dq^qaW=akAR3I5z{?$QrV19%2`7po52Q{n+F^Qkj?}CCu zeYNGnN=Lq6Tt@()HDea;Iuu!G&T-~HPDE~a5is#1QUucAmPN4RIv1Sc-53e7XpJr5$Y z&2J@#stY#?@kpCz8s_;fA))4L+%uj5A6FC28f!`$UD$}O%SQ4j^DE^OT@0a|?^}wV zq}uki_Kz--QWq0ZcG1MKXU6%EnRJ;p1d*%SrtT=?!DmzVc6Q#KD7m+K*)!XbFr0su zMFkA& zZVZ2^EzBioV_zKA_{SM2e~Rz~AvMt{J4$wtFFS@})L#3i(a1@~wq_+zb^TspRViI` z39#c3zbU^j(=gV5L4&7OxUP=*vI_sP@r(E>p_6bjpOwH-DvlbZJEcf@V%&cLjv;!? z&GdMyE&;xM(NW3-qz$deZTn1|^)l^{@$6GuEL8j+<5DMbjQGZ@6s=3Ono3n-;3A%H zl_T(F3;IgDjp{9QX-G?B{qqoqjotzKm@m9Ny~+TXa7>U$Pq}R3Ju9C$wMkovHe9}z zYbsKu)osYM4e_^|dyXU-v%mb}0CG&{Ed~eQs1KzV5eGm2LdKAbrl)dL}lN z318`MhU)QdQaWW7(YX8t;z{5voic9;)8WY7&2+B~53V@B#MNN9PM14B8)iZ6y5$)i z*N682x&=^$WOD0;4yxwwv91e;GYw!0zP*x+VqI`>-i8AbarGueu+J&V0l>Cg1nQ4E zRj0Y26+hrzqRS^HxO4lt38U#3b2YYJk|c6_+`o4UzRHc$*qEL6mM($g-5Ag{j|WY_ zd>FpWbgCM!Wi*D#*DYy{j05)H>f=d&7Zz)|q07tE>!{vM*43j>f0iyC4C5p4hxka} zAb$AU6iZG9Zh?`S zL#?wV5kCT?6E#JPn#$DI6Zu8_)A?7==o{mG?&V64?7Qo3Y|TB^;V0*GLtNMS%)clr z-_QA2g?rkpHT{B|xJ`))p)}cBfmG&MFp?nfFqg~Q4JSNEbXABMF&Q^GQj?M7lWi3B zhG9}XP=w^)VL^HlCOQmTN z?y+Ae^&tU``Vff|wUNOpQHJh^>+=<}OjyPPQJe)6 z?hE!(Vt6Kw+#L!TuJN?PIhZ+9;T2@@1Y9yBZ&Sw16sumCykyHt`{AW!&?%xUSlwNm zFLKerJguj=RegkV6Gl#@TjzyiXRedD2u6vlOa5Bj()&l*jZD*2iQ&O{Mih=n6yeDP zwKw5M(V|*JR1+w}C46P*uI#4=c;nBRN-53$d;5fE-w}_XE}CmpTYWLSwi(gxXE#yn z8*qm2Bu)r%!gi=Q-x>WE1A}KLK8FsoDdf1=L&Rg=QQemg^wUQi)x2b!o(@`pUSik^ zi#I`7o%JQk;~#P^Bu50Qn$CU?@0>4#N4qr4&6lDPZJMidTIp`mhXP_Ojux#y#9c#V zqAqh{d<%JT4{)U`S^sg-){&PVkLDP1#|xJ8K9!wDY;I_QM+^J+{|axmtBQY357Yvwwy6%u<~Wcu-+YsCpwKIkxJvs%MI5l zV!52%lvY)_!L*#>p`uT|8poCTM^;^cfoAOam8%;LL1X0uo2DHV<|6a**qsD?xMr5R zz{iHgN1~SN6V_~2;TGY8?%3QS)jYJe2un?Jo4Q~rkRx*rbM>;bnFmEtEp;`hbo00=y#GbXL|T&b94-;)8psB7S#}+=}&O+c6hpTPba{^IgYlvD@08Cs^bnWA9cwE|9t-t3|7v zfPGH+!&%maR8CV#i|GU<>fqC=$I%Bnf!?{;^G{!>IQ^_Nt;jluJa8a>ms^R-R6TiI zE<#&Muf#rPDcT}e{lsxCeIoK1O8DmKh%M`DAq9td&W6;}gBftR`-z~8hTU{h`ER?7 zIMdthUh`S|;V}H86Lo^yYLdmqPUX9&W1!DTps?}TBAW2xI1ay7MR{)l&KE)i9!yhX zY;!UCh{35$;0J!ZcnCXWYMitTH9}6ZrTC{f`$Y#lFFUSQ#+nx&hmzmnDt&8xmp%c8 zzm)rA;m$Ed&kw}3LBUM-X+z?f>K#JB-i`FGy3N%>63%8 z9ovJ=ORORRkO%lOJt!%YRY`jG*E8CcH`Mq-v@E7EptG>XK-$k+Yc-ICIk1rp^r}p! zVlvTq%mjn46Xkk%*}8|bcZQzbc;aHvSUZ{~@~>~(p~++CL2tQCr2tv$8yXk|7Tfaq zV2?>mO4hH?C?xVDs)1?DZ^|PBj*h`7L^(oFG8 z`U>tsPjU){S@OIOn_SaKMzHNe%uiR8N^T%LwMSMh3Cdie;AlN8sXfAG&OLm)?o5*m z+m1xA%`P!tK(+1!3W{{z{U_`}gasxEn-WMVv`GyTas^3+;KYQSBT%Rb*`!pGND2i9 zxTNBVw44-UZIW9x+4~t8+`!3B=bkp}EAHd931B&Vg*&LjRDG$(O8pw|(?+O-X#>BH zLb(jBf|P5`K1CquDd3Eh=|WS>As?MeEnpyyjB%2*^FG!8??USNVzv-sM)Nt!1#cOK zk*yVUtV8Rd>+RsyTTwMHo7!7zzx3Swn7eyAnVy;UHibbS4-OG|#elNZ_-V#Lxu!A~ z`CAa}<%mx}++(rob_*-#q?md+t0sKxmc@4hhfc~{*ks$Eg2ooV*KCK-Sm1F~Qr}7- zwSvrXz;A(rx!XE2Nc1_g991^Tj0__%8s-x}<~Jn(g$v$~njdOg(YJMkM^@SVUJ#eS zcmAvi|G2OCOa2G{O;Fx_eCI3yKgjBCUuW?U*nIu*YuY~y#9>z&sRudrbFC7ad6rezO zaqKz%LqQB&QGn$JI|9rokb@9k;@kE&`#=%GpAt|?0V+Fq2~b54*MV?^zed6Nz7Yi4 z5JHba-UayNeS7(i3jROSk1F7*0*^D#IEBBNEDfO2A&&xHb8C8jjQ@845=<@dx)-|^!RA|5 zFM2Kf#kY=L{8~iZZ{fYj0WYta6nQ+5(*gGcJrD}tTy9rB3BCqjuOq!-;ef(MB~SV5 z3S%cr_xXcg9@0<(#DJrRpuU0Zwd}@6>>6v&~KMoqyPG!&e z7|gB_KN+-$nax2?#@Ys!W6ykdu}XnX}ZV8d>rL|JNV>b6unL_D4??wWg^ z8vUN08$S=5RA3m*f}U=LB->nc`H~UE2>6I8#IGy|32U*3y%c6ATIfE}b*zJ8qJ_8Q zYjZF7=scSx1+(bl*f2?MLMtBGp70tW7BE<)mYsP+7M>?UD~^g1?umx=9_whUTzP;K z6A!OCY|X2d11s)H#N6C80RG!v?4-pqs^gSsWwKU91?S|bq|F$J9xscA=~)Uv&9$Ud%m>n15qT4<+hM#k`mLSYMQ1rqy7cY z)Hxy*VNE#2C;k;ozE8t$AZ}$A){rXE1Kfai^rfc$!(8kf@dl>DR@fPX7g8@o6vYGA z(ezf_gOB+03iH5q<4Rby&vTmC>;=J0y#2R6ty^AP;=3!kYr?!~m-^wx zYj`^WqV!8NZ(lUa7#vq(N42$=2-V+->{0B7m$2Wn+^U{^7K;ZnwenvFO?N4px*F79 zJd!QX#>;i<VpUUECD3@+(|d5m=%sR9;8Y4+4{ z@gBKC#r9F9URV&ohE9Wgk~YW<7qzVIV9un~IH0OM$TL>HA!c<~W*v-_CTI;A?ylK^ zF`a%8vCx4S0yF?GMVLCogtqSL_huN3oH3BsIOk9|H_24Xrin#SRPa0fkQ4WF$;vW& zjM$SdSb(FwE8NslL`!>ZFDgx6z?F4Gl%(JoVYhtz<<)^MACq%tGM0cZ*wC4Ry@(vPxhJa$0fr~n{P;Ds_I@8C@ZyUQJObYMc+qN9mUdjBX^3! zHB^e|cE)Y{IrftmJLy;Cure~cXF^j0@A~~S&6d6a`nq;rS8OWY$B$J03xnUX#jdRi zyqEHVcsnC%<8HEt$^lXQa*YOJQ?cA}bI8f{`lOtra@P53j&iM>0xdDru%D-c=U2C8`<$ zf5LL1*R#*pqZNZPX0&UA*bX;hhpl!HCNIg5U^s8PyRH40FCKn`{gDG*hsRu^+s)ZEq>H_ziU`gsXEuxC3cfsQs9|fE6 zgFELRQ%33vY_jO*3Q7y^!NcO{EvNYN*g-|Ck>W;op=|Tk=F17e4$d?UXKJEiC-)T8 zBRzTkYKP*M78yY2-o1b%2h9}eikOAkrq*3d5Gx9!TIn4P3ICV zJBd;m0b1W)axq0VYg!7)+O#Vh3LXi4lL}US&nfYG!~bn>(B8@3@aG?fWL+r z`|W)Kz)D4$LZvmf4gIrp_x?pI-=P3kGB;WhmzPJw35u#j>(xf+#(8T)qX8Cr3_h>N zP9neHmBw{@MxESFAJA0NGOGC~U}ic*Lj{={sd^$bvqctrjEAJ(tYH`D5!Go8YYcKR z_y_@bqO~+1LzSQLY}j%soP{_`v}zBr2pq{}clg5Hmlre*Q#yMbX}=dj$4MU`CV%WYVD)i;uPB^<>yZZq>W5LK>$X`T6H*8qquAtuoXD5 z)%V^sjoROCkz1ePGp&>xHPY_*4w(2&gTFCXRN zlx~`5xD)UjDQ72j_E|IyrFrY9&ye{?*q*9TLJ2=Tk;d*#_v!_{2z-8UILRPDc6mdf zNh1Tr7o4Kuok-)lke#oaPj-U=kvRLo*`9Y3aSp2u)MtOLtQ~Cz>nJT`C-XB3lkXs= zCf+gBzLTLE=%AX6);K%KJ&R$vk`FNBdZd*`AbDPs>vq;Q5VOZT9+`0Oi+zeV7D2)% z@&v=&t5b>C)lzZlG0{aS=EM(e3ePYyk-W#zK=NKMJc^-C4y#@0@f@)gqsG1Ox$RZ! z?GMcX3U;Vm9U_}G80p6|4EFDj8SI`JwN0*&WPV#CI~&bKr@2*JjI!LudCTza@V6)R zNXYYBRQx#y%jNCq5II#E_qQi3YK!1nOZiy!8>Gm<(wz>J4GBaNe>#kQc$FAb@Xn;= zWed$cTbanEac6^=vcclWM%5Z|jmc$?-0D#!7CRs^5?}0Em`A}6rcBI(>FP8%yRq9<4QR@$!=jt z>}x;}7XkP%;vSFr)0#t&Ky_punsL8PYox^Wyp+OY_8m&b;H&V^C2Svc;7QO-F7r5= zUX$xs;pbW+q?G@(v~5K@)(VbJV#)!g`bQ z$PEDv*jyU1TBGN$Bh28Vu#s$|+_zaxja82kA(l)Xqo^_JMcT(t_aL;*y0woxYQ6Cp z_c1RTt;hqBr9W2Lj4o-Sz}>6b(n9lmUKGVDF@g$&!z2vQ*HF6L(H=+J4Vb?$_4ebq z?M9Ll+IE@QT27|AcsYDRg6!5W@XSuAhz6^)wXEWYjJJQr6*{ojuK zNHC=0Gkas{qJkVV<^6lr54_xrd+FI`w24x11Nm}!LW0OGX%IlIq2|Y|(DQ!BY2c@Uw&P_Cf=NL*)`D6%jZ{TY&9>BZiH3Ha?433!3EMByQuJD!v+| z@AT633D$%!VeHxwsT;RcTPTQmEo#T$(`}Hn^Vt;!TpkWmu|zNR42X%Ogkxw#d>{W_2yUXimx7wyCVp0Ba_S%l={3o?;pPW+LMoAd zx%ShZX_uIL$jGBbd_=h(9tic~x-}V+6VBz@^y1VI$Q-5Ca=S5mDq1`0^=PcNKr&Re z$flg_iSCBwto=|7pJSo-bef7%SjMSRQKeVFbmzL@aXB9m#1a*TsCSq)ept^NXNnr% zKY}p{C`Q+j7<2Bia(626VpvFfDHG(Rd-oMOh04b;-u_tD_;GG_nf4+$fVVV0CPg;{ zFo{Ioy5_HhzwucizbKBZi|WWpAggZgC4GqMbK%GEyIrN@ERt}i)veyMiFR1l&sYfC zD3$ed+Cerh$6hBPvZsyYh52hrL3>eTEbxeOlv3q;T%Qnonb>17^{UFPm}Dfc(eU<7 z7+Estf>~&OA3^soPO?6w4vRIZXkCE{#i{SDtM2tXv-dzKWIwH?5(jl$nnnFr)ZDX> zw8NH>Qr)E3xNYNMw3NoFbYzjFy}1XT?pEP?>5>^*ZJL8ln&8jamh<7 zm+7F=upjceu?ul!nS>OmhG@;>RT7k$*Ge%l+O`!Meho@VCWI{mYC?p&BDam%PHJ7J z#8r%e97{?5q|+P2Xk4XE13YJ$gi}A-qQ$@OI$m3#h|fFt!a`$H;dAPzHx-fGQC$;B zJUTR3x%x9_dJ#o%J_?z_5OrRXV3J)I=G9=}g>`Gd0rZvW6qgb^{K~hG13h2KUeh=- z!0_KYH-#j2k`_#Zet=Qcn<^K(OkymUU#e9OJ{{hh2mp2&P?ph=s* zFobp|4xG6LRSq3pdQ_149T_nGMhhn`7C7z{sNRDF{b}86qaEXB9l_y{@5mx@vMIT< zGkb^&z6mf?)ivZRQ1dlP7igntPSCkt{5T8K>y=guj~UNnCF3tN_U$IS{aJV+^tEY; zqAR%#4&7wf#5i~OhdFb(9y`4vv@rBE$YYJZp>RMdz9pd7sSD@fQ&K%)#9xt9p zW$%2pg|Re+i!#&OD@D`UCO|1y;Kw(5_Oi{X(U%38`FMIg^r-b9@3ElGT5zB83I+XU5O` zS#*k7MaRa-S-X1ogYMZ;eY2=9M=*I+Jjf{}#FZK(9|1wwpfclM#xcUIb#w#OPWfJ> zcqa!&ahdnKcZI&JNzPJw4P`^B@+5Xz@~NnLf`}6X6p5-)fuN49p|7ncn0m|YHxF3E z$jBgsYY(VKxog=zKT_m#GrRR6)U&@UCs(NrRC$`)G4URww47PcV&3 zUtQqY)LW1L&p)j`7~a8|;!DDH$_T}}v?-p^#PG(O^%wFwu?cogBaoC45^7!=0B**) z{f#f8TX)!*&|j#eRPWWJOX_*#tja3`#}lkyo^$yUdsI+RHqG2vDXHvuH8VBzVVV{d z%S=%WTOJo(YzKEa+6|KR(*ex5{?yCM+F78~ZkWsaLT59Vmb|niKZJo*97nIE)cEf) zx<|8eHa4A!Z^c7Re`fd+>+6?dTa~HWwgg9+=z*0b^}A7v$nRn>z~fzkf&oN4h#1W# zL{I3SO?UW;O~@Dt%!+GWrI;CiLjSd17Up3gqPmnk=OwUSJqR((^Fu(gYLN7V)a*y( zC=BKkHohtM8N5ipz_fA0+^q=>i)s-qP%J|AMGiEeEWWq0D; zo#7YXmzCKL1I3c+g_Dx6yu?`j%zxhg;EpQq&1@Ch07&_nzclWDJ0&=Fo0pfs7iSF) zIw%yPJ*<&JJbYa$-hFmbClI$$ykigRf#((`_a}Cq{4KcRaoB>S9iu3>FqMtIV9=Y7 z=c?>>QulUQaoyx2$s-y+*cjV!H)|ZWotT_ogA;b~AeTdkr!vIgU+>|tvKB-*a#zr~ z9DW$D&w^or5^Hs+L4~bzo%#Gqo52yE5Af0)c}=!|NJ9bkSYTJL5N1%wwppw_vhdpQ zsSSRNWw{lf)(I6}sm-~~(NWJ-1#y>0F+G1*Espq%R4pcax!xMMzT_VQ$#3{~`}e

he3Lz|~C=LfwL^t7GBd?zc3Mzq~y8zVPLb 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 +#include +#include +#include +#include "utilci.h" /* Header file for DB2CI sample code */ + +int TbCreate( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ); +int TbCompress( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ); +int TbDrop( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ); + +int main(int argc, char *argv[]) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIEnv * envhp; /* environment handle */ + OCISvcCtx * svchp; /* connection handle */ + OCIError * errhp; /* error handle */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* checks the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO USE NULL AND DEFAULT VALUE\n"); + printf("COMPRESSION OPTION AT TABLE LEVEL AND COLUMN LEVEL.\n"); + + /* initialize the DB2CI application by calling a helper + utility function defined in utilci.c */ + rc = CIAppInit(dbAlias, + user, + pswd, + &envhp, + &svchp, + &errhp ); + if (rc != 0) + { + return rc; + } + + /* create the table */ + rc = TbCreate( envhp, svchp, errhp ); + + /* enable the compression option at table level */ + rc = TbCompress( envhp, svchp, errhp ); + + /* drop the table */ + rc = TbDrop( envhp, svchp, errhp ); + + /* terminate the DB2CI application by calling a helper + utility function defined in utilci.c */ + rc = CIAppTerm(&envhp, &svchp, errhp, dbAlias); + + return rc; +} /* main */ + +/* create the comp_tab table */ +int TbCreate( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + + char *stmt = + (char *)"CREATE TABLE COMP_TAB(Col1 INT NOT NULL WITH DEFAULT, " + "Col2 CHAR(7), " + "Col3 VARCHAR(7) NOT NULL, " + "Col4 DOUBLE)"; + + printf("\n-----------------------------------------------------------"); + printf("\nCreating table COMP_TAB\n\n"); + printf("USE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCIHandleFree\n"); + printf("TO SHOW HOW TO CREATE A TABLE:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* create the table */ + printf("\n Directly execute the statement\n"); + printf(" CREATE TABLE COMP_TAB(Col1 INT NOT NULL WITH DEFAULT,\n"); + printf(" Col2 CHAR(7),\n"); + printf(" Col3 VARCHAR(7) NOT NULL,\n"); + printf(" Col4 DOUBLE)\n"); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbCreate */ + +/* how to enable the compress option on table level */ +int TbCompress( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + + char *stmt1 = (char *)"ALTER TABLE COMP_TAB ACTIVATE " + "VALUE COMPRESSION"; + char *stmt2 = (char *)"ALTER TABLE COMP_TAB ALTER Col1 COMPRESS " + "SYSTEM DEFAULT"; + char *stmt3 = (char *)"ALTER TABLE COMP_TAB DEACTIVATE " + "VALUE COMPRESSION"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCIHandleFree\n"); + printf("TO SHOW HOW TO ALTER A TABLE FOR COMPRESSION OPTION:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n To activate VALUE COMPRESSION at table level and COMPRESS \n"); + printf(" SYSTEM DEFAULT at column level \n\n"); + + printf("\n Directly execute the statement\n"); + printf(" ALTER TABLE COMP_TAB ACTIVATE VALUE COMPRESSION \n\n"); + printf(" Rows will be formatted using the new row format on subsequent\n"); + printf(" insert, load and update operation, and NULL values will not be\n"); + printf(" taking up space if applicable.\n\n"); + + /* If the table COMP_TAB does not have many NULL values, enabling + compression will result in using more disk space than using + the old row format */ + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt1, + strlen( stmt1 ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n To save more disk space on system default value for column\n"); + printf(" Col1, enter\n"); + + printf("\n Directly execute the statement\n"); + printf(" ALTER TABLE COMP_TAB ALTER Col1 COMPRESS SYSTEM DEFAULT\n"); + printf("\n On subsequent insert, load, and update operations,numerical\n"); + printf(" 0 value (occupying 4 bytes of storage) for column Col1 will\n"); + printf(" not be saved on disk.\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt2, + strlen( stmt2 ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n\n To switch the table to use the old format, enter\n"); + printf("\n Directly execute the statement\n"); + printf(" ALTER TABLE COMP_TAB DEACTIVATE VALUE COMPRESSION\n\n"); + printf(" Rows inserted, loaded or updated after the ALTER statement\n"); + printf(" will have old row format.\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt3, + strlen( stmt3 ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbCompress */ + +/* drop the table comp_tab */ +int TbDrop( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + + char *stmt = (char *)"DROP TABLE COMP_TAB"; + + printf("\n-----------------------------------------------------------"); + printf("\nDropping table COMP_TAB\n\n"); + printf("USE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCIHandleFree\n"); + printf("TO SHOW HOW TO DROP A TABLE:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* drop the table */ + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbDrop */ diff --git a/db2ci/tbcreate.c b/db2ci/tbcreate.c new file mode 100644 index 0000000..ca56c61 --- /dev/null +++ b/db2ci/tbcreate.c @@ -0,0 +1,213 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2009 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: tbcreate.c +** +** SAMPLE: How to create and drop tables +** +** DB2CI FUNCTIONS USED: +** OCIHandleAlloc -- Allocate Handle +** OCIStmtPrepare -- Prepare a SQL statement +** OCIStmtExecute -- Execute a SQL statement +** OCIHandleFree -- Free Handle Resources +** +** OUTPUT FILE: tbcreate.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilci.h" /* Header file for DB2CI sample code */ + +int TbCreate( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ); +int TbDrop( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ); + +int main(int argc, char *argv[]) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIEnv * envhp; /* environment handle */ + OCISvcCtx * svchp; /* connection handle */ + OCIError * errhp; /* error handle */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO CREATE AND DROP TABLES.\n"); + + /* initialize the DB2CI application by calling a helper + utility function defined in utilci.c */ + rc = CIAppInit(dbAlias, + user, + pswd, + &envhp, + &svchp, + &errhp ); + if (rc != 0) + { + return rc; + } + + /* create a table */ + rc = TbCreate( envhp, svchp, errhp ); + /* drop a table */ + rc = TbDrop( envhp, svchp, errhp ); + + /* terminate the DB2CI application by calling a helper + utility function defined in utilci.c */ + rc = CIAppTerm(&envhp, &svchp, errhp, dbAlias); + + return rc; +} /* main */ + +/* create a table */ +int TbCreate( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + + char *stmt = (char *)"CREATE TABLE TBDEFINE(Col1 SMALLINT, " + " Col2 CHAR(7), " + " Col3 VARCHAR(7), " + " Col4 DEC(9,2), " + " Col5 DATE, " + " Col6 BLOB(5000), " + " Col7 CLOB(5000))"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCIHandleFree\n"); + printf("TO SHOW HOW TO CREATE A TABLE:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* create the table */ + printf("\n Directly execute the statement\n"); + printf(" CREATE TABLE TBDEFINE(Col1 SMALLINT,\n"); + printf(" Col2 CHAR(7),\n"); + printf(" Col3 VARCHAR(7),\n"); + printf(" Col4 DEC(9,2),\n"); + printf(" Col5 DATE,\n"); + printf(" Col6 BLOB(5000),\n"); + printf(" Col7 CLOB(5000))\n"); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbCreate */ + +/* drop a table */ +int TbDrop( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + + char *stmt = (char *)"DROP TABLE TBDEFINE"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCIHandleFree\n"); + printf("TO SHOW HOW TO DROP A TABLE:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* drop the table */ + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbDrop */ + diff --git a/db2ci/tbmod.c b/db2ci/tbmod.c new file mode 100644 index 0000000..b6aef4c --- /dev/null +++ b/db2ci/tbmod.c @@ -0,0 +1,624 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2007 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: tbmod.c +** +** SAMPLE: How to modify table data +** +** CI FUNCTIONS USED: +** OCIHandleAlloc -- Allocate Handle +** OCIBindByPos -- Bind a Parameter Marker to a Buffer or +** LOB locator +** OCITransCommit/OCITransRollback -- End Transactions of a Connection +** OCIStmtExecute -- Execute a Statement +** OCIStmtFetch -- Fetch Next Row +** OCIHandleFree -- Free Handle Resources +** OCIStmtPrepare -- Prepare a Statement +** OCIAttrSet -- Set Connection Attributes +** +** OUTPUT FILE: tbmod.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilci.h" /* Header file for CI sample code */ + + +/* methods to perform INSERT */ +int TbBasicInsert( OCIEnv * envhp, OCISvcCtx * stmthp, OCIError * errhp ); +int TbInsertWithParam( OCIEnv * envhp, OCISvcCtx * stmthp, OCIError * errhp ); + +/* methods to perform UPDATE */ +int TbBasicUpdate( OCIEnv * envhp, OCISvcCtx * stmthp, OCIError * errhp ); +int TbUpdateWithParam( OCIEnv * envhp, OCISvcCtx * stmthp, OCIError * errhp ); + +/* methods to perform DELETE */ +int TbBasicDelete( OCIEnv * envhp, OCISvcCtx * stmthp, OCIError * errhp ); +int TbDeleteWithParam( OCIEnv * envhp, OCISvcCtx * stmthp, OCIError * errhp ); + +int main(int argc, char *argv[]) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIEnv * henv; /* environment handle */ + OCISvcCtx * hdbc; /* connection handle */ + OCIError * errhp; /* error handle */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO MODIFY TABLE DATA.\n"); + + /* initialize the CI application by calling a helper + utility function defined in utilci.c */ + rc = CIAppInit(dbAlias, + user, + pswd, + &henv, + &hdbc, + &errhp ); + if (rc != 0) + { + return rc; + } + + /* methods to perform INSERT */ + rc = TbBasicInsert( henv, hdbc, errhp ); + rc = TbInsertWithParam( henv, hdbc, errhp ); + + /* methods to perform UPDATE */ + rc = TbBasicUpdate(henv, hdbc, errhp ); + rc = TbUpdateWithParam(henv, hdbc, errhp); + + /* methods to perform DELETE */ + rc = TbBasicDelete(henv, hdbc, errhp ); + rc = TbDeleteWithParam(henv, hdbc, errhp); + + /* terminate the CI application by calling a helper + utility function defined in utilci.c */ + rc = CIAppTerm(&henv, &hdbc, errhp, (char *)dbAlias); + + return rc; +} /* main */ + +/* perform a basic INSERT operation */ +int TbBasicInsert( OCIEnv * henv, OCISvcCtx * hdbc, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + + /* SQL INSERT statement to be executed */ + char *stmt = (char *) + "INSERT INTO org(deptnumb, location) " + " VALUES(120, 'Toronto'), (130, 'Vancouver'), (140, 'Ottawa')"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCITransRollback\n"); + printf(" OCIHandleFree\n"); + printf("TO PERFORM A BASIC INSERT:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)henv, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Directly execute the statement\n"); + printf(" INSERT INTO org(deptnumb, location)\n"); + printf(" VALUES(120, 'Toronto'),\n"); + printf(" (130, 'Vancouver'),\n"); + printf(" (140, 'Ottawa')\n"); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + hdbc, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on a connection */ + ciRC = OCITransRollback( hdbc, errhp, OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbBasicInsert */ + +/* perform an INSERT operation with an SQL statement + that contains parameter markers */ +int TbInsertWithParam( OCIEnv * henv, OCISvcCtx * hdbc, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIBind * hBind1 = NULL; + OCIBind * hBind2 = NULL; + OCIStmt * hstmt; /* statement handle */ + /* SQL INSERT statement with parameter markers to be executed */ + char *stmt = (char *) + "INSERT INTO org(deptnumb, location) VALUES(:1, :2)"; + sb2 parameter1[] = { 120, 130, 140 }; + char parameter2[][20] = { "Toronto", "Vancouver", "Ottawa" }; + int row_array_size = 3; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CI FUNCTIONS\n"); + printf(" OCIHandleHandle\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIBindByPos\n"); + printf(" OCIStmtExecute\n"); + printf(" OCITransRollback\n"); + printf(" OCIHandleFree\n"); + printf("TO SHOW HOW TO EXECUTE AN INSERT STATEMENT\n"); + printf("WITH PARAMETERS:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)henv, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Prepare the statement\n"); + printf(" INSERT INTO org(deptnumb, location) VALUES(:1, :2)\n"); + + /* prepare the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Bind parameter1 and parameter2 to the statement.\n"); + + /* bind parameter1 to the statement */ + ciRC = OCIBindByPos( + hstmt, + &hBind1, + errhp, + 1, + parameter1, + sizeof( sb2 ), + SQLT_INT, + NULL, + NULL, + NULL, + 0, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* bind parameter2 to the statement */ + ciRC = OCIBindByPos( + hstmt, + &hBind2, + errhp, + 2, + parameter2, + 20, + SQLT_STR, + NULL, + NULL, + NULL, + 0, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* execute the statement for a set of values */ + printf("\n Execute the prepared statement for\n"); + printf(" parameter1 = { 120, 130, 140 }\n"); + printf(" parameter2 = { 'Toronto', 'Vancouver', 'Ottawa' }\n"); + + /* execute the statement */ + ciRC = OCIStmtExecute( + hdbc, + hstmt, + errhp, + 3, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on a connection */ + ciRC = OCITransRollback( hdbc, errhp, OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbInsertWithParam */ + +/* perform a basic UDPATE operation */ +int TbBasicUpdate( OCIEnv * henv, OCISvcCtx * hdbc, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + /* SQL UPDATE statement to be executed */ + char * stmt = (char *) + "UPDATE org SET location = 'Toronto' WHERE deptnumb < 50"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCITransRollback\n"); + printf(" OCIHandleFree\n"); + printf("TO PERFORM A BASIC UPDATE:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)henv, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Directly execute the statement\n"); + printf(" UPDATE org SET location = 'Toronto' WHERE deptnumb < 50\n"); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + hdbc, + hstmt, + errhp, + 1, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on a connection */ + ciRC = OCITransRollback( hdbc, errhp, OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbBasicUpdate */ + +/* perform an UPDATE operation with an SQL statement + that contains parameter markers */ +int TbUpdateWithParam( OCIEnv * henv, OCISvcCtx * hdbc, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIBind * hBind1 = NULL; + OCIBind * hBind2 = NULL; + OCIStmt * hstmt; /* statement handle */ + /* SQL UPDATE statement with parameter markers to be executed */ + char *stmt = (char *) + "UPDATE org SET location = :1 WHERE deptnumb < :2"; + char parameter1[20]; + sb2 parameter2; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIBindByPos\n"); + printf(" OCIStmtExecute\n"); + printf(" OCITransRollback\n"); + printf(" OCIHandleFree\n"); + printf("TO SHOW HOW TO EXECUTE AN UPDATE STATEMENT\n"); + printf("WITH PARAMETERS:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)henv, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Prepare the statement\n"); + printf(" UPDATE org SET location = :1 WHERE deptnumb < :2\n"); + + /* prepare the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Bind parameter1 and parameter2 to the statement.\n"); + + /* bind parameter1 to the statement */ + ciRC = OCIBindByPos( + hstmt, + &hBind1, + errhp, + 1, + parameter1, + 20, + SQLT_STR, + NULL, + NULL, + NULL, + 0, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* bind parameter2 to the statement */ + ciRC = OCIBindByPos( + hstmt, + &hBind2, + errhp, + 2, + ¶meter2, + sizeof( sb2 ), + SQLT_INT, + NULL, + NULL, + NULL, + 0, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* execute the statement for a set of values */ + strcpy((char *)parameter1, "Toronto"); + parameter2 = 50; + + printf("\n Execute the prepared statement for\n"); + printf(" parameter1 = %s\n", parameter1); + printf(" parameter2 = %d\n", parameter2); + + /* execute the statement */ + ciRC = OCIStmtExecute( + hdbc, + hstmt, + errhp, + 1, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on a connection */ + ciRC = OCITransRollback( hdbc, errhp, OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbUpdateWithParam */ + +/* perform a basic DELETE operation */ +int TbBasicDelete( OCIEnv * henv, OCISvcCtx * hdbc, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + /* SQL DELETE statement to be executed */ + char *stmt = (char *)"DELETE FROM org WHERE deptnumb < 50"; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCITransRollback\n"); + printf(" OCIHandleFree\n"); + printf("TO PERFORM A BASIC DELETE:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)henv, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + hdbc, + hstmt, + errhp, + 1, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on a connection */ + ciRC = OCITransRollback( hdbc, errhp, OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbBasicDelete */ + +/* perform a DELETE operation with an SQL statement + that contains parameter markers */ +int TbDeleteWithParam( OCIEnv * henv, OCISvcCtx * hdbc, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIBind * hBind = NULL; + OCIStmt * hstmt; /* statement handle */ + /* SQL DELETE statement with parameter markers to be executed */ + char *stmt = (char *)"DELETE FROM org WHERE deptnumb < :deptnumb"; + sb2 parameter1; + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIBindByName\n"); + printf(" OCIStmtExecute\n"); + printf(" OCITransRollback\n"); + printf(" OCIHandleFree\n"); + printf("TO SHOW HOW TO EXECUTE A DELETE STATEMENT\n"); + printf("WITH NAMED PARAMETERS:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)henv, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Prepare the statement\n"); + printf(" %s\n", stmt); + + /* prepare the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Bind parameter1 to the statement.\n"); + + /* bind parameter1 to the statement */ + ciRC = OCIBindByName( + hstmt, + &hBind, + errhp, + ":deptnumb", + strlen( ":deptnumb" ), + ¶meter1, + sizeof( sb2 ), + SQLT_INT, + NULL, + NULL, + NULL, + 0, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* execute the statement for parameter1 = 50 */ + parameter1 = 50; + printf("\n Execute the prepared statement for\n"); + printf(" parameter1 = %d\n", parameter1); + + /* execute the statement */ + ciRC = OCIStmtExecute( + hdbc, + hstmt, + errhp, + 1, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on a connection */ + ciRC = OCITransRollback( hdbc, errhp, OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf(" Transaction rolled back.\n"); + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbDeleteWithParam */ + diff --git a/db2ci/tbread.c b/db2ci/tbread.c new file mode 100644 index 0000000..9fdb7bf --- /dev/null +++ b/db2ci/tbread.c @@ -0,0 +1,598 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2009 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: tbread.c +** +** SAMPLE: How to read data from tables +** +** DB2CI FUNCTIONS USED: +** OCIHandleAlloc -- Allocate Handle +** OCIDefineByPos -- Bind a Column to an Application Variable or +** LOB locator +** OCIBindByPos -- Bind a Parameter Marker to a Buffer or +** LOB locator +** OCIAttrGet -- Return a Column Attribute +** OCIStmtPrepare -- Prepare a statement +** OCIStmtExecure -- Execute a Statement +** OCIStmtFetch -- Fetch Next Row. +** OCIStmtFetch2 - Fetch next rowset. +** OCIHandleFree -- Free Handle Resources +** +** OUTPUT FILE: tbread.out (available in the online documentation) +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilci.h" /* Header file for DB2CI sample code */ + +#define ROWSET_SIZE 5 + +int TbBasicSelectUsingFetch( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ); +int TbSelectWithParam( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ); +int TbSelectWithUnknownOutCols( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ); + +int main(int argc, char *argv[]) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIEnv * envhp; /* environment handle */ + OCISvcCtx * svchp; /* connection handle */ + OCIError * errhp; /* error handle */ + + char dbAlias[SQL_MAX_DSN_LENGTH + 1]; + char user[MAX_UID_LENGTH + 1]; + char pswd[MAX_PWD_LENGTH + 1]; + + /* check the command line arguments */ + rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd); + if (rc != 0) + { + return rc; + } + + printf("\nTHIS SAMPLE SHOWS HOW TO READ TABLES.\n"); + + /* initialize the DB2CI application by calling a helper + utility function defined in utilci.c */ + rc = CIAppInit(dbAlias, + user, + pswd, + &envhp, + &svchp, + &errhp ); + if (rc != 0) + { + return rc; + } + + /* basic SELECT */ + rc = TbBasicSelectUsingFetch( envhp, svchp, errhp ); + + /* SELECT with parameter markers */ + rc = TbSelectWithParam( envhp, svchp, errhp ); + + /* SELECT with unknown output columns */ + rc = TbSelectWithUnknownOutCols(envhp, svchp, errhp ); + + /* terminate the DB2CI application by calling a helper + utility function defined in utilci.c */ + rc = CIAppTerm(&envhp, &svchp, errhp, dbAlias); + + return rc; +} /* main */ + +/* perform a basic SELECT operation using OCIDefineByPos */ +int TbBasicSelectUsingFetch( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + OCIDefine * defnhp1 = NULL; /* define handle */ + OCIDefine * defnhp2 = NULL; /* define handle */ + /* SQL SELECT statement to be executed */ + char *stmt = (char *)"SELECT deptnumb, location FROM org"; + + struct + { + sb2 ind; + sb2 val; + ub2 length; + ub2 rcode; + } + deptnumb; /* variable to be bound to the DEPTNUMB column */ + + struct + { + sb2 ind; + char val[15]; + ub2 length; + ub2 rcode; + } + location; /* variable to be bound to the LOCATION column */ + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCIDefineByPos\n"); + printf(" OCIStmtFetch\n"); + printf(" OCIHandleFree\n"); + printf("TO PERFORM A BASIC SELECT USING OCIDefineByPos:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Directly execute the statement\n"); + printf(" %s\n", stmt); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* define column 1 to variable */ + ciRC = OCIDefineByPos( + hstmt, + &defnhp1, + errhp, + 1, + &deptnumb.val, + sizeof( sb2 ), + SQLT_INT, + &deptnumb.ind, + &deptnumb.length, + &deptnumb.rcode, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* define column 2 to variable */ + ciRC = OCIDefineByPos( + hstmt, + &defnhp2, + errhp, + 2, + location.val, + sizeof( location.val ), + SQLT_STR, + &location.ind, + &location.length, + &location.rcode, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Fetch each row and display.\n"); + printf(" DEPTNUMB LOCATION \n"); + printf(" -------- -------------\n"); + + /* fetch each row and display */ + ciRC = OCIStmtFetch( + hstmt, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + if (ciRC == OCI_NO_DATA ) + { + printf("\n Data not found.\n"); + } + while (ciRC != OCI_NO_DATA ) + { + printf(" %-8d %-14.14s \n", deptnumb.val, location.val); + + /* fetch next row */ + ciRC = OCIStmtFetch( + hstmt, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + } + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbBasicSelectUsingFetch */ + +/* perform a SELECT that contains parameter markers */ +int TbSelectWithParam( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + OCIDefine * defnhp1 = NULL; /* define handle */ + OCIDefine * defnhp2 = NULL; /* define handle */ + OCIBind * hBind = NULL; /* bind handle */ + + char *stmt = (char *) + "SELECT deptnumb, location FROM org WHERE division = :1"; + + char divisionParam[15]; + + struct + { + sb2 ind; + sb2 val; + ub2 length; + ub2 rcode; + } + deptnumb; /* variable to be bound to the DEPTNUMB column */ + + struct + { + sb2 ind; + char val[15]; + ub2 length; + ub2 rcode; + } + location; /* variable to be bound to the LOCATION column */ + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCIBindByPos\n"); + printf(" OCIDefineByPos\n"); + printf(" OCIStmtFetch\n"); + printf(" OCIHandleFree\n"); + printf("TO PERFORM A SELECT WITH PARAMETERS:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Prepare the statement\n"); + printf(" %s\n", stmt); + + /* prepare the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Bind divisionParam to the statement\n"); + printf(" %s\n", stmt); + + /* bind divisionParam to the statement */ + ciRC = OCIBindByPos( + hstmt, + &hBind, + errhp, + 1, + divisionParam, + sizeof( divisionParam ), + SQLT_STR, + NULL, + NULL, + NULL, + 0, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* execute the statement for divisionParam = Eastern */ + printf("\n Execute the prepared statement for\n"); + printf(" divisionParam = 'Eastern'\n"); + strcpy(divisionParam, "Eastern"); + + /* execute the statement */ + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* bind column 1 to variable */ + ciRC = OCIDefineByPos( + hstmt, + &defnhp1, + errhp, + 1, + &deptnumb.val, + sizeof( sb2 ), + SQLT_INT, + &deptnumb.ind, + &deptnumb.length, + &deptnumb.rcode, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* bind column 2 to variable */ + ciRC = OCIDefineByPos( + hstmt, + &defnhp2, + errhp, + 2, + location.val, + sizeof( location.val ), + SQLT_STR, + &location.ind, + &location.length, + &location.rcode, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Fetch each row and display.\n"); + printf(" DEPTNUMB LOCATION \n"); + printf(" -------- -------------\n"); + + /* fetch each row and display */ + ciRC = OCIStmtFetch( + hstmt, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + if (ciRC == OCI_NO_DATA ) + { + printf("\n Data not found.\n"); + } + while (ciRC != OCI_NO_DATA ) + { + printf(" %-8d %-14.14s \n", deptnumb.val, location.val); + + /* fetch next row */ + ciRC = OCIStmtFetch( + hstmt, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + } + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbSelectWithParam */ + +/* perform a SELECT where the number of columns in the + result set is not known */ +int TbSelectWithUnknownOutCols( OCIEnv * envhp, OCISvcCtx * svchp, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + OCIStmt * hstmt; /* statement handle */ + /* SQL SELECT statement to be executed */ + char *stmt = (char *)"SELECT * FROM org"; + ub4 i, j; /* indices */ + ub4 nResultCols; + void * hCol; + char * colName; + ub4 colNameLen; + ub2 colSize; + ub2 colDisplaySize[MAX_COLUMNS]; + + struct + { + OCIDefine * defnhp; + char *buff; + sb2 ind; + ub2 length; + ub2 rcode; + } + outData[MAX_COLUMNS]; /* variable to read the results */ + + memset( outData, 0, sizeof( outData )); + + printf("\n-----------------------------------------------------------"); + printf("\nUSE THE DB2CI FUNCTIONS\n"); + printf(" OCIHandleAlloc\n"); + printf(" OCIStmtPrepare\n"); + printf(" OCIStmtExecute\n"); + printf(" OCIAttrGet\n"); + printf(" OCIParamGet\n"); + printf(" OCIDefineByPos\n"); + printf(" OCIStmtFetch\n"); + printf(" OCIHandleFree\n"); + printf("TO PERFORM A SELECT WITH UNKNOWN OUTPUT COLUMNS\n"); + printf("AT COMPILE TIME:\n"); + + /* allocate a statement handle */ + ciRC = OCIHandleAlloc( (dvoid *)envhp, (dvoid **)&hstmt, OCI_HTYPE_STMT, 0, NULL ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Directly execute the statement\n"); + printf(" %s.\n", stmt); + + /* directly execute the statement */ + ciRC = OCIStmtPrepare( + hstmt, + errhp, + (OraText *)stmt, + strlen( stmt ), + OCI_NTV_SYNTAX, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + ciRC = OCIStmtExecute( + svchp, + hstmt, + errhp, + 0, + 0, + NULL, + NULL, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf("\n Identify the output columns, then \n"); + printf(" fetch each row and display.\n"); + + /* identify the number of output columns */ + ciRC = OCIAttrGet( hstmt, OCI_HTYPE_STMT, (dvoid *)&nResultCols, NULL, OCI_ATTR_PARAM_COUNT, errhp ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf(" "); + for (i = 0; i < nResultCols; i++) + { + /* return a set of attributes for a column */ + ciRC = OCIParamGet( hstmt, OCI_HTYPE_STMT, errhp, &hCol, i + 1 ); + ERR_HANDLE_CHECK(errhp, ciRC); + + ciRC = OCIAttrGet( hCol, OCI_DTYPE_PARAM, &colName, &colNameLen, OCI_ATTR_NAME, errhp ); + ERR_HANDLE_CHECK(errhp, ciRC); + + ciRC = OCIAttrGet( hCol, OCI_DTYPE_PARAM, &colSize, NULL, OCI_ATTR_DATA_SIZE, errhp ); + ERR_HANDLE_CHECK(errhp, ciRC); + colSize = max( colSize, 32 ); + + /* set "column display size" to the larger of "column data display size" + and "column name length" and add one space between columns. */ + colDisplaySize[i] = max(colSize, colNameLen) + 1; + + /* print the column name */ + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], colName); + + /* set "output data buffer length" to "column data display size" + and add one byte for null the terminator */ + outData[i].length = colDisplaySize[i]; + + /* allocate memory to bind a column */ + outData[i].buff = (char *)malloc((int)outData[i].length); + + /* bind columns to program variables, converting all types to CHAR */ + ciRC = OCIDefineByPos( + hstmt, + &outData[i].defnhp, + errhp, + i + 1, + outData[i].buff, + outData[i].length, + SQLT_STR, + &outData[i].ind, + &outData[i].length, + &outData[i].rcode, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + } + + printf("\n "); + for (i = 0; i < nResultCols; i++) + { + for (j = 1; j < (int)colDisplaySize[i]; j++) + { + printf("-"); + } + printf(" "); + } + printf("\n"); + + /* fetch each row and display */ + ciRC = OCIStmtFetch( + hstmt, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + if (ciRC == OCI_NO_DATA ) + { + printf("\n Data not found.\n"); + } + while (ciRC != OCI_NO_DATA ) + { + printf(" "); + for (i = 0; i < nResultCols; i++) /* for all columns in this row */ + { /* check for NULL data */ + if (outData[i].ind == -1 ) + { + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], "NULL"); + } + else + { /* print outData for this column */ + printf("%-*.*s", + (int)colDisplaySize[i], + (int)colDisplaySize[i], + outData[i].buff); + } + } + printf("\n"); + + /* fetch next row */ + ciRC = OCIStmtFetch( + hstmt, + errhp, + 1, + OCI_FETCH_NEXT, + OCI_DEFAULT ); + ERR_HANDLE_CHECK(errhp, ciRC); + } + + /* free data buffers */ + for (i = 0; i < nResultCols; i++) + { + free(outData[i].buff); + } + + /* free the statement handle */ + ciRC = OCIHandleFree( hstmt, OCI_HTYPE_STMT ); + ERR_HANDLE_CHECK(errhp, ciRC); + + return rc; +} /* TbSelectWithUnknownOutCols */ diff --git a/db2ci/utilci.c b/db2ci/utilci.c new file mode 100644 index 0000000..0daed32 --- /dev/null +++ b/db2ci/utilci.c @@ -0,0 +1,487 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2009 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilci.c +** +** SAMPLE: Utility functions used by DB2 CI samples +** +** CI FUNCTIONS USED: +** OCIHandleAlloc -- Allocate Handle +** OCIDefineByPos -- Bind a Column to an Application Variable or +** LOB locator +** OCIAttrGet -- Return a Column Attribute +** OCILogon -- Connect to a Data Source +** OCILogoff -- Disconnect from a Data Source +** OCITransCommit/OCITransRollback -- End Transactions of a Connection +** OCIStmtFetch -- Fetch Next Row +** OCIHandleFree -- Free Handle Resources +** OCIErrorGet -- Get Multiple Field Settings of Diagnostic Record +** OCIAttrSet -- Set Connection Attributes +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#include +#include +#include +#include +#include "utilci.h" + +/* local functions for utilci.c */ +void HandleLocationPrint(sb4, int, char *); +void HandleDiagnosticsPrint(ub4, dvoid *); + +/* outputs to screen unexpected occurrences with CI functions */ +int HandleInfoPrint(ub4 htype, /* handle type identifier */ + void * hndl, /* handle used by the CI function */ + sb4 ciRC, /* return code of the CI function */ + int line, + char *file) +{ + int rc = 0; + + switch (ciRC) + { + case OCI_SUCCESS: + rc = 0; + break; + case OCI_INVALID_HANDLE: + printf("\n-CI INVALID HANDLE-----\n"); + HandleLocationPrint(ciRC, line, file); + rc = 1; + break; + case OCI_ERROR: + printf("\n--CI ERROR--------------\n"); + HandleLocationPrint(ciRC, line, file); + HandleDiagnosticsPrint(htype, hndl); + rc = 2; + break; + case OCI_SUCCESS_WITH_INFO: + rc = 0; + break; + case OCI_NEED_DATA: + rc = 0; + break; + case OCI_NO_DATA: + rc = 0; + break; + default: + printf("\n--default----------------\n"); + HandleLocationPrint(ciRC, line, file); + rc = 3; + break; + } + + return rc; +} /* HandleInfoPrint */ + +void HandleLocationPrint( sb4 ciRC, int line, char *file) +{ + printf(" ciRC = %ld\n", (long)ciRC); + printf(" line = %d\n", line); + printf(" file = %s\n", file); +} /* HandleLocationPrint */ + +void HandleDiagnosticsPrint(ub4 htype, /* handle type identifier */ + dvoid * hndl /* handle */ ) +{ + char message[1024 + 1]; + char sqlstate[5 + 1]; + sb4 sqlcode; + ub4 i = 1; + + /* get multiple field settings of diagnostic record */ + while (OCIErrorGet( hndl, + i, + (text *)sqlstate, + &sqlcode, + (text *)message, + sizeof( message ), + htype ) == OCI_SUCCESS) + { + printf("\n SQLSTATE = %s\n", sqlstate); + printf(" Native Error Code = %d\n", sqlcode); + printf("%s\n", message); + i++; + } + + printf("-------------------------\n"); +} /* HandleDiagnosticsPrint */ + +/* rollback transactions on a single connection */ +/* this function is used in HANDLE_CHECK */ +void TransRollback( OCISvcCtx * svch, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + + printf("\n Rolling back the transaction...\n"); + + /* end transactions on the connection */ + ciRC = OCITransRollback( svch, errhp, OCI_DEFAULT ); + rc = HandleInfoPrint(OCI_HTYPE_ERROR, errhp, ciRC, __LINE__, __FILE__); + if (rc == 0) + { + printf(" The transaction rolled back.\n"); + } +} /* TransRollback */ + +/* check command line arguments */ +int CmdLineArgsCheck1(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd]]\n", argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck1 */ + +/* check command line arguments */ +int CmdLineArgsCheck2(int argc, + char *argv[], + char dbAlias[], + char user[], + char pswd[], + char remoteNodeName[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias, "sample"); + strcpy(user, ""); + strcpy(pswd, ""); + strcpy(remoteNodeName, ""); + break; + case 2: + strcpy(dbAlias, argv[1]); + strcpy(user, ""); + strcpy(pswd, ""); + strcpy(remoteNodeName, ""); + break; + case 4: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + strcpy(remoteNodeName, ""); + break; + case 5: + strcpy(dbAlias, argv[1]); + strcpy(user, argv[2]); + strcpy(pswd, argv[3]); + strcpy(remoteNodeName, argv[4]); + break; + default: + printf("\nUSAGE: %s [dbAlias [userid passwd [remoteNodeName]]]\n", + argv[0]); + rc = 1; + break; + } /* endswitch */ + + return rc; +} /* CmdLineArgsCheck2 */ + +/* check command line arguments */ +int CmdLineArgsCheck3(int argc, + char *argv[], + char dbAlias1[], + char dbAlias2[], + char user1[], + char pswd1[], + char user2[], + char pswd2[]) +{ + int rc = 0; + + switch (argc) + { + case 1: + strcpy(dbAlias1, "sample"); + strcpy(dbAlias2, "sample2"); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 3: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, ""); + strcpy(pswd1, ""); + strcpy(user2, ""); + strcpy(pswd2, ""); + break; + case 5: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[3]); + strcpy(pswd2, argv[4]); + break; + case 7: + strcpy(dbAlias1, argv[1]); + strcpy(dbAlias2, argv[2]); + strcpy(user1, argv[3]); + strcpy(pswd1, argv[4]); + strcpy(user2, argv[5]); + strcpy(pswd2, argv[6]); + break; + default: + printf("\nUSAGE: %s " + "[dbAlias1 dbAlias2 [user1 pswd1 [user2 pswd2]]]\n", + argv[0]); + rc = 1; + break; + } + + return rc; +} /* CmdLineArgsCheck3 */ + +/* initialize a CI application by: + o allocating an environment handle + o allocating a connection handle + o connecting to the database */ +int CIAppInit(char dbAlias[], + char user[], + char pswd[], + OCIEnv ** pHenv, + OCISvcCtx ** pHdbc, + OCIError ** errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + + /* allocate an environment handle */ + ciRC = OCIEnvCreate( (OCIEnv **)pHenv, OCI_OBJECT, NULL, NULL, NULL, NULL, 0, NULL ); + if (ciRC != OCI_SUCCESS) + { + printf("\n--ERROR while allocating the environment handle.\n"); + printf(" ciRC = %d\n", ciRC); + printf(" line = %d\n", __LINE__); + printf(" file = %s\n", __FILE__); + return 1; + } + + /* allocate an error handle */ + ciRC = OCIHandleAlloc( *pHenv, (dvoid *)errhp, OCI_HTYPE_ERROR, 0, NULL ); + ENV_HANDLE_CHECK(*pHenv, ciRC); + + /* allocate a database connection handle */ + ciRC = OCIHandleAlloc( *pHenv, (dvoid *)pHdbc, OCI_HTYPE_SVCCTX, 0, NULL ); + ENV_HANDLE_CHECK(*pHenv, ciRC); + + printf("\n Connecting to %s...\n", dbAlias); + + /* connect to the database */ + ciRC = OCILogon( *pHenv, + *errhp, + pHdbc, + (OraText *)user, + strlen( (char *)user ), + (OraText *)pswd, + strlen( (char *)pswd ), + (OraText *)dbAlias, + strlen( (char *)dbAlias )); + ERR_HANDLE_CHECK(*errhp, ciRC); + printf(" Connected to %s.\n", dbAlias); + + return 0; +} /* CIAppInit */ + +/* terminate a CI application by: + o disconnecting from the database + o freeing the connection handle + o freeing the environment handle */ +int CIAppTerm(OCIEnv ** pHenv, OCISvcCtx ** pHdbc, OCIError * errhp, char * dbAlias ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + + printf("\n Disconnecting from %s...\n", dbAlias); + + /* disconnect from the database */ + ciRC = OCILogoff( *pHdbc, errhp ); + ERR_HANDLE_CHECK(errhp, ciRC); + + printf(" Disconnected from %s.\n", dbAlias); + + /* free connection handle */ + ciRC = OCIHandleFree( *pHdbc, OCI_HTYPE_SVCCTX ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* free error handle */ + ciRC = OCIHandleFree( errhp, OCI_HTYPE_ERROR ); + ERR_HANDLE_CHECK(errhp, ciRC); + + /* free environment handle */ + ciRC = OCIHandleFree( *pHenv, OCI_HTYPE_ENV ); + ERR_HANDLE_CHECK(errhp, ciRC); + + (void)OCITerminate( OCI_DEFAULT ); + + return 0; +} /* CIAppTerm */ + +/* output result sets */ +int StmtResultPrint(OCIStmt * hstmt, OCISvcCtx * hdbc, OCIError * errhp ) +{ + sb4 ciRC = OCI_SUCCESS; + int rc = 0; + + ub4 i; /* index */ + ub4 nResultCols; + void * hCol; + char * colName; + ub4 colNameLen; + ub4 colDisplaySize[MAX_COLUMNS]; /* maximum size of the column */ + OCIDefine * hDefine; + + struct + { + char *buff; + ub2 len; + ub2 buffLen; + sb2 nullInd; + ub2 rcode; + } + outData[MAX_COLUMNS]; /* variable to read the results */ + + /* identify the output columns */ + ciRC = OCIAttrGet( hstmt, OCI_HTYPE_STMT, (dvoid *)&nResultCols, NULL, OCI_ATTR_PARAM_COUNT, errhp ); + ERR_HANDLE_CHECK( errhp, ciRC); + + printf("\n"); + for (i = 0; i < nResultCols; i++) + { + + /* return a set of attributes for a column */ + ciRC = OCIParamGet( (dvoid *)hstmt, OCI_HTYPE_STMT, errhp, &hCol, i + 1 ); + ERR_HANDLE_CHECK( errhp, ciRC); + + ciRC = OCIAttrGet( hCol, OCI_DTYPE_PARAM, (dvoid *)&colName, &colNameLen, OCI_ATTR_NAME, errhp ); + ERR_HANDLE_CHECK( errhp, ciRC); + + /* set "column display size" to max of "column data display size", + and "column name length", plus at least one space between columns */ + colDisplaySize[i] = max(32, colNameLen) + 1; + + /* print the column name */ + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], colName); + + /* set "output data buffer length" to "column data display size" + plus one byte for the null terminator */ + outData[i].buffLen = 32 + 1; + + /* allocate memory to define column */ + outData[i].buff = (char *)malloc((int)outData[i].buffLen); + + /* bind columns to program variables, converting all types to CHAR */ + ciRC = OCIDefineByPos( + hstmt, + &hDefine, + errhp, + i + 1L, + (dvoid *)outData[i].buff, + outData[i].buffLen, + SQLT_STR, + &outData[i].nullInd, + &outData[i].len, + &outData[i].rcode, + OCI_DEFAULT ); + ERR_HANDLE_CHECK( errhp, ciRC); + } + + printf("\n"); + /* fetch each row and display */ + ciRC = OCIStmtFetch( hstmt, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT ); + if (ciRC == OCI_NO_DATA) + { + printf("\n Data not found.\n"); + } + + while (ciRC == OCI_SUCCESS || ciRC == OCI_SUCCESS_WITH_INFO) + { + for (i = 0; i < nResultCols; i++) + { + /* check for NULL data */ + if (outData[i].nullInd == -1 ) + { + printf("%-*.*s", + (int)colDisplaySize[i], (int)colDisplaySize[i], "NULL"); + } + else + { + /* print outData for this column */ + printf("%-*.*s", + (int)colDisplaySize[i], + (int)colDisplaySize[i], outData[i].buff); + } + } /* for all columns in this row */ + + printf("\n"); + + /* fetch next row */ + ciRC = OCIStmtFetch( hstmt, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT ); + ERR_HANDLE_CHECK( errhp, ciRC); + } /* while rows to fetch */ + + /* free data buffers */ + for (i = 0; i < nResultCols; i++) + { + free(outData[i].buff); + } + + return rc; +} /* StmtResultPrint */ diff --git a/db2ci/utilci.h b/db2ci/utilci.h new file mode 100644 index 0000000..04d0d9b --- /dev/null +++ b/db2ci/utilci.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** (c) Copyright IBM Corp. 2009 All rights reserved. +** +** The following sample of source code ("Sample") is owned by International +** Business Machines Corporation or one of its subsidiaries ("IBM") and is +** copyrighted and licensed, not sold. You may use, copy, modify, and +** distribute the Sample in any form without payment to IBM, for the purpose of +** assisting you in the development of your applications. +** +** The Sample code is provided to you on an "AS IS" basis, without warranty of +** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR +** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do +** not allow for the exclusion or limitation of implied warranties, so the above +** limitations or exclusions may not apply to you. IBM shall not be liable for +** any damages you suffer as a result of using, copying, modifying or +** distributing the Sample, even if IBM has been advised of the possibility of +** such damages. +***************************************************************************** +** +** SOURCE FILE NAME: utilci.h +** +** SAMPLE: Declaration of utility functions used by DB2 CI samples +***************************************************************************** +** +** For more information on the sample programs, see the README file. +** +** For information on using SQL statements, see the SQL Reference. +** +** For the latest information on programming, building, and running DB2 +** applications, visit the DB2 application development website: +** http://www.software.ibm.com/data/db2/udb/ad +****************************************************************************/ + +#ifndef UTILCI_H +#define UTILCI_H + +#ifndef SQL_MAX_DSN_LENGTH +#define SQL_MAX_DSN_LENGTH 128 +#endif +#define MAX_UID_LENGTH 18 +#define MAX_PWD_LENGTH 30 +#define MAX_STMT_LEN 255 +#define MAX_COLUMNS 255 +#ifdef DB2WIN +#define MAX_TABLES 50 +#else +#define MAX_TABLES 255 +#endif + +#ifndef max +#define max(a,b) (a > b ? a : b) +#endif + +/* macro for error handle checking */ +#define ERR_HANDLE_CHECK(errhp, ciRC) \ +if (ciRC != OCI_SUCCESS) \ +{ \ + rc = HandleInfoPrint(OCI_HTYPE_ERROR, errhp, \ + ciRC, __LINE__, __FILE__); \ + if (rc != 0) return rc; \ +} +#define ENV_HANDLE_CHECK(envhp, ciRC) \ +if (ciRC != OCI_SUCCESS) \ +{ \ + rc = HandleInfoPrint(OCI_HTYPE_ENV, envhp, \ + ciRC, __LINE__, __FILE__); \ + if (rc != 0) return rc; \ +} +/* functions used in ...CHECK_HANDLE macros */ +int HandleInfoPrint(ub4, dvoid *, sb4, int, char *); +void TransRollback( OCISvcCtx * svch, OCIError * errhp ); + +/* functions to check the number of command line arguments */ +int CmdLineArgsCheck1(int, char *argv[], char *, char *, char *); +int CmdLineArgsCheck2(int, char *argv[], char *, char *, char *, char *); +int CmdLineArgsCheck3(int, char *argv[], char *, char *, + char *, char *, char *, char *); + +/* other utility functions */ +int CIAppInit(char dbAlias[], char user[], char pswd[], OCIEnv ** pHenv, OCISvcCtx ** pHdbc, OCIError ** errhp ); +int CIAppTerm(OCIEnv ** pHenv, OCISvcCtx ** pHdbc, OCIError * errhp, char * dbAlias ); +int StmtResultPrint(OCIStmt * hstmt, OCISvcCtx * hdbc, OCIError * errhp ); + +#endif + diff --git a/db2sampl/addr.xsd b/db2sampl/addr.xsd new file mode 100644 index 0000000..c386b56 --- /dev/null +++ b/db2sampl/addr.xsd @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/db2sampl/c1.xml b/db2sampl/c1.xml new file mode 100755 index 0000000..1b01887 --- /dev/null +++ b/db2sampl/c1.xml @@ -0,0 +1,10 @@ + +Kathy Smith + +5 Rosewood +Toronto +Ontario +M6W 1E6 + +416-555-1358 + diff --git a/db2sampl/c2.xml b/db2sampl/c2.xml new file mode 100755 index 0000000..e46d1ba --- /dev/null +++ b/db2sampl/c2.xml @@ -0,0 +1,10 @@ + +Kathy Smith + +25 EastCreek +Markham +Ontario +N9C 3T6 + +905-555-7258 + diff --git a/db2sampl/c3.xml b/db2sampl/c3.xml new file mode 100755 index 0000000..5045f09 --- /dev/null +++ b/db2sampl/c3.xml @@ -0,0 +1,10 @@ + +Jim Noodle + +25 EastCreek +Markham +Ontario +N9C 3T6 + +905-555-7258 + diff --git a/db2sampl/c4.xml b/db2sampl/c4.xml new file mode 100755 index 0000000..fc9150d --- /dev/null +++ b/db2sampl/c4.xml @@ -0,0 +1,13 @@ + +Robert Shoemaker + +1596 Baseline +Aurora +Ontario +N8X 7F8 + +905-555-7258 +416-555-2937 +905-555-8743 +613-555-3278 + diff --git a/db2sampl/c5.xml b/db2sampl/c5.xml new file mode 100755 index 0000000..8fa7eab --- /dev/null +++ b/db2sampl/c5.xml @@ -0,0 +1,15 @@ + +Matt Foreman + +1596 Baseline +Toronto +Ontario +M3Z 5H9 + +905-555-4789 +416-555-3376 + +Gopher Runner +416-555-3426 + + diff --git a/db2sampl/c6.xml b/db2sampl/c6.xml new file mode 100644 index 0000000..194ac31 --- /dev/null +++ b/db2sampl/c6.xml @@ -0,0 +1,15 @@ + +Larry Menard + +223 NatureValley Road +Toronto +Ontario +M4C 5K8 + +905-555-9146 +416-555-6121 + +Goose Defender +416-555-1943 + + diff --git a/db2sampl/catalog.xsd b/db2sampl/catalog.xsd new file mode 100644 index 0000000..e15caf1 --- /dev/null +++ b/db2sampl/catalog.xsd @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/db2sampl/customer.xsd b/db2sampl/customer.xsd new file mode 100644 index 0000000..f04807f --- /dev/null +++ b/db2sampl/customer.xsd @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/db2sampl/db200130.asc b/db2sampl/db200130.asc new file mode 100644 index 0000000..52f8122 --- /dev/null +++ b/db2sampl/db200130.asc @@ -0,0 +1,56 @@ + + + Resume: Delores M. Quintana + + + Personal Information + + Address: 1150 Eglinton Ave + Mellonville, Idaho 83725 + Phone: (208) 875-9933 + Birthdate: September 15, 1925 + Sex: Female + Marital Status: Married + Height: 5'2" + Weight: 120 lbs. + + + Department Information + + Employee Number: 000130 + Dept Number: C01 + Manager: Sally Kwan + Position: Analyst + Phone: (208) 385-4578 + Hire Date: 1971-07-28 + + + Education + + 1965 Math and English, B.A. + Adelphi University + + 1960 Dental Technician + Florida Institute of Technology + + + Work History + + 10/91 - present Advisory Systems Analyst + Producing documentation tools for engineering + department. + + 12/85 - 9/91 Technical Writer + Writer, text programmer, and planner. + + 1/79 - 11/85 COBOL Payroll Programmer + Writing payroll programs for a diesel fuel + company. + + + Interests + + o Cooking + o Reading + o Sewing + o Remodeling diff --git a/db2sampl/db200130.bmp b/db2sampl/db200130.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f5151084a25783b7a01a5af8c48725a6080accc7 GIT binary patch literal 43690 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 MeNc<$<8QzH7nBqnDF6Tf literal 0 HcmV?d00001 diff --git a/db2sampl/db200130.gif b/db2sampl/db200130.gif new file mode 100644 index 0000000000000000000000000000000000000000..0f65d0fd955969f8b9a76861599f4786f6c838f8 GIT binary patch literal 29540 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 + +Resume: Delores M. Quintana + + + + + + + + +
+